blob: acb0702316cea3f166a221114416125dd56519b3 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020023#ifdef FEAT_FLOAT
24static void f_abs(typval_T *argvars, typval_T *rettv);
25static void f_acos(typval_T *argvars, typval_T *rettv);
26#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028#ifdef FEAT_FLOAT
29static void f_asin(typval_T *argvars, typval_T *rettv);
30static void f_atan(typval_T *argvars, typval_T *rettv);
31static void f_atan2(typval_T *argvars, typval_T *rettv);
32#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010033#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020034static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010035static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010036# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010037static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010038# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020040static void f_byte2line(typval_T *argvars, typval_T *rettv);
41static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
42static void f_byteidx(typval_T *argvars, typval_T *rettv);
43static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
44static void f_call(typval_T *argvars, typval_T *rettv);
45#ifdef FEAT_FLOAT
46static void f_ceil(typval_T *argvars, typval_T *rettv);
47#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_changenr(typval_T *argvars, typval_T *rettv);
49static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_confirm(typval_T *argvars, typval_T *rettv);
52static void f_copy(typval_T *argvars, typval_T *rettv);
53#ifdef FEAT_FLOAT
54static void f_cos(typval_T *argvars, typval_T *rettv);
55static void f_cosh(typval_T *argvars, typval_T *rettv);
56#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010058#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020059static void f_debugbreak(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4132eb52020-02-14 16:53:00 +010063static void f_echoraw(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020064static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020065static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_escape(typval_T *argvars, typval_T *rettv);
67static void f_eval(typval_T *argvars, typval_T *rettv);
68static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_exists(typval_T *argvars, typval_T *rettv);
71#ifdef FEAT_FLOAT
72static void f_exp(typval_T *argvars, typval_T *rettv);
73#endif
74static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020075static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077#ifdef FEAT_FLOAT
78static void f_float2nr(typval_T *argvars, typval_T *rettv);
79static void f_floor(typval_T *argvars, typval_T *rettv);
80static void f_fmod(typval_T *argvars, typval_T *rettv);
81#endif
82static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020084static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_function(typval_T *argvars, typval_T *rettv);
86static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
87static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010088static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020090static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010092static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getpid(typval_T *argvars, typval_T *rettv);
94static void f_getcurpos(typval_T *argvars, typval_T *rettv);
95static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getreg(typval_T *argvars, typval_T *rettv);
97static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010098static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
100static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_hlID(typval_T *argvars, typval_T *rettv);
102static void f_hlexists(typval_T *argvars, typval_T *rettv);
103static void f_hostname(typval_T *argvars, typval_T *rettv);
104static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_index(typval_T *argvars, typval_T *rettv);
106static void f_input(typval_T *argvars, typval_T *rettv);
107static void f_inputdialog(typval_T *argvars, typval_T *rettv);
108static void f_inputlist(typval_T *argvars, typval_T *rettv);
109static void f_inputrestore(typval_T *argvars, typval_T *rettv);
110static void f_inputsave(typval_T *argvars, typval_T *rettv);
111static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100112static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200113static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200114static void f_islocked(typval_T *argvars, typval_T *rettv);
115#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200116static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_isnan(typval_T *argvars, typval_T *rettv);
118#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
120static void f_len(typval_T *argvars, typval_T *rettv);
121static void f_libcall(typval_T *argvars, typval_T *rettv);
122static void f_libcallnr(typval_T *argvars, typval_T *rettv);
123static void f_line(typval_T *argvars, typval_T *rettv);
124static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125#ifdef FEAT_FLOAT
126static void f_log(typval_T *argvars, typval_T *rettv);
127static void f_log10(typval_T *argvars, typval_T *rettv);
128#endif
129#ifdef FEAT_LUA
130static void f_luaeval(typval_T *argvars, typval_T *rettv);
131#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_maparg(typval_T *argvars, typval_T *rettv);
133static void f_mapcheck(typval_T *argvars, typval_T *rettv);
134static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_matchend(typval_T *argvars, typval_T *rettv);
136static void f_matchlist(typval_T *argvars, typval_T *rettv);
137static void f_matchstr(typval_T *argvars, typval_T *rettv);
138static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
139static void f_max(typval_T *argvars, typval_T *rettv);
140static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141#ifdef FEAT_MZSCHEME
142static void f_mzeval(typval_T *argvars, typval_T *rettv);
143#endif
144static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
145static void f_nr2char(typval_T *argvars, typval_T *rettv);
146static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_PERL
148static void f_perleval(typval_T *argvars, typval_T *rettv);
149#endif
150#ifdef FEAT_FLOAT
151static void f_pow(typval_T *argvars, typval_T *rettv);
152#endif
153static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
154static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200155static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_pumvisible(typval_T *argvars, typval_T *rettv);
157#ifdef FEAT_PYTHON3
158static void f_py3eval(typval_T *argvars, typval_T *rettv);
159#endif
160#ifdef FEAT_PYTHON
161static void f_pyeval(typval_T *argvars, typval_T *rettv);
162#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100163#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
164static void f_pyxeval(typval_T *argvars, typval_T *rettv);
165#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100166static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100167static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200169static void f_reg_executing(typval_T *argvars, typval_T *rettv);
170static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_remote_expr(typval_T *argvars, typval_T *rettv);
172static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
173static void f_remote_peek(typval_T *argvars, typval_T *rettv);
174static void f_remote_read(typval_T *argvars, typval_T *rettv);
175static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100176static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_rename(typval_T *argvars, typval_T *rettv);
178static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179#ifdef FEAT_FLOAT
180static void f_round(typval_T *argvars, typval_T *rettv);
181#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100182#ifdef FEAT_RUBY
183static void f_rubyeval(typval_T *argvars, typval_T *rettv);
184#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_screenattr(typval_T *argvars, typval_T *rettv);
186static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100187static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_screencol(typval_T *argvars, typval_T *rettv);
189static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100190static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_search(typval_T *argvars, typval_T *rettv);
192static void f_searchdecl(typval_T *argvars, typval_T *rettv);
193static void f_searchpair(typval_T *argvars, typval_T *rettv);
194static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
195static void f_searchpos(typval_T *argvars, typval_T *rettv);
196static void f_server2client(typval_T *argvars, typval_T *rettv);
197static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200199static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100203static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204#ifdef FEAT_CRYPT
205static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_shellescape(typval_T *argvars, typval_T *rettv);
208static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209#ifdef FEAT_FLOAT
210static void f_sin(typval_T *argvars, typval_T *rettv);
211static void f_sinh(typval_T *argvars, typval_T *rettv);
212#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_soundfold(typval_T *argvars, typval_T *rettv);
214static void f_spellbadword(typval_T *argvars, typval_T *rettv);
215static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
216static void f_split(typval_T *argvars, typval_T *rettv);
217#ifdef FEAT_FLOAT
218static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100219#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100220static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100221#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_str2float(typval_T *argvars, typval_T *rettv);
223#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200224static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_str2nr(typval_T *argvars, typval_T *rettv);
226static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200227static void f_strgetchar(typval_T *argvars, typval_T *rettv);
228static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200229static void f_strlen(typval_T *argvars, typval_T *rettv);
230static void f_strcharpart(typval_T *argvars, typval_T *rettv);
231static void f_strpart(typval_T *argvars, typval_T *rettv);
232static void f_strridx(typval_T *argvars, typval_T *rettv);
233static void f_strtrans(typval_T *argvars, typval_T *rettv);
234static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
235static void f_strwidth(typval_T *argvars, typval_T *rettv);
236static void f_submatch(typval_T *argvars, typval_T *rettv);
237static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200238static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200239static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_synID(typval_T *argvars, typval_T *rettv);
241static void f_synIDattr(typval_T *argvars, typval_T *rettv);
242static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
243static void f_synstack(typval_T *argvars, typval_T *rettv);
244static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_taglist(typval_T *argvars, typval_T *rettv);
247static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248#ifdef FEAT_FLOAT
249static void f_tan(typval_T *argvars, typval_T *rettv);
250static void f_tanh(typval_T *argvars, typval_T *rettv);
251#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200252static void f_tolower(typval_T *argvars, typval_T *rettv);
253static void f_toupper(typval_T *argvars, typval_T *rettv);
254static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100255static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256#ifdef FEAT_FLOAT
257static void f_trunc(typval_T *argvars, typval_T *rettv);
258#endif
259static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_virtcol(typval_T *argvars, typval_T *rettv);
261static void f_visualmode(typval_T *argvars, typval_T *rettv);
262static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100263static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264static void f_wordcount(typval_T *argvars, typval_T *rettv);
265static void f_xor(typval_T *argvars, typval_T *rettv);
266
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100267
268 static type_T *
269ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
270{
271 return &t_void;
272}
273 static type_T *
274ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
275{
276 return &t_any;
277}
278 static type_T *
279ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
280{
281 return &t_number;
282}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100283#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100284 static type_T *
285ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
286{
287 return &t_float;
288}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100289#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100290 static type_T *
291ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
292{
293 return &t_string;
294}
295 static type_T * ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
296{
297 return &t_list_any;
298}
299 static type_T *
300ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
301{
302 return &t_list_number;
303}
304 static type_T *
305ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
306{
307 return &t_list_string;
308}
309 static type_T *
310ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
311{
312 return &t_list_dict_any;
313}
314 static type_T *
315ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
316{
317 return &t_dict_any;
318}
319 static type_T *
320ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
321{
322 return &t_dict_number;
323}
324 static type_T *
325ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
326{
327 return &t_dict_string;
328}
329 static type_T *
330ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
331{
332 return &t_blob;
333}
334 static type_T *
335ret_partial_void(int argcount UNUSED, type_T **argtypes UNUSED)
336{
337 return &t_partial_void;
338}
339#ifdef FEAT_JOB_CHANNEL
340 static type_T *
341ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
342{
343 return &t_channel;
344}
345 static type_T *
346ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
347{
348 return &t_job;
349}
350#endif
351
352static type_T *ret_f_function(int argcount, type_T **argtypes);
353
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200354/*
355 * Array with names and number of arguments of all internal functions
356 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
357 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200358typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200360 char *f_name; // function name
361 char f_min_argc; // minimal number of arguments
362 char f_max_argc; // maximal number of arguments
363 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100364 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
365 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200367 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200368} funcentry_T;
369
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200370// values for f_argtype; zero means it cannot be used as a method
371#define FEARG_1 1 // base is the first argument
372#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200373#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200374#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200375#define FEARG_LAST 9 // base is the last argument
376
Bram Moolenaarac92e252019-08-03 21:58:38 +0200377static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378{
379#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100380 {"abs", 1, 1, FEARG_1, ret_any, f_abs},
381 {"acos", 1, 1, FEARG_1, ret_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200382#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100383 {"add", 2, 2, FEARG_1, ret_any, f_add},
384 {"and", 2, 2, FEARG_1, ret_number, f_and},
385 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
386 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
387 {"argc", 0, 1, 0, ret_number, f_argc},
388 {"argidx", 0, 0, 0, ret_number, f_argidx},
389 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
390 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100392 {"asin", 1, 1, FEARG_1, ret_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200393#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100394 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
395 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
396 {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile},
397 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
398 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
399 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
400 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
401 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
402 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
403 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
404 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
405 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200406#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100407 {"atan", 1, 1, FEARG_1, ret_float, f_atan},
408 {"atan2", 2, 2, FEARG_1, ret_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100410#ifdef FEAT_BEVAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100411 {"balloon_gettext", 0, 0, 0, ret_string, f_balloon_gettext},
412 {"balloon_show", 1, 1, FEARG_1, ret_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100413# if defined(FEAT_BEVAL_TERM)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100414 {"balloon_split", 1, 1, FEARG_1, ret_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100415# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100416#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100417 {"browse", 4, 4, 0, ret_string, f_browse},
418 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
419 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
420 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
421 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
422 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
423 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
424 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
425 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
426 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
427 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
428 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
429 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
430 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
431 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
432 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
433 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
434 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100436 {"ceil", 1, 1, FEARG_1, ret_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437#endif
438#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100439 {"ch_canread", 1, 1, FEARG_1, ret_number, f_ch_canread},
440 {"ch_close", 1, 1, FEARG_1, ret_void, f_ch_close},
441 {"ch_close_in", 1, 1, FEARG_1, ret_void, f_ch_close_in},
442 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, f_ch_evalexpr},
443 {"ch_evalraw", 2, 3, FEARG_1, ret_any, f_ch_evalraw},
444 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, f_ch_getbufnr},
445 {"ch_getjob", 1, 1, FEARG_1, ret_job, f_ch_getjob},
446 {"ch_info", 1, 1, FEARG_1, ret_dict_any, f_ch_info},
447 {"ch_log", 1, 2, FEARG_1, ret_void, f_ch_log},
448 {"ch_logfile", 1, 2, FEARG_1, ret_void, f_ch_logfile},
449 {"ch_open", 1, 2, FEARG_1, ret_channel, f_ch_open},
450 {"ch_read", 1, 2, FEARG_1, ret_string, f_ch_read},
451 {"ch_readblob", 1, 2, FEARG_1, ret_blob, f_ch_readblob},
452 {"ch_readraw", 1, 2, FEARG_1, ret_string, f_ch_readraw},
453 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, f_ch_sendexpr},
454 {"ch_sendraw", 2, 3, FEARG_1, ret_void, f_ch_sendraw},
455 {"ch_setoptions", 2, 2, FEARG_1, ret_void, f_ch_setoptions},
456 {"ch_status", 1, 2, FEARG_1, ret_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200457#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100458 {"changenr", 0, 0, 0, ret_number, f_changenr},
459 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
460 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
461 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
462 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
463 {"col", 1, 1, FEARG_1, ret_number, f_col},
464 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
465 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
466 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
467 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
468 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
469 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200470#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100471 {"cos", 1, 1, FEARG_1, ret_float, f_cos},
472 {"cosh", 1, 1, FEARG_1, ret_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100474 {"count", 2, 4, FEARG_1, ret_number, f_count},
475 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
476 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100477#ifdef MSWIN
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100478 {"debugbreak", 1, 1, FEARG_1, ret_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200479#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100480 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
481 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
482 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
483 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
484 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
485 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
486 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
487 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
488 {"environ", 0, 0, 0, ret_dict_string, f_environ},
489 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
490 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
491 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
492 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
493 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
494 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
495 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200496#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"exp", 1, 1, FEARG_1, ret_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100499 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
500 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
501 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
502 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
503 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
504 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
505 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
506 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
507 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
508 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100510 {"float2nr", 1, 1, FEARG_1, ret_number, f_float2nr},
511 {"floor", 1, 1, FEARG_1, ret_float, f_floor},
512 {"fmod", 2, 2, FEARG_1, ret_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100514 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
515 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
516 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
517 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
518 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
519 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
520 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
521 {"foreground", 0, 0, 0, ret_void, f_foreground},
522 {"funcref", 1, 3, FEARG_1, ret_partial_void, f_funcref},
523 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
524 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
525 {"get", 2, 3, FEARG_1, ret_any, f_get},
526 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
527 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
528 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
529 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
530 {"getchar", 0, 1, 0, ret_number, f_getchar},
531 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
532 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
533 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
534 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
535 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
536 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
537 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
538 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
539 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
540 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
541 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
542 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
543 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
544 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
545 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
546 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
547 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
548 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
549 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
550 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
551 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
552 {"getpid", 0, 0, 0, ret_number, f_getpid},
553 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
554 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
555 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
556 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
557 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
558 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
559 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
560 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
561 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
562 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
563 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
564 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
565 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
566 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
567 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
568 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
Bram Moolenaar79296512020-03-22 16:17:14 +0100569 {"has", 1, 2, 0, ret_number, f_has},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100570 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
571 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
572 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
573 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
574 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
575 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
576 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
577 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
578 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
579 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
580 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
581 {"hostname", 0, 0, 0, ret_string, f_hostname},
582 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
583 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
584 {"index", 2, 4, FEARG_1, ret_number, f_index},
585 {"input", 1, 3, FEARG_1, ret_string, f_input},
586 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
587 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
588 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
589 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
590 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
591 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
592 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
593 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
594 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200595#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100596 {"isinf", 1, 1, FEARG_1, ret_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200597#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100598 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200599#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100600 {"isnan", 1, 1, FEARG_1, ret_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100602 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100604 {"job_getchannel", 1, 1, FEARG_1, ret_channel, f_job_getchannel},
605 {"job_info", 0, 1, FEARG_1, ret_dict_any, f_job_info},
606 {"job_setoptions", 2, 2, FEARG_1, ret_void, f_job_setoptions},
607 {"job_start", 1, 2, FEARG_1, ret_job, f_job_start},
608 {"job_status", 1, 1, FEARG_1, ret_string, f_job_status},
609 {"job_stop", 1, 2, FEARG_1, ret_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200610#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100611 {"join", 1, 2, FEARG_1, ret_string, f_join},
612 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
613 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
614 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
615 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
616 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
617 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
618 {"len", 1, 1, FEARG_1, ret_number, f_len},
619 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
620 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
621 {"line", 1, 2, FEARG_1, ret_number, f_line},
622 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
623 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
624 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
625 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
626 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
627 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
628 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200629#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100630 {"log", 1, 1, FEARG_1, ret_float, f_log},
631 {"log10", 1, 1, FEARG_1, ret_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632#endif
633#ifdef FEAT_LUA
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100634 {"luaeval", 1, 2, FEARG_1, ret_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100636 {"map", 2, 2, FEARG_1, ret_any, f_map},
637 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
638 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
639 {"match", 2, 4, FEARG_1, ret_any, f_match},
640 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
641 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
642 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
643 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
644 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
645 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
646 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
647 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
648 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100649#ifdef FEAT_MENU
Bram Moolenaar0eabd4d2020-03-15 16:13:53 +0100650 {"menu_info", 1, 2, FEARG_1, ret_dict_any, f_menu_info},
Bram Moolenaara2cbdea2020-03-16 21:08:31 +0100651#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100652 {"min", 1, 1, FEARG_1, ret_any, f_min},
653 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
654 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655#ifdef FEAT_MZSCHEME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100656 {"mzeval", 1, 1, FEARG_1, ret_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100658 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
659 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
660 {"or", 2, 2, FEARG_1, ret_number, f_or},
661 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662#ifdef FEAT_PERL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100663 {"perleval", 1, 1, FEARG_1, ret_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200664#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100665#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100666 {"popup_atcursor", 2, 2, FEARG_1, ret_number, f_popup_atcursor},
667 {"popup_beval", 2, 2, FEARG_1, ret_number, f_popup_beval},
668 {"popup_clear", 0, 0, 0, ret_void, f_popup_clear},
669 {"popup_close", 1, 2, FEARG_1, ret_void, f_popup_close},
670 {"popup_create", 2, 2, FEARG_1, ret_number, f_popup_create},
671 {"popup_dialog", 2, 2, FEARG_1, ret_number, f_popup_dialog},
672 {"popup_filter_menu", 2, 2, 0, ret_number, f_popup_filter_menu},
673 {"popup_filter_yesno", 2, 2, 0, ret_number, f_popup_filter_yesno},
674 {"popup_findinfo", 0, 0, 0, ret_number, f_popup_findinfo},
675 {"popup_findpreview", 0, 0, 0, ret_number, f_popup_findpreview},
676 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, f_popup_getoptions},
677 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, f_popup_getpos},
678 {"popup_hide", 1, 1, FEARG_1, ret_void, f_popup_hide},
679 {"popup_locate", 2, 2, 0, ret_number, f_popup_locate},
680 {"popup_menu", 2, 2, FEARG_1, ret_number, f_popup_menu},
681 {"popup_move", 2, 2, FEARG_1, ret_void, f_popup_move},
682 {"popup_notification", 2, 2, FEARG_1, ret_number, f_popup_notification},
683 {"popup_setoptions", 2, 2, FEARG_1, ret_void, f_popup_setoptions},
684 {"popup_settext", 2, 2, FEARG_1, ret_void, f_popup_settext},
685 {"popup_show", 1, 1, FEARG_1, ret_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200686#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200687#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100688 {"pow", 2, 2, FEARG_1, ret_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200689#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100690 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
691 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200692#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100693 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, f_prompt_setcallback},
694 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, f_prompt_setinterrupt},
695 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200696#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100697#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100698 {"prop_add", 3, 3, FEARG_1, ret_void, f_prop_add},
699 {"prop_clear", 1, 3, FEARG_1, ret_void, f_prop_clear},
700 {"prop_find", 1, 2, FEARG_1, ret_dict_any, f_prop_find},
701 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, f_prop_list},
702 {"prop_remove", 1, 3, FEARG_1, ret_number, f_prop_remove},
703 {"prop_type_add", 2, 2, FEARG_1, ret_void, f_prop_type_add},
704 {"prop_type_change", 2, 2, FEARG_1, ret_void, f_prop_type_change},
705 {"prop_type_delete", 1, 2, FEARG_1, ret_void, f_prop_type_delete},
706 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, f_prop_type_get},
707 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100708#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100709 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
710 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200711#ifdef FEAT_PYTHON3
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100712 {"py3eval", 1, 1, FEARG_1, ret_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200713#endif
714#ifdef FEAT_PYTHON
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100715 {"pyeval", 1, 1, FEARG_1, ret_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200716#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100717#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100718 {"pyxeval", 1, 1, FEARG_1, ret_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100719#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100720 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
721 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
722 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
723 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
724 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
725 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
726 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100728 {"reltimefloat", 1, 1, FEARG_1, ret_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200729#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100730 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
731 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
732 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
733 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
734 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
735 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
736 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
737 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
738 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
739 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
740 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
741 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200742#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100743 {"round", 1, 1, FEARG_1, ret_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100745#ifdef FEAT_RUBY
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100746 {"rubyeval", 1, 1, FEARG_1, ret_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100747#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100748 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
749 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
750 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
751 {"screencol", 0, 0, 0, ret_number, f_screencol},
752 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
753 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
754 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
755 {"search", 1, 4, FEARG_1, ret_number, f_search},
756 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
757 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
758 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
759 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
760 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
761 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
762 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
763 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
764 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
765 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
766 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
767 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
768 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
769 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
770 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
771 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
772 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
773 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
774 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
775 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
776 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
777 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778#ifdef FEAT_CRYPT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100779 {"sha256", 1, 1, FEARG_1, ret_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200780#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100781 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
782 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100783#ifdef FEAT_SIGNS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100784 {"sign_define", 1, 2, FEARG_1, ret_any, f_sign_define},
785 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, f_sign_getdefined},
786 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, f_sign_getplaced},
787 {"sign_jump", 3, 3, FEARG_1, ret_number, f_sign_jump},
788 {"sign_place", 4, 5, FEARG_1, ret_number, f_sign_place},
789 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, f_sign_placelist},
790 {"sign_undefine", 0, 1, FEARG_1, ret_number, f_sign_undefine},
791 {"sign_unplace", 1, 2, FEARG_1, ret_number, f_sign_unplace},
792 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100793#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100794 {"simplify", 1, 1, 0, ret_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200795#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100796 {"sin", 1, 1, FEARG_1, ret_float, f_sin},
797 {"sinh", 1, 1, FEARG_1, ret_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200798#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100799 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200800#ifdef FEAT_SOUND
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100801 {"sound_clear", 0, 0, 0, ret_void, f_sound_clear},
802 {"sound_playevent", 1, 2, FEARG_1, ret_number, f_sound_playevent},
803 {"sound_playfile", 1, 2, FEARG_1, ret_number, f_sound_playfile},
804 {"sound_stop", 1, 1, FEARG_1, ret_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200805#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100806 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
807 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
808 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
809 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200810#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100811 {"sqrt", 1, 1, FEARG_1, ret_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200812#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100813 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
814 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200815#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100816 {"str2float", 1, 1, FEARG_1, ret_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100818 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
819 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
820 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
821 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
822 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823#ifdef HAVE_STRFTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100824 {"strftime", 1, 2, FEARG_1, ret_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100826 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
827 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
828 {"string", 1, 1, FEARG_1, ret_string, f_string},
829 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
830 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100831#ifdef HAVE_STRPTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100832 {"strptime", 2, 2, FEARG_1, ret_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100833#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100834 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
835 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
836 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
837 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
838 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
839 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
840 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
841 {"synID", 3, 3, 0, ret_number, f_synID},
842 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
843 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
844 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
845 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
846 {"system", 1, 2, FEARG_1, ret_string, f_system},
847 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
848 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
849 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
850 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
851 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
852 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100854 {"tan", 1, 1, FEARG_1, ret_float, f_tan},
855 {"tanh", 1, 1, FEARG_1, ret_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100857 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200858#ifdef FEAT_TERMINAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100859 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, f_term_dumpdiff},
860 {"term_dumpload", 1, 2, FEARG_1, ret_number, f_term_dumpload},
861 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, f_term_dumpwrite},
862 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200863# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100864 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200865# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100866 {"term_getattr", 2, 2, FEARG_1, ret_number, f_term_getattr},
867 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, f_term_getcursor},
868 {"term_getjob", 1, 1, FEARG_1, ret_job, f_term_getjob},
869 {"term_getline", 2, 2, FEARG_1, ret_string, f_term_getline},
870 {"term_getscrolled", 1, 1, FEARG_1, ret_number, f_term_getscrolled},
871 {"term_getsize", 1, 1, FEARG_1, ret_list_number, f_term_getsize},
872 {"term_getstatus", 1, 1, FEARG_1, ret_string, f_term_getstatus},
873 {"term_gettitle", 1, 1, FEARG_1, ret_string, f_term_gettitle},
874 {"term_gettty", 1, 2, FEARG_1, ret_string, f_term_gettty},
875 {"term_list", 0, 0, 0, ret_list_number, f_term_list},
876 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, f_term_scrape},
877 {"term_sendkeys", 2, 2, FEARG_1, ret_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200878# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100879 {"term_setansicolors", 2, 2, FEARG_1, ret_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200880# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100881 {"term_setapi", 2, 2, FEARG_1, ret_void, f_term_setapi},
882 {"term_setkill", 2, 2, FEARG_1, ret_void, f_term_setkill},
883 {"term_setrestore", 2, 2, FEARG_1, ret_void, f_term_setrestore},
884 {"term_setsize", 3, 3, FEARG_1, ret_void, f_term_setsize},
885 {"term_start", 1, 2, FEARG_1, ret_number, f_term_start},
886 {"term_wait", 1, 2, FEARG_1, ret_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200887#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100888 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
889 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
890 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
891 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
892 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
893 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
894 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
895 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200896#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100897 {"test_null_channel", 0, 0, 0, ret_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200898#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100899 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200900#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100901 {"test_null_job", 0, 0, 0, ret_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200902#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100903 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
904 {"test_null_partial", 0, 0, 0, ret_partial_void, f_test_null_partial},
905 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
906 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
907 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
908 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200909#ifdef FEAT_GUI
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100910 {"test_scrollbar", 3, 3, FEARG_2, ret_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200911#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100912 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
913 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
914 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
915 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
916 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917#ifdef FEAT_TIMERS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100918 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, f_timer_info},
919 {"timer_pause", 2, 2, FEARG_1, ret_void, f_timer_pause},
920 {"timer_start", 2, 3, FEARG_1, ret_number, f_timer_start},
921 {"timer_stop", 1, 1, FEARG_1, ret_void, f_timer_stop},
922 {"timer_stopall", 0, 0, 0, ret_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100924 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
925 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
926 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
927 {"trim", 1, 2, FEARG_1, ret_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100929 {"trunc", 1, 1, FEARG_1, ret_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200930#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100931 {"type", 1, 1, FEARG_1, ret_number, f_type},
932 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
933 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
934 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
935 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
936 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
937 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
938 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
939 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
940 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
941 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
942 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
943 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
944 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
945 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
946 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
947 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
948 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
949 {"wincol", 0, 0, 0, ret_number, f_wincol},
950 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
951 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
952 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
953 {"winline", 0, 0, 0, ret_number, f_winline},
954 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
955 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
956 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
957 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
958 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
959 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
960 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
961 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200962};
963
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200964/*
965 * Function given to ExpandGeneric() to obtain the list of internal
966 * or user defined function names.
967 */
968 char_u *
969get_function_name(expand_T *xp, int idx)
970{
971 static int intidx = -1;
972 char_u *name;
973
974 if (idx == 0)
975 intidx = -1;
976 if (intidx < 0)
977 {
978 name = get_user_func_name(xp, idx);
979 if (name != NULL)
980 return name;
981 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200982 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200983 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200984 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200985 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200986 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200987 STRCAT(IObuff, ")");
988 return IObuff;
989 }
990
991 return NULL;
992}
993
994/*
995 * Function given to ExpandGeneric() to obtain the list of internal or
996 * user defined variable or function names.
997 */
998 char_u *
999get_expr_name(expand_T *xp, int idx)
1000{
1001 static int intidx = -1;
1002 char_u *name;
1003
1004 if (idx == 0)
1005 intidx = -1;
1006 if (intidx < 0)
1007 {
1008 name = get_function_name(xp, idx);
1009 if (name != NULL)
1010 return name;
1011 }
1012 return get_user_var_name(xp, ++intidx);
1013}
1014
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001015/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001016 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001017 * Return index, or -1 if not found
1018 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001019 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001020find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001021{
1022 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001023 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001024 int cmp;
1025 int x;
1026
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001027 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001028
1029 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001030 while (first <= last)
1031 {
1032 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001033 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001034 if (cmp < 0)
1035 last = x - 1;
1036 else if (cmp > 0)
1037 first = x + 1;
1038 else
1039 return x;
1040 }
1041 return -1;
1042}
1043
1044 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001045has_internal_func(char_u *name)
1046{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001047 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001048}
1049
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001050 char *
1051internal_func_name(int idx)
1052{
1053 return global_functions[idx].f_name;
1054}
1055
1056 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001057internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001058{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001059 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001060}
1061
1062/*
1063 * Check the argument count to use for internal function "idx".
1064 * Returns OK or FAIL;
1065 */
1066 int
1067check_internal_func(int idx, int argcount)
1068{
1069 int res;
1070 char *name;
1071
1072 if (argcount < global_functions[idx].f_min_argc)
1073 res = FCERR_TOOFEW;
1074 else if (argcount > global_functions[idx].f_max_argc)
1075 res = FCERR_TOOMANY;
1076 else
1077 return OK;
1078
1079 name = internal_func_name(idx);
1080 if (res == FCERR_TOOMANY)
1081 semsg(_(e_toomanyarg), name);
1082 else
1083 semsg(_(e_toofewarg), name);
1084 return FAIL;
1085}
1086
Bram Moolenaarac92e252019-08-03 21:58:38 +02001087 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001088call_internal_func(
1089 char_u *name,
1090 int argcount,
1091 typval_T *argvars,
1092 typval_T *rettv)
1093{
1094 int i;
1095
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001096 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001097 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001098 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001099 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001100 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001101 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001102 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001103 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001104 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001105 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001106}
1107
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001108 void
1109call_internal_func_by_idx(
1110 int idx,
1111 typval_T *argvars,
1112 typval_T *rettv)
1113{
1114 global_functions[idx].f_func(argvars, rettv);
1115}
1116
Bram Moolenaarac92e252019-08-03 21:58:38 +02001117/*
1118 * Invoke a method for base->method().
1119 */
1120 int
1121call_internal_method(
1122 char_u *name,
1123 int argcount,
1124 typval_T *argvars,
1125 typval_T *rettv,
1126 typval_T *basetv)
1127{
1128 int i;
1129 int fi;
1130 typval_T argv[MAX_FUNC_ARGS + 1];
1131
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001132 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001133 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001134 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001135 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001136 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001137 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001138 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001139 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001140 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001141
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001142 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001143 {
1144 // base value goes last
1145 for (i = 0; i < argcount; ++i)
1146 argv[i] = argvars[i];
1147 argv[argcount] = *basetv;
1148 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001149 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001150 {
1151 // base value goes second
1152 argv[0] = argvars[0];
1153 argv[1] = *basetv;
1154 for (i = 1; i < argcount; ++i)
1155 argv[i + 1] = argvars[i];
1156 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001157 else if (global_functions[fi].f_argtype == FEARG_3)
1158 {
1159 // base value goes third
1160 argv[0] = argvars[0];
1161 argv[1] = argvars[1];
1162 argv[2] = *basetv;
1163 for (i = 2; i < argcount; ++i)
1164 argv[i + 1] = argvars[i];
1165 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001166 else if (global_functions[fi].f_argtype == FEARG_4)
1167 {
1168 // base value goes fourth
1169 argv[0] = argvars[0];
1170 argv[1] = argvars[1];
1171 argv[2] = argvars[2];
1172 argv[3] = *basetv;
1173 for (i = 3; i < argcount; ++i)
1174 argv[i + 1] = argvars[i];
1175 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001176 else
1177 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001178 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001179 argv[0] = *basetv;
1180 for (i = 0; i < argcount; ++i)
1181 argv[i + 1] = argvars[i];
1182 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001183 argv[argcount + 1].v_type = VAR_UNKNOWN;
1184
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001185 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001186 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001187}
1188
1189/*
1190 * Return TRUE for a non-zero Number and a non-empty String.
1191 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001192 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001193non_zero_arg(typval_T *argvars)
1194{
1195 return ((argvars[0].v_type == VAR_NUMBER
1196 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001197 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001198 && argvars[0].vval.v_number == VVAL_TRUE)
1199 || (argvars[0].v_type == VAR_STRING
1200 && argvars[0].vval.v_string != NULL
1201 && *argvars[0].vval.v_string != NUL));
1202}
1203
1204/*
1205 * Get the lnum from the first argument.
1206 * Also accepts ".", "$", etc., but that only works for the current buffer.
1207 * Returns -1 on error.
1208 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001209 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001210tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001211{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001212 linenr_T lnum;
1213
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001214 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001215 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001216 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001217 int fnum;
1218 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1219
1220 if (fp != NULL)
1221 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001222 }
1223 return lnum;
1224}
1225
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001226/*
1227 * Get the lnum from the first argument.
1228 * Also accepts "$", then "buf" is used.
1229 * Returns 0 on error.
1230 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001231 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001232tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1233{
1234 if (argvars[0].v_type == VAR_STRING
1235 && argvars[0].vval.v_string != NULL
1236 && argvars[0].vval.v_string[0] == '$'
1237 && buf != NULL)
1238 return buf->b_ml.ml_line_count;
1239 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1240}
1241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001242#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001243/*
1244 * Get the float value of "argvars[0]" into "f".
1245 * Returns FAIL when the argument is not a Number or Float.
1246 */
1247 static int
1248get_float_arg(typval_T *argvars, float_T *f)
1249{
1250 if (argvars[0].v_type == VAR_FLOAT)
1251 {
1252 *f = argvars[0].vval.v_float;
1253 return OK;
1254 }
1255 if (argvars[0].v_type == VAR_NUMBER)
1256 {
1257 *f = (float_T)argvars[0].vval.v_number;
1258 return OK;
1259 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001260 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001261 return FAIL;
1262}
1263
1264/*
1265 * "abs(expr)" function
1266 */
1267 static void
1268f_abs(typval_T *argvars, typval_T *rettv)
1269{
1270 if (argvars[0].v_type == VAR_FLOAT)
1271 {
1272 rettv->v_type = VAR_FLOAT;
1273 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1274 }
1275 else
1276 {
1277 varnumber_T n;
1278 int error = FALSE;
1279
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001280 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001281 if (error)
1282 rettv->vval.v_number = -1;
1283 else if (n > 0)
1284 rettv->vval.v_number = n;
1285 else
1286 rettv->vval.v_number = -n;
1287 }
1288}
1289
1290/*
1291 * "acos()" function
1292 */
1293 static void
1294f_acos(typval_T *argvars, typval_T *rettv)
1295{
1296 float_T f = 0.0;
1297
1298 rettv->v_type = VAR_FLOAT;
1299 if (get_float_arg(argvars, &f) == OK)
1300 rettv->vval.v_float = acos(f);
1301 else
1302 rettv->vval.v_float = 0.0;
1303}
1304#endif
1305
1306/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001307 * "and(expr, expr)" function
1308 */
1309 static void
1310f_and(typval_T *argvars, typval_T *rettv)
1311{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001312 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1313 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001314}
1315
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001316#ifdef FEAT_FLOAT
1317/*
1318 * "asin()" function
1319 */
1320 static void
1321f_asin(typval_T *argvars, typval_T *rettv)
1322{
1323 float_T f = 0.0;
1324
1325 rettv->v_type = VAR_FLOAT;
1326 if (get_float_arg(argvars, &f) == OK)
1327 rettv->vval.v_float = asin(f);
1328 else
1329 rettv->vval.v_float = 0.0;
1330}
1331
1332/*
1333 * "atan()" function
1334 */
1335 static void
1336f_atan(typval_T *argvars, typval_T *rettv)
1337{
1338 float_T f = 0.0;
1339
1340 rettv->v_type = VAR_FLOAT;
1341 if (get_float_arg(argvars, &f) == OK)
1342 rettv->vval.v_float = atan(f);
1343 else
1344 rettv->vval.v_float = 0.0;
1345}
1346
1347/*
1348 * "atan2()" function
1349 */
1350 static void
1351f_atan2(typval_T *argvars, typval_T *rettv)
1352{
1353 float_T fx = 0.0, fy = 0.0;
1354
1355 rettv->v_type = VAR_FLOAT;
1356 if (get_float_arg(argvars, &fx) == OK
1357 && get_float_arg(&argvars[1], &fy) == OK)
1358 rettv->vval.v_float = atan2(fx, fy);
1359 else
1360 rettv->vval.v_float = 0.0;
1361}
1362#endif
1363
1364/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001365 * "balloon_show()" function
1366 */
1367#ifdef FEAT_BEVAL
1368 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001369f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1370{
1371 rettv->v_type = VAR_STRING;
1372 if (balloonEval != NULL)
1373 {
1374 if (balloonEval->msg == NULL)
1375 rettv->vval.v_string = NULL;
1376 else
1377 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1378 }
1379}
1380
1381 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001382f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1383{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001384 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001385 {
1386 if (argvars[0].v_type == VAR_LIST
1387# ifdef FEAT_GUI
1388 && !gui.in_use
1389# endif
1390 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001391 {
1392 list_T *l = argvars[0].vval.v_list;
1393
1394 // empty list removes the balloon
1395 post_balloon(balloonEval, NULL,
1396 l == NULL || l->lv_len == 0 ? NULL : l);
1397 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001398 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001399 {
1400 char_u *mesg = tv_get_string_chk(&argvars[0]);
1401
1402 if (mesg != NULL)
1403 // empty string removes the balloon
1404 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1405 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001406 }
1407}
1408
Bram Moolenaar669a8282017-11-19 20:13:05 +01001409# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001410 static void
1411f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1412{
1413 if (rettv_list_alloc(rettv) == OK)
1414 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001415 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001416
1417 if (msg != NULL)
1418 {
1419 pumitem_T *array;
1420 int size = split_message(msg, &array);
1421 int i;
1422
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001423 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001424 for (i = 1; i < size - 1; ++i)
1425 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001426 while (size > 0)
1427 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001428 vim_free(array);
1429 }
1430 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001431}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001432# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001433#endif
1434
1435/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001436 * Get buffer by number or pattern.
1437 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001438 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001439tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001440{
1441 char_u *name = tv->vval.v_string;
1442 buf_T *buf;
1443
1444 if (tv->v_type == VAR_NUMBER)
1445 return buflist_findnr((int)tv->vval.v_number);
1446 if (tv->v_type != VAR_STRING)
1447 return NULL;
1448 if (name == NULL || *name == NUL)
1449 return curbuf;
1450 if (name[0] == '$' && name[1] == NUL)
1451 return lastbuf;
1452
1453 buf = buflist_find_by_name(name, curtab_only);
1454
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001455 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001456 if (buf == NULL)
1457 buf = find_buffer(tv);
1458
1459 return buf;
1460}
1461
1462/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001463 * Get the buffer from "arg" and give an error and return NULL if it is not
1464 * valid.
1465 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001466 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001467get_buf_arg(typval_T *arg)
1468{
1469 buf_T *buf;
1470
1471 ++emsg_off;
1472 buf = tv_get_buf(arg, FALSE);
1473 --emsg_off;
1474 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001475 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001476 return buf;
1477}
1478
1479/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480 * "byte2line(byte)" function
1481 */
1482 static void
1483f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1484{
1485#ifndef FEAT_BYTEOFF
1486 rettv->vval.v_number = -1;
1487#else
1488 long boff = 0;
1489
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001490 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001491 if (boff < 0)
1492 rettv->vval.v_number = -1;
1493 else
1494 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1495 (linenr_T)0, &boff);
1496#endif
1497}
1498
1499 static void
1500byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1501{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001503 char_u *str;
1504 varnumber_T idx;
1505
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001506 str = tv_get_string_chk(&argvars[0]);
1507 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508 rettv->vval.v_number = -1;
1509 if (str == NULL || idx < 0)
1510 return;
1511
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001512 t = str;
1513 for ( ; idx > 0; idx--)
1514 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001515 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001516 return;
1517 if (enc_utf8 && comp)
1518 t += utf_ptr2len(t);
1519 else
1520 t += (*mb_ptr2len)(t);
1521 }
1522 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001523}
1524
1525/*
1526 * "byteidx()" function
1527 */
1528 static void
1529f_byteidx(typval_T *argvars, typval_T *rettv)
1530{
1531 byteidx(argvars, rettv, FALSE);
1532}
1533
1534/*
1535 * "byteidxcomp()" function
1536 */
1537 static void
1538f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1539{
1540 byteidx(argvars, rettv, TRUE);
1541}
1542
1543/*
1544 * "call(func, arglist [, dict])" function
1545 */
1546 static void
1547f_call(typval_T *argvars, typval_T *rettv)
1548{
1549 char_u *func;
1550 partial_T *partial = NULL;
1551 dict_T *selfdict = NULL;
1552
1553 if (argvars[1].v_type != VAR_LIST)
1554 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001555 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 return;
1557 }
1558 if (argvars[1].vval.v_list == NULL)
1559 return;
1560
1561 if (argvars[0].v_type == VAR_FUNC)
1562 func = argvars[0].vval.v_string;
1563 else if (argvars[0].v_type == VAR_PARTIAL)
1564 {
1565 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001566 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001567 }
1568 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001569 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001571 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001572
1573 if (argvars[2].v_type != VAR_UNKNOWN)
1574 {
1575 if (argvars[2].v_type != VAR_DICT)
1576 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001577 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578 return;
1579 }
1580 selfdict = argvars[2].vval.v_dict;
1581 }
1582
1583 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1584}
1585
1586#ifdef FEAT_FLOAT
1587/*
1588 * "ceil({float})" function
1589 */
1590 static void
1591f_ceil(typval_T *argvars, typval_T *rettv)
1592{
1593 float_T f = 0.0;
1594
1595 rettv->v_type = VAR_FLOAT;
1596 if (get_float_arg(argvars, &f) == OK)
1597 rettv->vval.v_float = ceil(f);
1598 else
1599 rettv->vval.v_float = 0.0;
1600}
1601#endif
1602
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603/*
1604 * "changenr()" function
1605 */
1606 static void
1607f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1608{
1609 rettv->vval.v_number = curbuf->b_u_seq_cur;
1610}
1611
1612/*
1613 * "char2nr(string)" function
1614 */
1615 static void
1616f_char2nr(typval_T *argvars, typval_T *rettv)
1617{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001618 if (has_mbyte)
1619 {
1620 int utf8 = 0;
1621
1622 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001623 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624
1625 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001626 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001628 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001629 }
1630 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001631 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001632}
1633
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001634 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001635get_optional_window(typval_T *argvars, int idx)
1636{
1637 win_T *win = curwin;
1638
1639 if (argvars[idx].v_type != VAR_UNKNOWN)
1640 {
1641 win = find_win_by_nr_or_id(&argvars[idx]);
1642 if (win == NULL)
1643 {
1644 emsg(_(e_invalwindow));
1645 return NULL;
1646 }
1647 }
1648 return win;
1649}
1650
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001652 * "col(string)" function
1653 */
1654 static void
1655f_col(typval_T *argvars, typval_T *rettv)
1656{
1657 colnr_T col = 0;
1658 pos_T *fp;
1659 int fnum = curbuf->b_fnum;
1660
1661 fp = var2fpos(&argvars[0], FALSE, &fnum);
1662 if (fp != NULL && fnum == curbuf->b_fnum)
1663 {
1664 if (fp->col == MAXCOL)
1665 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001666 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1668 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1669 else
1670 col = MAXCOL;
1671 }
1672 else
1673 {
1674 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001675 // col(".") when the cursor is on the NUL at the end of the line
1676 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001677 if (virtual_active() && fp == &curwin->w_cursor)
1678 {
1679 char_u *p = ml_get_cursor();
1680
1681 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1682 curwin->w_virtcol - curwin->w_cursor.coladd))
1683 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001684 int l;
1685
1686 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1687 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 }
1689 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001690 }
1691 }
1692 rettv->vval.v_number = col;
1693}
1694
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001695/*
1696 * "confirm(message, buttons[, default [, type]])" function
1697 */
1698 static void
1699f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1700{
1701#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1702 char_u *message;
1703 char_u *buttons = NULL;
1704 char_u buf[NUMBUFLEN];
1705 char_u buf2[NUMBUFLEN];
1706 int def = 1;
1707 int type = VIM_GENERIC;
1708 char_u *typestr;
1709 int error = FALSE;
1710
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001711 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 if (message == NULL)
1713 error = TRUE;
1714 if (argvars[1].v_type != VAR_UNKNOWN)
1715 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001716 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001717 if (buttons == NULL)
1718 error = TRUE;
1719 if (argvars[2].v_type != VAR_UNKNOWN)
1720 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001721 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722 if (argvars[3].v_type != VAR_UNKNOWN)
1723 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001724 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 if (typestr == NULL)
1726 error = TRUE;
1727 else
1728 {
1729 switch (TOUPPER_ASC(*typestr))
1730 {
1731 case 'E': type = VIM_ERROR; break;
1732 case 'Q': type = VIM_QUESTION; break;
1733 case 'I': type = VIM_INFO; break;
1734 case 'W': type = VIM_WARNING; break;
1735 case 'G': type = VIM_GENERIC; break;
1736 }
1737 }
1738 }
1739 }
1740 }
1741
1742 if (buttons == NULL || *buttons == NUL)
1743 buttons = (char_u *)_("&Ok");
1744
1745 if (!error)
1746 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1747 def, NULL, FALSE);
1748#endif
1749}
1750
1751/*
1752 * "copy()" function
1753 */
1754 static void
1755f_copy(typval_T *argvars, typval_T *rettv)
1756{
1757 item_copy(&argvars[0], rettv, FALSE, 0);
1758}
1759
1760#ifdef FEAT_FLOAT
1761/*
1762 * "cos()" function
1763 */
1764 static void
1765f_cos(typval_T *argvars, typval_T *rettv)
1766{
1767 float_T f = 0.0;
1768
1769 rettv->v_type = VAR_FLOAT;
1770 if (get_float_arg(argvars, &f) == OK)
1771 rettv->vval.v_float = cos(f);
1772 else
1773 rettv->vval.v_float = 0.0;
1774}
1775
1776/*
1777 * "cosh()" function
1778 */
1779 static void
1780f_cosh(typval_T *argvars, typval_T *rettv)
1781{
1782 float_T f = 0.0;
1783
1784 rettv->v_type = VAR_FLOAT;
1785 if (get_float_arg(argvars, &f) == OK)
1786 rettv->vval.v_float = cosh(f);
1787 else
1788 rettv->vval.v_float = 0.0;
1789}
1790#endif
1791
1792/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001793 * "cursor(lnum, col)" function, or
1794 * "cursor(list)"
1795 *
1796 * Moves the cursor to the specified line and column.
1797 * Returns 0 when the position could be set, -1 otherwise.
1798 */
1799 static void
1800f_cursor(typval_T *argvars, typval_T *rettv)
1801{
1802 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001803 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001804 int set_curswant = TRUE;
1805
1806 rettv->vval.v_number = -1;
1807 if (argvars[1].v_type == VAR_UNKNOWN)
1808 {
1809 pos_T pos;
1810 colnr_T curswant = -1;
1811
1812 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1813 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001814 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001815 return;
1816 }
1817 line = pos.lnum;
1818 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001819 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001820 if (curswant >= 0)
1821 {
1822 curwin->w_curswant = curswant - 1;
1823 set_curswant = FALSE;
1824 }
1825 }
1826 else
1827 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001828 line = tv_get_lnum(argvars);
1829 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001831 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001833 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001834 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835 if (line > 0)
1836 curwin->w_cursor.lnum = line;
1837 if (col > 0)
1838 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001840
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001841 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001842 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001843 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844 if (has_mbyte)
1845 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846
1847 curwin->w_set_curswant = set_curswant;
1848 rettv->vval.v_number = 0;
1849}
1850
Bram Moolenaar4f974752019-02-17 17:44:42 +01001851#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001852/*
1853 * "debugbreak()" function
1854 */
1855 static void
1856f_debugbreak(typval_T *argvars, typval_T *rettv)
1857{
1858 int pid;
1859
1860 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001861 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001862 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001863 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001864 else
1865 {
1866 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1867
1868 if (hProcess != NULL)
1869 {
1870 DebugBreakProcess(hProcess);
1871 CloseHandle(hProcess);
1872 rettv->vval.v_number = OK;
1873 }
1874 }
1875}
1876#endif
1877
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001878/*
1879 * "deepcopy()" function
1880 */
1881 static void
1882f_deepcopy(typval_T *argvars, typval_T *rettv)
1883{
1884 int noref = 0;
1885 int copyID;
1886
1887 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001888 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001889 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001890 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001891 else
1892 {
1893 copyID = get_copyID();
1894 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1895 }
1896}
1897
1898/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001899 * "did_filetype()" function
1900 */
1901 static void
1902f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1903{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001904 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001905}
1906
1907/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001908 * "echoraw({expr})" function
1909 */
1910 static void
1911f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1912{
1913 char_u *str = tv_get_string_chk(&argvars[0]);
1914
1915 if (str != NULL && *str != NUL)
1916 {
1917 out_str(str);
1918 out_flush();
1919 }
1920}
1921
1922/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001923 * "empty({expr})" function
1924 */
1925 static void
1926f_empty(typval_T *argvars, typval_T *rettv)
1927{
1928 int n = FALSE;
1929
1930 switch (argvars[0].v_type)
1931 {
1932 case VAR_STRING:
1933 case VAR_FUNC:
1934 n = argvars[0].vval.v_string == NULL
1935 || *argvars[0].vval.v_string == NUL;
1936 break;
1937 case VAR_PARTIAL:
1938 n = FALSE;
1939 break;
1940 case VAR_NUMBER:
1941 n = argvars[0].vval.v_number == 0;
1942 break;
1943 case VAR_FLOAT:
1944#ifdef FEAT_FLOAT
1945 n = argvars[0].vval.v_float == 0.0;
1946 break;
1947#endif
1948 case VAR_LIST:
1949 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001950 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001951 break;
1952 case VAR_DICT:
1953 n = argvars[0].vval.v_dict == NULL
1954 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1955 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001956 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 case VAR_SPECIAL:
1958 n = argvars[0].vval.v_number != VVAL_TRUE;
1959 break;
1960
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001961 case VAR_BLOB:
1962 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001963 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1964 break;
1965
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001966 case VAR_JOB:
1967#ifdef FEAT_JOB_CHANNEL
1968 n = argvars[0].vval.v_job == NULL
1969 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1970 break;
1971#endif
1972 case VAR_CHANNEL:
1973#ifdef FEAT_JOB_CHANNEL
1974 n = argvars[0].vval.v_channel == NULL
1975 || !channel_is_open(argvars[0].vval.v_channel);
1976 break;
1977#endif
1978 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001979 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001980 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001981 n = TRUE;
1982 break;
1983 }
1984
1985 rettv->vval.v_number = n;
1986}
1987
1988/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001989 * "environ()" function
1990 */
1991 static void
1992f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1993{
1994#if !defined(AMIGA)
1995 int i = 0;
1996 char_u *entry, *value;
1997# ifdef MSWIN
1998 extern wchar_t **_wenviron;
1999# else
2000 extern char **environ;
2001# endif
2002
2003 if (rettv_dict_alloc(rettv) != OK)
2004 return;
2005
2006# ifdef MSWIN
2007 if (*_wenviron == NULL)
2008 return;
2009# else
2010 if (*environ == NULL)
2011 return;
2012# endif
2013
2014 for (i = 0; ; ++i)
2015 {
2016# ifdef MSWIN
2017 short_u *p;
2018
2019 if ((p = (short_u *)_wenviron[i]) == NULL)
2020 return;
2021 entry = utf16_to_enc(p, NULL);
2022# else
2023 if ((entry = (char_u *)environ[i]) == NULL)
2024 return;
2025 entry = vim_strsave(entry);
2026# endif
2027 if (entry == NULL) // out of memory
2028 return;
2029 if ((value = vim_strchr(entry, '=')) == NULL)
2030 {
2031 vim_free(entry);
2032 continue;
2033 }
2034 *value++ = NUL;
2035 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2036 vim_free(entry);
2037 }
2038#endif
2039}
2040
2041/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002042 * "escape({string}, {chars})" function
2043 */
2044 static void
2045f_escape(typval_T *argvars, typval_T *rettv)
2046{
2047 char_u buf[NUMBUFLEN];
2048
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002049 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2050 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002051 rettv->v_type = VAR_STRING;
2052}
2053
2054/*
2055 * "eval()" function
2056 */
2057 static void
2058f_eval(typval_T *argvars, typval_T *rettv)
2059{
2060 char_u *s, *p;
2061
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002062 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002063 if (s != NULL)
2064 s = skipwhite(s);
2065
2066 p = s;
2067 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2068 {
2069 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002070 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002071 need_clr_eos = FALSE;
2072 rettv->v_type = VAR_NUMBER;
2073 rettv->vval.v_number = 0;
2074 }
2075 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002076 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077}
2078
2079/*
2080 * "eventhandler()" function
2081 */
2082 static void
2083f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2084{
2085 rettv->vval.v_number = vgetc_busy;
2086}
2087
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088static garray_T redir_execute_ga;
2089
2090/*
2091 * Append "value[value_len]" to the execute() output.
2092 */
2093 void
2094execute_redir_str(char_u *value, int value_len)
2095{
2096 int len;
2097
2098 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002099 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002100 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002101 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002102 if (ga_grow(&redir_execute_ga, len) == OK)
2103 {
2104 mch_memmove((char *)redir_execute_ga.ga_data
2105 + redir_execute_ga.ga_len, value, len);
2106 redir_execute_ga.ga_len += len;
2107 }
2108}
2109
2110/*
2111 * Get next line from a list.
2112 * Called by do_cmdline() to get the next line.
2113 * Returns allocated string, or NULL for end of function.
2114 */
2115
2116 static char_u *
2117get_list_line(
2118 int c UNUSED,
2119 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002120 int indent UNUSED,
2121 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122{
2123 listitem_T **p = (listitem_T **)cookie;
2124 listitem_T *item = *p;
2125 char_u buf[NUMBUFLEN];
2126 char_u *s;
2127
2128 if (item == NULL)
2129 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002130 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002131 *p = item->li_next;
2132 return s == NULL ? NULL : vim_strsave(s);
2133}
2134
2135/*
2136 * "execute()" function
2137 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002138 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002139execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002140{
2141 char_u *cmd = NULL;
2142 list_T *list = NULL;
2143 int save_msg_silent = msg_silent;
2144 int save_emsg_silent = emsg_silent;
2145 int save_emsg_noredir = emsg_noredir;
2146 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002147 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002148 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002149 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002150 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002151
2152 rettv->vval.v_string = NULL;
2153 rettv->v_type = VAR_STRING;
2154
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002155 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002156 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002157 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002158 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002159 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002160 return;
2161 ++list->lv_refcount;
2162 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002163 else if (argvars[arg_off].v_type == VAR_JOB
2164 || argvars[arg_off].v_type == VAR_CHANNEL)
2165 {
2166 emsg(_(e_inval_string));
2167 return;
2168 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002169 else
2170 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002171 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172 if (cmd == NULL)
2173 return;
2174 }
2175
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002176 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177 {
2178 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002179 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180
2181 if (s == NULL)
2182 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002183 if (*s == NUL)
2184 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002185 if (STRNCMP(s, "silent", 6) == 0)
2186 ++msg_silent;
2187 if (STRCMP(s, "silent!") == 0)
2188 {
2189 emsg_silent = TRUE;
2190 emsg_noredir = TRUE;
2191 }
2192 }
2193 else
2194 ++msg_silent;
2195
2196 if (redir_execute)
2197 save_ga = redir_execute_ga;
2198 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2199 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002200 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002201 if (!echo_output)
2202 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002203
2204 if (cmd != NULL)
2205 do_cmdline_cmd(cmd);
2206 else
2207 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002208 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002209
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002210 range_list_materialize(list);
2211 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002212 do_cmdline(NULL, get_list_line, (void *)&item,
2213 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2214 --list->lv_refcount;
2215 }
2216
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002217 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002218 if (ga_grow(&redir_execute_ga, 1) == OK)
2219 {
2220 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2221 rettv->vval.v_string = redir_execute_ga.ga_data;
2222 }
2223 else
2224 {
2225 ga_clear(&redir_execute_ga);
2226 rettv->vval.v_string = NULL;
2227 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002228 msg_silent = save_msg_silent;
2229 emsg_silent = save_emsg_silent;
2230 emsg_noredir = save_emsg_noredir;
2231
2232 redir_execute = save_redir_execute;
2233 if (redir_execute)
2234 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002235 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002236
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002237 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002238 if (echo_output)
2239 // When not working silently: put it in column zero. A following
2240 // "echon" will overwrite the message, unavoidably.
2241 msg_col = 0;
2242 else
2243 // When working silently: Put it back where it was, since nothing
2244 // should have been written.
2245 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002246}
2247
2248/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002249 * "execute()" function
2250 */
2251 static void
2252f_execute(typval_T *argvars, typval_T *rettv)
2253{
2254 execute_common(argvars, rettv, 0);
2255}
2256
2257/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002258 * "exists()" function
2259 */
2260 static void
2261f_exists(typval_T *argvars, typval_T *rettv)
2262{
2263 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002264 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002265
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002266 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002267 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002269 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002270 if (mch_getenv(p + 1) != NULL)
2271 n = TRUE;
2272 else
2273 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002274 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002275 p = expand_env_save(p);
2276 if (p != NULL && *p != '$')
2277 n = TRUE;
2278 vim_free(p);
2279 }
2280 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002281 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002282 {
2283 n = (get_option_tv(&p, NULL, TRUE) == OK);
2284 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002285 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002286 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002287 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002288 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002289 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002290 }
2291 else if (*p == ':')
2292 {
2293 n = cmd_exists(p + 1);
2294 }
2295 else if (*p == '#')
2296 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 if (p[1] == '#')
2298 n = autocmd_supported(p + 2);
2299 else
2300 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002302 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002304 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002305 }
2306
2307 rettv->vval.v_number = n;
2308}
2309
2310#ifdef FEAT_FLOAT
2311/*
2312 * "exp()" function
2313 */
2314 static void
2315f_exp(typval_T *argvars, typval_T *rettv)
2316{
2317 float_T f = 0.0;
2318
2319 rettv->v_type = VAR_FLOAT;
2320 if (get_float_arg(argvars, &f) == OK)
2321 rettv->vval.v_float = exp(f);
2322 else
2323 rettv->vval.v_float = 0.0;
2324}
2325#endif
2326
2327/*
2328 * "expand()" function
2329 */
2330 static void
2331f_expand(typval_T *argvars, typval_T *rettv)
2332{
2333 char_u *s;
2334 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002335 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002336 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2337 expand_T xpc;
2338 int error = FALSE;
2339 char_u *result;
2340
2341 rettv->v_type = VAR_STRING;
2342 if (argvars[1].v_type != VAR_UNKNOWN
2343 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002344 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002346 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002348 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002349 if (*s == '%' || *s == '#' || *s == '<')
2350 {
2351 ++emsg_off;
2352 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2353 --emsg_off;
2354 if (rettv->v_type == VAR_LIST)
2355 {
2356 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2357 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002358 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359 }
2360 else
2361 rettv->vval.v_string = result;
2362 }
2363 else
2364 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002365 // When the optional second argument is non-zero, don't remove matches
2366 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002368 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002369 options |= WILD_KEEP_ALL;
2370 if (!error)
2371 {
2372 ExpandInit(&xpc);
2373 xpc.xp_context = EXPAND_FILES;
2374 if (p_wic)
2375 options += WILD_ICASE;
2376 if (rettv->v_type == VAR_STRING)
2377 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2378 options, WILD_ALL);
2379 else if (rettv_list_alloc(rettv) != FAIL)
2380 {
2381 int i;
2382
2383 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2384 for (i = 0; i < xpc.xp_numfiles; i++)
2385 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2386 ExpandCleanup(&xpc);
2387 }
2388 }
2389 else
2390 rettv->vval.v_string = NULL;
2391 }
2392}
2393
2394/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002395 * "expandcmd()" function
2396 * Expand all the special characters in a command string.
2397 */
2398 static void
2399f_expandcmd(typval_T *argvars, typval_T *rettv)
2400{
2401 exarg_T eap;
2402 char_u *cmdstr;
2403 char *errormsg = NULL;
2404
2405 rettv->v_type = VAR_STRING;
2406 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2407
2408 memset(&eap, 0, sizeof(eap));
2409 eap.cmd = cmdstr;
2410 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002411 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002412 eap.usefilter = FALSE;
2413 eap.nextcmd = NULL;
2414 eap.cmdidx = CMD_USER;
2415
2416 expand_filename(&eap, &cmdstr, &errormsg);
2417 if (errormsg != NULL && *errormsg != NUL)
2418 emsg(errormsg);
2419
2420 rettv->vval.v_string = cmdstr;
2421}
2422
2423/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002424 * "feedkeys()" function
2425 */
2426 static void
2427f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2428{
2429 int remap = TRUE;
2430 int insert = FALSE;
2431 char_u *keys, *flags;
2432 char_u nbuf[NUMBUFLEN];
2433 int typed = FALSE;
2434 int execute = FALSE;
2435 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002436 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002437 char_u *keys_esc;
2438
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002439 // This is not allowed in the sandbox. If the commands would still be
2440 // executed in the sandbox it would be OK, but it probably happens later,
2441 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 if (check_secure())
2443 return;
2444
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002445 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446
2447 if (argvars[1].v_type != VAR_UNKNOWN)
2448 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002449 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 for ( ; *flags != NUL; ++flags)
2451 {
2452 switch (*flags)
2453 {
2454 case 'n': remap = FALSE; break;
2455 case 'm': remap = TRUE; break;
2456 case 't': typed = TRUE; break;
2457 case 'i': insert = TRUE; break;
2458 case 'x': execute = TRUE; break;
2459 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002460 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 }
2462 }
2463 }
2464
2465 if (*keys != NUL || execute)
2466 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002467 // Need to escape K_SPECIAL and CSI before putting the string in the
2468 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002469 keys_esc = vim_strsave_escape_csi(keys);
2470 if (keys_esc != NULL)
2471 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002472 if (lowlevel)
2473 {
2474#ifdef USE_INPUT_BUF
Bram Moolenaar9645e2d2020-03-20 20:48:49 +01002475 int idx;
2476 int len = (int)STRLEN(keys);
2477
2478 for (idx = 0; idx < len; ++idx)
2479 {
2480 // if a CTRL-C was typed, set got_int, similar to what
2481 // happens in fill_input_buf()
2482 if (keys[idx] == 3 && ctrl_c_interrupts && typed)
2483 got_int = TRUE;
2484 add_to_input_buf(keys + idx, 1);
2485 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002486#else
2487 emsg(_("E980: lowlevel input not supported"));
2488#endif
2489 }
2490 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002491 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002492 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002493 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002494 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002495#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002496 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002497#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002498 )
2499 typebuf_was_filled = TRUE;
2500 }
2501 vim_free(keys_esc);
2502
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002503 if (execute)
2504 {
2505 int save_msg_scroll = msg_scroll;
2506
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002507 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002508 msg_scroll = FALSE;
2509
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002510 if (!dangerous)
2511 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002512 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002513 if (!dangerous)
2514 --ex_normal_busy;
2515
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002516 msg_scroll |= save_msg_scroll;
2517 }
2518 }
2519 }
2520}
2521
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002522#ifdef FEAT_FLOAT
2523/*
2524 * "float2nr({float})" function
2525 */
2526 static void
2527f_float2nr(typval_T *argvars, typval_T *rettv)
2528{
2529 float_T f = 0.0;
2530
2531 if (get_float_arg(argvars, &f) == OK)
2532 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002533 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002534 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002535 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002536 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 else
2538 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002539 }
2540}
2541
2542/*
2543 * "floor({float})" function
2544 */
2545 static void
2546f_floor(typval_T *argvars, typval_T *rettv)
2547{
2548 float_T f = 0.0;
2549
2550 rettv->v_type = VAR_FLOAT;
2551 if (get_float_arg(argvars, &f) == OK)
2552 rettv->vval.v_float = floor(f);
2553 else
2554 rettv->vval.v_float = 0.0;
2555}
2556
2557/*
2558 * "fmod()" function
2559 */
2560 static void
2561f_fmod(typval_T *argvars, typval_T *rettv)
2562{
2563 float_T fx = 0.0, fy = 0.0;
2564
2565 rettv->v_type = VAR_FLOAT;
2566 if (get_float_arg(argvars, &fx) == OK
2567 && get_float_arg(&argvars[1], &fy) == OK)
2568 rettv->vval.v_float = fmod(fx, fy);
2569 else
2570 rettv->vval.v_float = 0.0;
2571}
2572#endif
2573
2574/*
2575 * "fnameescape({string})" function
2576 */
2577 static void
2578f_fnameescape(typval_T *argvars, typval_T *rettv)
2579{
2580 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002581 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 rettv->v_type = VAR_STRING;
2583}
2584
2585/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002586 * "foreground()" function
2587 */
2588 static void
2589f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2590{
2591#ifdef FEAT_GUI
2592 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002593 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002595 return;
2596 }
2597#endif
2598#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002599 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002600#endif
2601}
2602
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002603 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002604common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002605{
2606 char_u *s;
2607 char_u *name;
2608 int use_string = FALSE;
2609 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002610 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002611
2612 if (argvars[0].v_type == VAR_FUNC)
2613 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002614 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002615 s = argvars[0].vval.v_string;
2616 }
2617 else if (argvars[0].v_type == VAR_PARTIAL
2618 && argvars[0].vval.v_partial != NULL)
2619 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002620 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002622 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002623 }
2624 else
2625 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002626 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002627 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002628 use_string = TRUE;
2629 }
2630
Bram Moolenaar843b8842016-08-21 14:36:15 +02002631 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002632 {
2633 name = s;
2634 trans_name = trans_function_name(&name, FALSE,
2635 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2636 if (*name != NUL)
2637 s = NULL;
2638 }
2639
Bram Moolenaar843b8842016-08-21 14:36:15 +02002640 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2641 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002642 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002643 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002645 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002646 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002647 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002648 else
2649 {
2650 int dict_idx = 0;
2651 int arg_idx = 0;
2652 list_T *list = NULL;
2653
2654 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2655 {
2656 char sid_buf[25];
2657 int off = *s == 's' ? 2 : 5;
2658
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002659 // Expand s: and <SID> into <SNR>nr_, so that the function can
2660 // also be called from another script. Using trans_function_name()
2661 // would also work, but some plugins depend on the name being
2662 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002663 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002664 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002665 if (name != NULL)
2666 {
2667 STRCPY(name, sid_buf);
2668 STRCAT(name, s + off);
2669 }
2670 }
2671 else
2672 name = vim_strsave(s);
2673
2674 if (argvars[1].v_type != VAR_UNKNOWN)
2675 {
2676 if (argvars[2].v_type != VAR_UNKNOWN)
2677 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002678 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002679 arg_idx = 1;
2680 dict_idx = 2;
2681 }
2682 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002683 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002684 dict_idx = 1;
2685 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002686 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002687 arg_idx = 1;
2688 if (dict_idx > 0)
2689 {
2690 if (argvars[dict_idx].v_type != VAR_DICT)
2691 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002692 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002694 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002695 }
2696 if (argvars[dict_idx].vval.v_dict == NULL)
2697 dict_idx = 0;
2698 }
2699 if (arg_idx > 0)
2700 {
2701 if (argvars[arg_idx].v_type != VAR_LIST)
2702 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002703 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002705 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002706 }
2707 list = argvars[arg_idx].vval.v_list;
2708 if (list == NULL || list->lv_len == 0)
2709 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002710 else if (list->lv_len > MAX_FUNC_ARGS)
2711 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002712 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002713 vim_free(name);
2714 goto theend;
2715 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002716 }
2717 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002718 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002720 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002721
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002722 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002723 if (pt == NULL)
2724 vim_free(name);
2725 else
2726 {
2727 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2728 {
2729 listitem_T *li;
2730 int i = 0;
2731 int arg_len = 0;
2732 int lv_len = 0;
2733
2734 if (arg_pt != NULL)
2735 arg_len = arg_pt->pt_argc;
2736 if (list != NULL)
2737 lv_len = list->lv_len;
2738 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002739 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002740 if (pt->pt_argv == NULL)
2741 {
2742 vim_free(pt);
2743 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002744 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002745 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002746 for (i = 0; i < arg_len; i++)
2747 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2748 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002749 {
2750 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002751 for (li = list->lv_first; li != NULL;
2752 li = li->li_next)
2753 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002754 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002755 }
2756
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002757 // For "function(dict.func, [], dict)" and "func" is a partial
2758 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002759 if (dict_idx > 0)
2760 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002761 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2763 ++pt->pt_dict->dv_refcount;
2764 }
2765 else if (arg_pt != NULL)
2766 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002767 // If the dict was bound automatically the result is also
2768 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002769 pt->pt_dict = arg_pt->pt_dict;
2770 pt->pt_auto = arg_pt->pt_auto;
2771 if (pt->pt_dict != NULL)
2772 ++pt->pt_dict->dv_refcount;
2773 }
2774
2775 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002776 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2777 {
2778 pt->pt_func = arg_pt->pt_func;
2779 func_ptr_ref(pt->pt_func);
2780 vim_free(name);
2781 }
2782 else if (is_funcref)
2783 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002784 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002785 func_ptr_ref(pt->pt_func);
2786 vim_free(name);
2787 }
2788 else
2789 {
2790 pt->pt_name = name;
2791 func_ref(name);
2792 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002793 }
2794 rettv->v_type = VAR_PARTIAL;
2795 rettv->vval.v_partial = pt;
2796 }
2797 else
2798 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002799 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002800 rettv->v_type = VAR_FUNC;
2801 rettv->vval.v_string = name;
2802 func_ref(name);
2803 }
2804 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002805theend:
2806 vim_free(trans_name);
2807}
2808
2809/*
2810 * "funcref()" function
2811 */
2812 static void
2813f_funcref(typval_T *argvars, typval_T *rettv)
2814{
2815 common_function(argvars, rettv, TRUE);
2816}
2817
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002818 static type_T *
2819ret_f_function(int argcount, type_T **argtypes UNUSED)
2820{
2821 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2822 return &t_func_any;
2823 return &t_partial_void;
2824}
2825
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002826/*
2827 * "function()" function
2828 */
2829 static void
2830f_function(typval_T *argvars, typval_T *rettv)
2831{
2832 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002833}
2834
2835/*
2836 * "garbagecollect()" function
2837 */
2838 static void
2839f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2840{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002841 // This is postponed until we are back at the toplevel, because we may be
2842 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002843 want_garbage_collect = TRUE;
2844
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002845 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002846 garbage_collect_at_exit = TRUE;
2847}
2848
2849/*
2850 * "get()" function
2851 */
2852 static void
2853f_get(typval_T *argvars, typval_T *rettv)
2854{
2855 listitem_T *li;
2856 list_T *l;
2857 dictitem_T *di;
2858 dict_T *d;
2859 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002860 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002861
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002862 if (argvars[0].v_type == VAR_BLOB)
2863 {
2864 int error = FALSE;
2865 int idx = tv_get_number_chk(&argvars[1], &error);
2866
2867 if (!error)
2868 {
2869 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002870 if (idx < 0)
2871 idx = blob_len(argvars[0].vval.v_blob) + idx;
2872 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2873 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002874 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002875 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002876 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002877 tv = rettv;
2878 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002879 }
2880 }
2881 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002882 {
2883 if ((l = argvars[0].vval.v_list) != NULL)
2884 {
2885 int error = FALSE;
2886
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002887 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002888 if (!error && li != NULL)
2889 tv = &li->li_tv;
2890 }
2891 }
2892 else if (argvars[0].v_type == VAR_DICT)
2893 {
2894 if ((d = argvars[0].vval.v_dict) != NULL)
2895 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002896 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002897 if (di != NULL)
2898 tv = &di->di_tv;
2899 }
2900 }
2901 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2902 {
2903 partial_T *pt;
2904 partial_T fref_pt;
2905
2906 if (argvars[0].v_type == VAR_PARTIAL)
2907 pt = argvars[0].vval.v_partial;
2908 else
2909 {
2910 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2911 fref_pt.pt_name = argvars[0].vval.v_string;
2912 pt = &fref_pt;
2913 }
2914
2915 if (pt != NULL)
2916 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002917 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002918 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002919
2920 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2921 {
2922 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002923 n = partial_name(pt);
2924 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002925 rettv->vval.v_string = NULL;
2926 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002927 {
2928 rettv->vval.v_string = vim_strsave(n);
2929 if (rettv->v_type == VAR_FUNC)
2930 func_ref(rettv->vval.v_string);
2931 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002932 }
2933 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002934 {
2935 what_is_dict = TRUE;
2936 if (pt->pt_dict != NULL)
2937 rettv_dict_set(rettv, pt->pt_dict);
2938 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002939 else if (STRCMP(what, "args") == 0)
2940 {
2941 rettv->v_type = VAR_LIST;
2942 if (rettv_list_alloc(rettv) == OK)
2943 {
2944 int i;
2945
2946 for (i = 0; i < pt->pt_argc; ++i)
2947 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2948 }
2949 }
2950 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002951 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002952
2953 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2954 // third argument
2955 if (!what_is_dict)
2956 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002957 }
2958 }
2959 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002960 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002961
2962 if (tv == NULL)
2963 {
2964 if (argvars[2].v_type != VAR_UNKNOWN)
2965 copy_tv(&argvars[2], rettv);
2966 }
2967 else
2968 copy_tv(tv, rettv);
2969}
2970
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002971/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002972 * "getchangelist()" function
2973 */
2974 static void
2975f_getchangelist(typval_T *argvars, typval_T *rettv)
2976{
2977#ifdef FEAT_JUMPLIST
2978 buf_T *buf;
2979 int i;
2980 list_T *l;
2981 dict_T *d;
2982#endif
2983
2984 if (rettv_list_alloc(rettv) != OK)
2985 return;
2986
2987#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002988 if (argvars[0].v_type == VAR_UNKNOWN)
2989 buf = curbuf;
2990 else
2991 {
2992 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2993 ++emsg_off;
2994 buf = tv_get_buf(&argvars[0], FALSE);
2995 --emsg_off;
2996 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002997 if (buf == NULL)
2998 return;
2999
3000 l = list_alloc();
3001 if (l == NULL)
3002 return;
3003
3004 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3005 return;
3006 /*
3007 * The current window change list index tracks only the position in the
3008 * current buffer change list. For other buffers, use the change list
3009 * length as the current index.
3010 */
3011 list_append_number(rettv->vval.v_list,
3012 (varnumber_T)((buf == curwin->w_buffer)
3013 ? curwin->w_changelistidx : buf->b_changelistlen));
3014
3015 for (i = 0; i < buf->b_changelistlen; ++i)
3016 {
3017 if (buf->b_changelist[i].lnum == 0)
3018 continue;
3019 if ((d = dict_alloc()) == NULL)
3020 return;
3021 if (list_append_dict(l, d) == FAIL)
3022 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003023 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3024 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003025 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003026 }
3027#endif
3028}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003029
3030/*
3031 * "getcharsearch()" function
3032 */
3033 static void
3034f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3035{
3036 if (rettv_dict_alloc(rettv) != FAIL)
3037 {
3038 dict_T *dict = rettv->vval.v_dict;
3039
Bram Moolenaare0be1672018-07-08 16:50:37 +02003040 dict_add_string(dict, "char", last_csearch());
3041 dict_add_number(dict, "forward", last_csearch_forward());
3042 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003043 }
3044}
3045
3046/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003047 * "getenv()" function
3048 */
3049 static void
3050f_getenv(typval_T *argvars, typval_T *rettv)
3051{
3052 int mustfree = FALSE;
3053 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3054
3055 if (p == NULL)
3056 {
3057 rettv->v_type = VAR_SPECIAL;
3058 rettv->vval.v_number = VVAL_NULL;
3059 return;
3060 }
3061 if (!mustfree)
3062 p = vim_strsave(p);
3063 rettv->vval.v_string = p;
3064 rettv->v_type = VAR_STRING;
3065}
3066
3067/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003068 * "getfontname()" function
3069 */
3070 static void
3071f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3072{
3073 rettv->v_type = VAR_STRING;
3074 rettv->vval.v_string = NULL;
3075#ifdef FEAT_GUI
3076 if (gui.in_use)
3077 {
3078 GuiFont font;
3079 char_u *name = NULL;
3080
3081 if (argvars[0].v_type == VAR_UNKNOWN)
3082 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003083 // Get the "Normal" font. Either the name saved by
3084 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003085 font = gui.norm_font;
3086 name = hl_get_font_name();
3087 }
3088 else
3089 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003090 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003091 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003092 return;
3093 font = gui_mch_get_font(name, FALSE);
3094 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003095 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003096 }
3097 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3098 if (argvars[0].v_type != VAR_UNKNOWN)
3099 gui_mch_free_font(font);
3100 }
3101#endif
3102}
3103
3104/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003105 * "getjumplist()" function
3106 */
3107 static void
3108f_getjumplist(typval_T *argvars, typval_T *rettv)
3109{
3110#ifdef FEAT_JUMPLIST
3111 win_T *wp;
3112 int i;
3113 list_T *l;
3114 dict_T *d;
3115#endif
3116
3117 if (rettv_list_alloc(rettv) != OK)
3118 return;
3119
3120#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003121 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003122 if (wp == NULL)
3123 return;
3124
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003125 cleanup_jumplist(wp, TRUE);
3126
Bram Moolenaar4f505882018-02-10 21:06:32 +01003127 l = list_alloc();
3128 if (l == NULL)
3129 return;
3130
3131 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3132 return;
3133 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3134
3135 for (i = 0; i < wp->w_jumplistlen; ++i)
3136 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003137 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3138 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003139 if ((d = dict_alloc()) == NULL)
3140 return;
3141 if (list_append_dict(l, d) == FAIL)
3142 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003143 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3144 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003145 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003146 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003147 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003148 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003149 }
3150#endif
3151}
3152
3153/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003154 * "getpid()" function
3155 */
3156 static void
3157f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3158{
3159 rettv->vval.v_number = mch_get_pid();
3160}
3161
3162 static void
3163getpos_both(
3164 typval_T *argvars,
3165 typval_T *rettv,
3166 int getcurpos)
3167{
3168 pos_T *fp;
3169 list_T *l;
3170 int fnum = -1;
3171
3172 if (rettv_list_alloc(rettv) == OK)
3173 {
3174 l = rettv->vval.v_list;
3175 if (getcurpos)
3176 fp = &curwin->w_cursor;
3177 else
3178 fp = var2fpos(&argvars[0], TRUE, &fnum);
3179 if (fnum != -1)
3180 list_append_number(l, (varnumber_T)fnum);
3181 else
3182 list_append_number(l, (varnumber_T)0);
3183 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3184 : (varnumber_T)0);
3185 list_append_number(l, (fp != NULL)
3186 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3187 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003188 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003189 (varnumber_T)0);
3190 if (getcurpos)
3191 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003192 int save_set_curswant = curwin->w_set_curswant;
3193 colnr_T save_curswant = curwin->w_curswant;
3194 colnr_T save_virtcol = curwin->w_virtcol;
3195
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003196 update_curswant();
3197 list_append_number(l, curwin->w_curswant == MAXCOL ?
3198 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003199
3200 // Do not change "curswant", as it is unexpected that a get
3201 // function has a side effect.
3202 if (save_set_curswant)
3203 {
3204 curwin->w_set_curswant = save_set_curswant;
3205 curwin->w_curswant = save_curswant;
3206 curwin->w_virtcol = save_virtcol;
3207 curwin->w_valid &= ~VALID_VIRTCOL;
3208 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003209 }
3210 }
3211 else
3212 rettv->vval.v_number = FALSE;
3213}
3214
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003215/*
3216 * "getcurpos()" function
3217 */
3218 static void
3219f_getcurpos(typval_T *argvars, typval_T *rettv)
3220{
3221 getpos_both(argvars, rettv, TRUE);
3222}
3223
3224/*
3225 * "getpos(string)" function
3226 */
3227 static void
3228f_getpos(typval_T *argvars, typval_T *rettv)
3229{
3230 getpos_both(argvars, rettv, FALSE);
3231}
3232
3233/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003234 * "getreg()" function
3235 */
3236 static void
3237f_getreg(typval_T *argvars, typval_T *rettv)
3238{
3239 char_u *strregname;
3240 int regname;
3241 int arg2 = FALSE;
3242 int return_list = FALSE;
3243 int error = FALSE;
3244
3245 if (argvars[0].v_type != VAR_UNKNOWN)
3246 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003247 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003248 error = strregname == NULL;
3249 if (argvars[1].v_type != VAR_UNKNOWN)
3250 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003251 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003252 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003253 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003254 }
3255 }
3256 else
3257 strregname = get_vim_var_str(VV_REG);
3258
3259 if (error)
3260 return;
3261
3262 regname = (strregname == NULL ? '"' : *strregname);
3263 if (regname == 0)
3264 regname = '"';
3265
3266 if (return_list)
3267 {
3268 rettv->v_type = VAR_LIST;
3269 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3270 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3271 if (rettv->vval.v_list == NULL)
3272 (void)rettv_list_alloc(rettv);
3273 else
3274 ++rettv->vval.v_list->lv_refcount;
3275 }
3276 else
3277 {
3278 rettv->v_type = VAR_STRING;
3279 rettv->vval.v_string = get_reg_contents(regname,
3280 arg2 ? GREG_EXPR_SRC : 0);
3281 }
3282}
3283
3284/*
3285 * "getregtype()" function
3286 */
3287 static void
3288f_getregtype(typval_T *argvars, typval_T *rettv)
3289{
3290 char_u *strregname;
3291 int regname;
3292 char_u buf[NUMBUFLEN + 2];
3293 long reglen = 0;
3294
3295 if (argvars[0].v_type != VAR_UNKNOWN)
3296 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003297 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003298 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003299 {
3300 rettv->v_type = VAR_STRING;
3301 rettv->vval.v_string = NULL;
3302 return;
3303 }
3304 }
3305 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003306 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003307 strregname = get_vim_var_str(VV_REG);
3308
3309 regname = (strregname == NULL ? '"' : *strregname);
3310 if (regname == 0)
3311 regname = '"';
3312
3313 buf[0] = NUL;
3314 buf[1] = NUL;
3315 switch (get_reg_type(regname, &reglen))
3316 {
3317 case MLINE: buf[0] = 'V'; break;
3318 case MCHAR: buf[0] = 'v'; break;
3319 case MBLOCK:
3320 buf[0] = Ctrl_V;
3321 sprintf((char *)buf + 1, "%ld", reglen + 1);
3322 break;
3323 }
3324 rettv->v_type = VAR_STRING;
3325 rettv->vval.v_string = vim_strsave(buf);
3326}
3327
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003328/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003329 * "gettagstack()" function
3330 */
3331 static void
3332f_gettagstack(typval_T *argvars, typval_T *rettv)
3333{
3334 win_T *wp = curwin; // default is current window
3335
3336 if (rettv_dict_alloc(rettv) != OK)
3337 return;
3338
3339 if (argvars[0].v_type != VAR_UNKNOWN)
3340 {
3341 wp = find_win_by_nr_or_id(&argvars[0]);
3342 if (wp == NULL)
3343 return;
3344 }
3345
3346 get_tagstack(wp, rettv->vval.v_dict);
3347}
3348
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003349// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003350#include "version.h"
3351
3352/*
3353 * "has()" function
3354 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003355 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003356f_has(typval_T *argvars, typval_T *rettv)
3357{
3358 int i;
3359 char_u *name;
Bram Moolenaar79296512020-03-22 16:17:14 +01003360 int x = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003361 int n = FALSE;
Bram Moolenaar79296512020-03-22 16:17:14 +01003362 typedef struct {
3363 char *name;
3364 short present;
3365 } has_item_T;
3366 static has_item_T has_list[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003367 {
Bram Moolenaar79296512020-03-22 16:17:14 +01003368 {"amiga",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003369#ifdef AMIGA
Bram Moolenaar79296512020-03-22 16:17:14 +01003370 1
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003371#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003372 0
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003373#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003374 },
3375 {"arp",
3376#if defined(AMIGA) && defined(FEAT_ARP)
3377 1
3378#else
3379 0
3380#endif
3381 },
3382 {"beos",
3383#ifdef __BEOS__
3384 1
3385#else
3386 0
3387#endif
3388 },
3389 {"haiku",
3390#ifdef __HAIKU__
3391 1
3392#else
3393 0
3394#endif
3395 },
3396 {"bsd",
3397#if defined(BSD) && !defined(MACOS_X)
3398 1
3399#else
3400 0
3401#endif
3402 },
3403 {"hpux",
3404#ifdef hpux
3405 1
3406#else
3407 0
3408#endif
3409 },
3410 {"linux",
3411#ifdef __linux__
3412 1
3413#else
3414 0
3415#endif
3416 },
3417 {"mac", // Mac OS X (and, once, Mac OS Classic)
3418#ifdef MACOS_X
3419 1
3420#else
3421 0
3422#endif
3423 },
3424 {"osx", // Mac OS X
3425#ifdef MACOS_X
3426 1
3427#else
3428 0
3429#endif
3430 },
3431 {"macunix", // Mac OS X, with the darwin feature
3432#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3433 1
3434#else
3435 0
3436#endif
3437 },
3438 {"osxdarwin", // synonym for macunix
3439#if defined(MACOS_X) && defined(MACOS_X_DARWIN)
3440 1
3441#else
3442 0
3443#endif
3444 },
3445 {"qnx",
3446#ifdef __QNX__
3447 1
3448#else
3449 0
3450#endif
3451 },
3452 {"sun",
3453#ifdef SUN_SYSTEM
3454 1
3455#else
3456 0
3457#endif
3458 },
3459 {"unix",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003460#ifdef UNIX
Bram Moolenaar79296512020-03-22 16:17:14 +01003461 1
3462#else
3463 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003464#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003465 },
3466 {"vms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003467#ifdef VMS
Bram Moolenaar79296512020-03-22 16:17:14 +01003468 1
3469#else
3470 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003472 },
3473 {"win32",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003474#ifdef MSWIN
Bram Moolenaar79296512020-03-22 16:17:14 +01003475 1
3476#else
3477 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003478#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003479 },
3480 {"win32unix",
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003481#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar79296512020-03-22 16:17:14 +01003482 1
3483#else
3484 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003485#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003486 },
3487 {"win64",
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003488#ifdef _WIN64
Bram Moolenaar79296512020-03-22 16:17:14 +01003489 1
3490#else
3491 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003493 },
3494 {"ebcdic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003495#ifdef EBCDIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003496 1
3497#else
3498 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003499#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003500 },
3501 {"fname_case",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003502#ifndef CASE_INSENSITIVE_FILENAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003503 1
3504#else
3505 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003507 },
3508 {"acl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003509#ifdef HAVE_ACL
Bram Moolenaar79296512020-03-22 16:17:14 +01003510 1
3511#else
3512 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003513#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003514 },
3515 {"arabic",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003516#ifdef FEAT_ARABIC
Bram Moolenaar79296512020-03-22 16:17:14 +01003517 1
3518#else
3519 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003521 },
3522 {"autocmd", 1},
3523 {"autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003524#ifdef FEAT_AUTOCHDIR
Bram Moolenaar79296512020-03-22 16:17:14 +01003525 1
3526#else
3527 0
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003528#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003529 },
3530 {"autoservername",
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003531#ifdef FEAT_AUTOSERVERNAME
Bram Moolenaar79296512020-03-22 16:17:14 +01003532 1
3533#else
3534 0
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003535#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003536 },
3537 {"balloon_eval",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003538#ifdef FEAT_BEVAL_GUI
Bram Moolenaar79296512020-03-22 16:17:14 +01003539 1
3540#else
3541 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003542#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003543 },
3544 {"balloon_multiline",
3545#if defined(FEAT_BEVAL_GUI) && !defined(FEAT_GUI_MSWIN)
3546 // MS-Windows requires runtime check, see below
3547 1
3548#else
3549 0
3550#endif
3551 },
3552 {"balloon_eval_term",
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003553#ifdef FEAT_BEVAL_TERM
Bram Moolenaar79296512020-03-22 16:17:14 +01003554 1
3555#else
3556 0
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003557#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003558 },
3559 {"builtin_terms",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003560#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
Bram Moolenaar79296512020-03-22 16:17:14 +01003561 1
3562#else
3563 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003564#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003565 },
3566 {"all_builtin_terms",
3567#if defined(ALL_BUILTIN_TCAPS)
3568 1
3569#else
3570 0
3571#endif
3572 },
3573 {"browsefilter",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003574#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003575 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003576 || defined(FEAT_GUI_MOTIF))
Bram Moolenaar79296512020-03-22 16:17:14 +01003577 1
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003578#else
Bram Moolenaar79296512020-03-22 16:17:14 +01003579 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003580#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01003581 },
3582 {"byte_offset",
3583#ifdef FEAT_BYTEOFF
3584 1
3585#else
3586 0
3587#endif
3588 },
3589 {"channel",
3590#ifdef FEAT_JOB_CHANNEL
3591 1
3592#else
3593 0
3594#endif
3595 },
3596 {"cindent",
3597#ifdef FEAT_CINDENT
3598 1
3599#else
3600 0
3601#endif
3602 },
3603 {"clientserver",
3604#ifdef FEAT_CLIENTSERVER
3605 1
3606#else
3607 0
3608#endif
3609 },
3610 {"clipboard",
3611#ifdef FEAT_CLIPBOARD
3612 1
3613#else
3614 0
3615#endif
3616 },
3617 {"cmdline_compl", 1},
3618 {"cmdline_hist", 1},
3619 {"comments", 1},
3620 {"conceal",
3621#ifdef FEAT_CONCEAL
3622 1
3623#else
3624 0
3625#endif
3626 },
3627 {"cryptv",
3628#ifdef FEAT_CRYPT
3629 1
3630#else
3631 0
3632#endif
3633 },
3634 {"crypt-blowfish",
3635#ifdef FEAT_CRYPT
3636 1
3637#else
3638 0
3639#endif
3640 },
3641 {"crypt-blowfish2",
3642#ifdef FEAT_CRYPT
3643 1
3644#else
3645 0
3646#endif
3647 },
3648 {"cscope",
3649#ifdef FEAT_CSCOPE
3650 1
3651#else
3652 0
3653#endif
3654 },
3655 {"cursorbind", 1},
3656 {"cursorshape",
3657#ifdef CURSOR_SHAPE
3658 1
3659#else
3660 0
3661#endif
3662 },
3663 {"debug",
3664#ifdef DEBUG
3665 1
3666#else
3667 0
3668#endif
3669 },
3670 {"dialog_con",
3671#ifdef FEAT_CON_DIALOG
3672 1
3673#else
3674 0
3675#endif
3676 },
3677 {"dialog_gui",
3678#ifdef FEAT_GUI_DIALOG
3679 1
3680#else
3681 0
3682#endif
3683 },
3684 {"diff",
3685#ifdef FEAT_DIFF
3686 1
3687#else
3688 0
3689#endif
3690 },
3691 {"digraphs",
3692#ifdef FEAT_DIGRAPHS
3693 1
3694#else
3695 0
3696#endif
3697 },
3698 {"directx",
3699#ifdef FEAT_DIRECTX
3700 1
3701#else
3702 0
3703#endif
3704 },
3705 {"dnd",
3706#ifdef FEAT_DND
3707 1
3708#else
3709 0
3710#endif
3711 },
3712 {"emacs_tags",
3713#ifdef FEAT_EMACS_TAGS
3714 1
3715#else
3716 0
3717#endif
3718 },
3719 {"eval", 1}, // always present, of course!
3720 {"ex_extra", 1}, // graduated feature
3721 {"extra_search",
3722#ifdef FEAT_SEARCH_EXTRA
3723 1
3724#else
3725 0
3726#endif
3727 },
3728 {"file_in_path",
3729#ifdef FEAT_SEARCHPATH
3730 1
3731#else
3732 0
3733#endif
3734 },
3735 {"filterpipe",
3736#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
3737 1
3738#else
3739 0
3740#endif
3741 },
3742 {"find_in_path",
3743#ifdef FEAT_FIND_ID
3744 1
3745#else
3746 0
3747#endif
3748 },
3749 {"float",
3750#ifdef FEAT_FLOAT
3751 1
3752#else
3753 0
3754#endif
3755 },
3756 {"folding",
3757#ifdef FEAT_FOLDING
3758 1
3759#else
3760 0
3761#endif
3762 },
3763 {"footer",
3764#ifdef FEAT_FOOTER
3765 1
3766#else
3767 0
3768#endif
3769 },
3770 {"fork",
3771#if !defined(USE_SYSTEM) && defined(UNIX)
3772 1
3773#else
3774 0
3775#endif
3776 },
3777 {"gettext",
3778#ifdef FEAT_GETTEXT
3779 1
3780#else
3781 0
3782#endif
3783 },
3784 {"gui",
3785#ifdef FEAT_GUI
3786 1
3787#else
3788 0
3789#endif
3790 },
3791 {"gui_neXtaw",
3792#if defined(FEAT_GUI_ATHENA) && defined(FEAT_GUI_NEXTAW)
3793 1
3794#else
3795 0
3796#endif
3797 },
3798 {"gui_athena",
3799#if defined(FEAT_GUI_ATHENA) && !defined(FEAT_GUI_NEXTAW)
3800 1
3801#else
3802 0
3803#endif
3804 },
3805 {"gui_gtk",
3806#ifdef FEAT_GUI_GTK
3807 1
3808#else
3809 0
3810#endif
3811 },
3812 {"gui_gtk2",
3813#if defined(FEAT_GUI_GTK) && !defined(USE_GTK3)
3814 1
3815#else
3816 0
3817#endif
3818 },
3819 {"gui_gtk3",
3820#if defined(FEAT_GUI_GTK) && defined(USE_GTK3)
3821 1
3822#else
3823 0
3824#endif
3825 },
3826 {"gui_gnome",
3827#ifdef FEAT_GUI_GNOME
3828 1
3829#else
3830 0
3831#endif
3832 },
3833 {"gui_haiku",
3834#ifdef FEAT_GUI_HAIKU
3835 1
3836#else
3837 0
3838#endif
3839 },
3840 {"gui_mac",
3841#ifdef FEAT_GUI_MAC
3842 1
3843#else
3844 0
3845#endif
3846 },
3847 {"gui_motif",
3848#ifdef FEAT_GUI_MOTIF
3849 1
3850#else
3851 0
3852#endif
3853 },
3854 {"gui_photon",
3855#ifdef FEAT_GUI_PHOTON
3856 1
3857#else
3858 0
3859#endif
3860 },
3861 {"gui_win32",
3862#ifdef FEAT_GUI_MSWIN
3863 1
3864#else
3865 0
3866#endif
3867 },
3868 {"iconv",
3869#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3870 1
3871#else
3872 0
3873#endif
3874 },
3875 {"insert_expand", 1},
3876 {"job",
3877#ifdef FEAT_JOB_CHANNEL
3878 1
3879#else
3880 0
3881#endif
3882 },
3883 {"jumplist",
3884#ifdef FEAT_JUMPLIST
3885 1
3886#else
3887 0
3888#endif
3889 },
3890 {"keymap",
3891#ifdef FEAT_KEYMAP
3892 1
3893#else
3894 0
3895#endif
3896 },
3897 {"lambda", 1}, // always with FEAT_EVAL, since 7.4.2120 with closure
3898 {"langmap",
3899#ifdef FEAT_LANGMAP
3900 1
3901#else
3902 0
3903#endif
3904 },
3905 {"libcall",
3906#ifdef FEAT_LIBCALL
3907 1
3908#else
3909 0
3910#endif
3911 },
3912 {"linebreak",
3913#ifdef FEAT_LINEBREAK
3914 1
3915#else
3916 0
3917#endif
3918 },
3919 {"lispindent",
3920#ifdef FEAT_LISP
3921 1
3922#else
3923 0
3924#endif
3925 },
3926 {"listcmds", 1},
3927 {"localmap", 1},
3928 {"lua",
3929#if defined(FEAT_LUA) && !defined(DYNAMIC_LUA)
3930 1
3931#else
3932 0
3933#endif
3934 },
3935 {"menu",
3936#ifdef FEAT_MENU
3937 1
3938#else
3939 0
3940#endif
3941 },
3942 {"mksession",
3943#ifdef FEAT_SESSION
3944 1
3945#else
3946 0
3947#endif
3948 },
3949 {"modify_fname", 1},
3950 {"mouse", 1},
3951 {"mouseshape",
3952#ifdef FEAT_MOUSESHAPE
3953 1
3954#else
3955 0
3956#endif
3957 },
3958 {"mouse_dec",
3959#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_DEC)
3960 1
3961#else
3962 0
3963#endif
3964 },
3965 {"mouse_gpm",
3966#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_GPM)
3967 1
3968#else
3969 0
3970#endif
3971 },
3972 {"mouse_jsbterm",
3973#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_JSB)
3974 1
3975#else
3976 0
3977#endif
3978 },
3979 {"mouse_netterm",
3980#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_NET)
3981 1
3982#else
3983 0
3984#endif
3985 },
3986 {"mouse_pterm",
3987#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_PTERM)
3988 1
3989#else
3990 0
3991#endif
3992 },
3993 {"mouse_sgr",
3994#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
3995 1
3996#else
3997 0
3998#endif
3999 },
4000 {"mouse_sysmouse",
4001#if (defined(UNIX) || defined(VMS)) && defined(FEAT_SYSMOUSE)
4002 1
4003#else
4004 0
4005#endif
4006 },
4007 {"mouse_urxvt",
4008#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_URXVT)
4009 1
4010#else
4011 0
4012#endif
4013 },
4014 {"mouse_xterm",
4015#if (defined(UNIX) || defined(VMS)) && defined(FEAT_MOUSE_XTERM)
4016 1
4017#else
4018 0
4019#endif
4020 },
4021 {"multi_byte", 1},
4022 {"multi_byte_ime",
4023#ifdef FEAT_MBYTE_IME
4024 1
4025#else
4026 0
4027#endif
4028 },
4029 {"multi_lang",
4030#ifdef FEAT_MULTI_LANG
4031 1
4032#else
4033 0
4034#endif
4035 },
4036 {"mzscheme",
4037#if defined(FEAT_MZSCHEME) && !defined(DYNAMIC_MZSCHEME)
4038 1
4039#else
4040 0
4041#endif
4042 },
4043 {"num64", 1},
4044 {"ole",
4045#ifdef FEAT_OLE
4046 1
4047#else
4048 0
4049#endif
4050 },
4051 {"packages",
4052#ifdef FEAT_EVAL
4053 1
4054#else
4055 0
4056#endif
4057 },
4058 {"path_extra",
4059#ifdef FEAT_PATH_EXTRA
4060 1
4061#else
4062 0
4063#endif
4064 },
4065 {"perl",
4066#if defined(FEAT_PERL) && !defined(DYNAMIC_PERL)
4067 1
4068#else
4069 0
4070#endif
4071 },
4072 {"persistent_undo",
4073#ifdef FEAT_PERSISTENT_UNDO
4074 1
4075#else
4076 0
4077#endif
4078 },
4079 {"python_compiled",
4080#if defined(FEAT_PYTHON)
4081 1
4082#else
4083 0
4084#endif
4085 },
4086 {"python_dynamic",
4087#if defined(FEAT_PYTHON) && defined(DYNAMIC_PYTHON)
4088 1
4089#else
4090 0
4091#endif
4092 },
4093 {"python",
4094#if defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)
4095 1
4096#else
4097 0
4098#endif
4099 },
4100 {"pythonx",
4101#if (defined(FEAT_PYTHON) && !defined(DYNAMIC_PYTHON)) \
4102 || (defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3))
4103 1
4104#else
4105 0
4106#endif
4107 },
4108 {"python3_compiled",
4109#if defined(FEAT_PYTHON3)
4110 1
4111#else
4112 0
4113#endif
4114 },
4115 {"python3_dynamic",
4116#if defined(FEAT_PYTHON3) && defined(DYNAMIC_PYTHON3)
4117 1
4118#else
4119 0
4120#endif
4121 },
4122 {"python3",
4123#if defined(FEAT_PYTHON3) && !defined(DYNAMIC_PYTHON3)
4124 1
4125#else
4126 0
4127#endif
4128 },
4129 {"popupwin",
4130#ifdef FEAT_PROP_POPUP
4131 1
4132#else
4133 0
4134#endif
4135 },
4136 {"postscript",
4137#ifdef FEAT_POSTSCRIPT
4138 1
4139#else
4140 0
4141#endif
4142 },
4143 {"printer",
4144#ifdef FEAT_PRINTER
4145 1
4146#else
4147 0
4148#endif
4149 },
4150 {"profile",
4151#ifdef FEAT_PROFILE
4152 1
4153#else
4154 0
4155#endif
4156 },
4157 {"reltime",
4158#ifdef FEAT_RELTIME
4159 1
4160#else
4161 0
4162#endif
4163 },
4164 {"quickfix",
4165#ifdef FEAT_QUICKFIX
4166 1
4167#else
4168 0
4169#endif
4170 },
4171 {"rightleft",
4172#ifdef FEAT_RIGHTLEFT
4173 1
4174#else
4175 0
4176#endif
4177 },
4178 {"ruby",
4179#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4180 1
4181#else
4182 0
4183#endif
4184 },
4185 {"scrollbind", 1},
4186 {"showcmd",
4187#ifdef FEAT_CMDL_INFO
4188 1
4189#else
4190 0
4191#endif
4192 },
4193 {"cmdline_info",
4194#ifdef FEAT_CMDL_INFO
4195 1
4196#else
4197 0
4198#endif
4199 },
4200 {"signs",
4201#ifdef FEAT_SIGNS
4202 1
4203#else
4204 0
4205#endif
4206 },
4207 {"smartindent",
4208#ifdef FEAT_SMARTINDENT
4209 1
4210#else
4211 0
4212#endif
4213 },
4214 {"startuptime",
4215#ifdef STARTUPTIME
4216 1
4217#else
4218 0
4219#endif
4220 },
4221 {"statusline",
4222#ifdef FEAT_STL_OPT
4223 1
4224#else
4225 0
4226#endif
4227 },
4228 {"netbeans_intg",
4229#ifdef FEAT_NETBEANS_INTG
4230 1
4231#else
4232 0
4233#endif
4234 },
4235 {"sound",
4236#ifdef FEAT_SOUND
4237 1
4238#else
4239 0
4240#endif
4241 },
4242 {"spell",
4243#ifdef FEAT_SPELL
4244 1
4245#else
4246 0
4247#endif
4248 },
4249 {"syntax",
4250#ifdef FEAT_SYN_HL
4251 1
4252#else
4253 0
4254#endif
4255 },
4256 {"system",
4257#if defined(USE_SYSTEM) || !defined(UNIX)
4258 1
4259#else
4260 0
4261#endif
4262 },
4263 {"tag_binary",
4264#ifdef FEAT_TAG_BINS
4265 1
4266#else
4267 0
4268#endif
4269 },
4270 {"tcl",
4271#if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
4272 1
4273#else
4274 0
4275#endif
4276 },
4277 {"termguicolors",
4278#ifdef FEAT_TERMGUICOLORS
4279 1
4280#else
4281 0
4282#endif
4283 },
4284 {"terminal",
4285#if defined(FEAT_TERMINAL) && !defined(MSWIN)
4286 1
4287#else
4288 0
4289#endif
4290 },
4291 {"terminfo",
4292#ifdef TERMINFO
4293 1
4294#else
4295 0
4296#endif
4297 },
4298 {"termresponse",
4299#ifdef FEAT_TERMRESPONSE
4300 1
4301#else
4302 0
4303#endif
4304 },
4305 {"textobjects",
4306#ifdef FEAT_TEXTOBJ
4307 1
4308#else
4309 0
4310#endif
4311 },
4312 {"textprop",
4313#ifdef FEAT_PROP_POPUP
4314 1
4315#else
4316 0
4317#endif
4318 },
4319 {"tgetent",
4320#ifdef HAVE_TGETENT
4321 1
4322#else
4323 0
4324#endif
4325 },
4326 {"timers",
4327#ifdef FEAT_TIMERS
4328 1
4329#else
4330 0
4331#endif
4332 },
4333 {"title",
4334#ifdef FEAT_TITLE
4335 1
4336#else
4337 0
4338#endif
4339 },
4340 {"toolbar",
4341#ifdef FEAT_TOOLBAR
4342 1
4343#else
4344 0
4345#endif
4346 },
4347 {"unnamedplus",
4348#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4349 1
4350#else
4351 0
4352#endif
4353 },
4354 {"user-commands", 1}, // was accidentally included in 5.4
4355 {"user_commands", 1},
4356 {"vartabs",
4357#ifdef FEAT_VARTABS
4358 1
4359#else
4360 0
4361#endif
4362 },
4363 {"vertsplit", 1},
4364 {"viminfo",
4365#ifdef FEAT_VIMINFO
4366 1
4367#else
4368 0
4369#endif
4370 },
4371 {"vimscript-1", 1},
4372 {"vimscript-2", 1},
4373 {"vimscript-3", 1},
4374 {"vimscript-4", 1},
4375 {"virtualedit", 1},
4376 {"visual", 1},
4377 {"visualextra", 1},
4378 {"vreplace", 1},
4379 {"vtp",
4380#ifdef FEAT_VTP
4381 1
4382#else
4383 0
4384#endif
4385 },
4386 {"wildignore",
4387#ifdef FEAT_WILDIGN
4388 1
4389#else
4390 0
4391#endif
4392 },
4393 {"wildmenu",
4394#ifdef FEAT_WILDMENU
4395 1
4396#else
4397 0
4398#endif
4399 },
4400 {"windows", 1},
4401 {"winaltkeys",
4402#ifdef FEAT_WAK
4403 1
4404#else
4405 0
4406#endif
4407 },
4408 {"writebackup",
4409#ifdef FEAT_WRITEBACKUP
4410 1
4411#else
4412 0
4413#endif
4414 },
4415 {"xim",
4416#ifdef FEAT_XIM
4417 1
4418#else
4419 0
4420#endif
4421 },
4422 {"xfontset",
4423#ifdef FEAT_XFONTSET
4424 1
4425#else
4426 0
4427#endif
4428 },
4429 {"xpm",
4430#if defined(FEAT_XPM_W32) || defined(HAVE_XPM)
4431 1
4432#else
4433 0
4434#endif
4435 },
4436 {"xpm_w32", // for backward compatibility
4437#ifdef FEAT_XPM_W32
4438 1
4439#else
4440 0
4441#endif
4442 },
4443 {"xsmp",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004444#ifdef USE_XSMP
Bram Moolenaar79296512020-03-22 16:17:14 +01004445 1
4446#else
4447 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004449 },
4450 {"xsmp_interact",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004451#ifdef USE_XSMP_INTERACT
Bram Moolenaar79296512020-03-22 16:17:14 +01004452 1
4453#else
4454 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004455#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004456 },
4457 {"xterm_clipboard",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004458#ifdef FEAT_XCLIPBOARD
Bram Moolenaar79296512020-03-22 16:17:14 +01004459 1
4460#else
4461 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004462#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004463 },
4464 {"xterm_save",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004465#ifdef FEAT_XTERM_SAVE
Bram Moolenaar79296512020-03-22 16:17:14 +01004466 1
4467#else
4468 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004469#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004470 },
4471 {"X11",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004472#if defined(UNIX) && defined(FEAT_X11)
Bram Moolenaar79296512020-03-22 16:17:14 +01004473 1
4474#else
4475 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004476#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004477 },
4478 {NULL, 0}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004479 };
4480
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004481 name = tv_get_string(&argvars[0]);
Bram Moolenaar79296512020-03-22 16:17:14 +01004482 for (i = 0; has_list[i].name != NULL; ++i)
4483 if (STRICMP(name, has_list[i].name) == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004484 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004485 x = TRUE;
4486 n = has_list[i].present;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487 break;
4488 }
4489
Bram Moolenaar79296512020-03-22 16:17:14 +01004490 // features also in has_list[] but sometimes enabled at runtime
4491 if (x == TRUE && n == FALSE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004492 {
Bram Moolenaar79296512020-03-22 16:17:14 +01004493 if (0)
4494 ;
Bram Moolenaar4f974752019-02-17 17:44:42 +01004495#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004496 else if (STRICMP(name, "balloon_multiline") == 0)
4497 n = multiline_balloon_available();
4498#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004499#ifdef VIMDLL
4500 else if (STRICMP(name, "filterpipe") == 0)
4501 n = gui.in_use || gui.starting;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004502#endif
4503#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
4504 else if (STRICMP(name, "iconv") == 0)
4505 n = iconv_enabled(FALSE);
4506#endif
4507#ifdef DYNAMIC_LUA
4508 else if (STRICMP(name, "lua") == 0)
4509 n = lua_enabled(FALSE);
4510#endif
4511#ifdef DYNAMIC_MZSCHEME
4512 else if (STRICMP(name, "mzscheme") == 0)
4513 n = mzscheme_enabled(FALSE);
4514#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004515#ifdef DYNAMIC_PERL
4516 else if (STRICMP(name, "perl") == 0)
4517 n = perl_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004518#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004519#ifdef DYNAMIC_PYTHON
4520 else if (STRICMP(name, "python") == 0)
4521 n = python_enabled(FALSE);
4522#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004523#ifdef DYNAMIC_PYTHON3
4524 else if (STRICMP(name, "python3") == 0)
4525 n = python3_enabled(FALSE);
4526#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004527#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
4528 else if (STRICMP(name, "pythonx") == 0)
4529 {
4530# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
4531 if (p_pyx == 0)
4532 n = python3_enabled(FALSE) || python_enabled(FALSE);
4533 else if (p_pyx == 3)
4534 n = python3_enabled(FALSE);
4535 else if (p_pyx == 2)
4536 n = python_enabled(FALSE);
4537# elif defined(DYNAMIC_PYTHON)
4538 n = python_enabled(FALSE);
4539# elif defined(DYNAMIC_PYTHON3)
4540 n = python3_enabled(FALSE);
4541# endif
4542 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004543#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004544#ifdef DYNAMIC_RUBY
4545 else if (STRICMP(name, "ruby") == 0)
4546 n = ruby_enabled(FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004547#endif
Bram Moolenaar79296512020-03-22 16:17:14 +01004548#ifdef DYNAMIC_TCL
4549 else if (STRICMP(name, "tcl") == 0)
4550 n = tcl_enabled(FALSE);
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02004551#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004552#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02004553 else if (STRICMP(name, "terminal") == 0)
4554 n = terminal_enabled();
4555#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004556 }
4557
Bram Moolenaar79296512020-03-22 16:17:14 +01004558 // features not in has_list[]
4559 if (x == FALSE)
4560 {
4561 if (STRNICMP(name, "patch", 5) == 0)
4562 {
4563 x = TRUE;
4564 if (name[5] == '-'
4565 && STRLEN(name) >= 11
4566 && vim_isdigit(name[6])
4567 && vim_isdigit(name[8])
4568 && vim_isdigit(name[10]))
4569 {
4570 int major = atoi((char *)name + 6);
4571 int minor = atoi((char *)name + 8);
4572
4573 // Expect "patch-9.9.01234".
4574 n = (major < VIM_VERSION_MAJOR
4575 || (major == VIM_VERSION_MAJOR
4576 && (minor < VIM_VERSION_MINOR
4577 || (minor == VIM_VERSION_MINOR
4578 && has_patch(atoi((char *)name + 10))))));
4579 }
4580 else
4581 n = has_patch(atoi((char *)name + 5));
4582 }
4583 else if (STRICMP(name, "vim_starting") == 0)
4584 {
4585 x = TRUE;
4586 n = (starting != 0);
4587 }
4588 else if (STRICMP(name, "ttyin") == 0)
4589 {
4590 x = TRUE;
4591 n = mch_input_isatty();
4592 }
4593 else if (STRICMP(name, "ttyout") == 0)
4594 {
4595 x = TRUE;
4596 n = stdout_isatty;
4597 }
4598 else if (STRICMP(name, "multi_byte_encoding") == 0)
4599 {
4600 x = TRUE;
4601 n = has_mbyte;
4602 }
4603 else if (STRICMP(name, "gui_running") == 0)
4604 {
4605 x = TRUE;
4606#ifdef FEAT_GUI
4607 n = (gui.in_use || gui.starting);
4608#endif
4609 }
4610 else if (STRICMP(name, "browse") == 0)
4611 {
4612 x = TRUE;
4613#if defined(FEAT_GUI) && defined(FEAT_BROWSE)
4614 n = gui.in_use; // gui_mch_browse() works when GUI is running
4615#endif
4616 }
4617 else if (STRICMP(name, "syntax_items") == 0)
4618 {
4619 x = TRUE;
4620#ifdef FEAT_SYN_HL
4621 n = syntax_present(curwin);
4622#endif
4623 }
4624 else if (STRICMP(name, "vcon") == 0)
4625 {
4626 x = TRUE;
4627#ifdef FEAT_VTP
4628 n = is_term_win32() && has_vtp_working();
4629#endif
4630 }
4631 else if (STRICMP(name, "netbeans_enabled") == 0)
4632 {
4633 x = TRUE;
4634#ifdef FEAT_NETBEANS_INTG
4635 n = netbeans_active();
4636#endif
4637 }
4638 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
4639 {
4640 x = TRUE;
4641#ifdef FEAT_MOUSE_GPM
4642 n = gpm_enabled();
4643#endif
4644 }
4645 else if (STRICMP(name, "conpty") == 0)
4646 {
4647 x = TRUE;
4648#if defined(FEAT_TERMINAL) && defined(MSWIN)
4649 n = use_conpty();
4650#endif
4651 }
4652 else if (STRICMP(name, "clipboard_working") == 0)
4653 {
4654 x = TRUE;
4655#ifdef FEAT_CLIPBOARD
4656 n = clip_star.available;
4657#endif
4658 }
4659 }
4660
4661 if (argvars[1].v_type != VAR_UNKNOWN && tv_get_number(&argvars[1]) != 0)
4662 // return whether feature could ever be enabled
4663 rettv->vval.v_number = x;
4664 else
4665 // return whether feature is enabled
4666 rettv->vval.v_number = n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004667}
4668
4669/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004670 * "haslocaldir()" function
4671 */
4672 static void
4673f_haslocaldir(typval_T *argvars, typval_T *rettv)
4674{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004675 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004676 win_T *wp = NULL;
4677
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004678 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4679
4680 // Check for window-local and tab-local directories
4681 if (wp != NULL && wp->w_localdir != NULL)
4682 rettv->vval.v_number = 1;
4683 else if (tp != NULL && tp->tp_localdir != NULL)
4684 rettv->vval.v_number = 2;
4685 else
4686 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004687}
4688
4689/*
4690 * "hasmapto()" function
4691 */
4692 static void
4693f_hasmapto(typval_T *argvars, typval_T *rettv)
4694{
4695 char_u *name;
4696 char_u *mode;
4697 char_u buf[NUMBUFLEN];
4698 int abbr = FALSE;
4699
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004700 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004701 if (argvars[1].v_type == VAR_UNKNOWN)
4702 mode = (char_u *)"nvo";
4703 else
4704 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004705 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004706 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004707 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004708 }
4709
4710 if (map_to_exists(name, mode, abbr))
4711 rettv->vval.v_number = TRUE;
4712 else
4713 rettv->vval.v_number = FALSE;
4714}
4715
4716/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004717 * "highlightID(name)" function
4718 */
4719 static void
4720f_hlID(typval_T *argvars, typval_T *rettv)
4721{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004722 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004723}
4724
4725/*
4726 * "highlight_exists()" function
4727 */
4728 static void
4729f_hlexists(typval_T *argvars, typval_T *rettv)
4730{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004731 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004732}
4733
4734/*
4735 * "hostname()" function
4736 */
4737 static void
4738f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4739{
4740 char_u hostname[256];
4741
4742 mch_get_host_name(hostname, 256);
4743 rettv->v_type = VAR_STRING;
4744 rettv->vval.v_string = vim_strsave(hostname);
4745}
4746
4747/*
4748 * iconv() function
4749 */
4750 static void
4751f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4752{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004753 char_u buf1[NUMBUFLEN];
4754 char_u buf2[NUMBUFLEN];
4755 char_u *from, *to, *str;
4756 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004757
4758 rettv->v_type = VAR_STRING;
4759 rettv->vval.v_string = NULL;
4760
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004761 str = tv_get_string(&argvars[0]);
4762 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4763 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004764 vimconv.vc_type = CONV_NONE;
4765 convert_setup(&vimconv, from, to);
4766
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004767 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768 if (vimconv.vc_type == CONV_NONE)
4769 rettv->vval.v_string = vim_strsave(str);
4770 else
4771 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4772
4773 convert_setup(&vimconv, NULL, NULL);
4774 vim_free(from);
4775 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004776}
4777
4778/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004779 * "index()" function
4780 */
4781 static void
4782f_index(typval_T *argvars, typval_T *rettv)
4783{
4784 list_T *l;
4785 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004786 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004787 long idx = 0;
4788 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004789 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004790
4791 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004792 if (argvars[0].v_type == VAR_BLOB)
4793 {
4794 typval_T tv;
4795 int start = 0;
4796
4797 if (argvars[2].v_type != VAR_UNKNOWN)
4798 {
4799 start = tv_get_number_chk(&argvars[2], &error);
4800 if (error)
4801 return;
4802 }
4803 b = argvars[0].vval.v_blob;
4804 if (b == NULL)
4805 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004806 if (start < 0)
4807 {
4808 start = blob_len(b) + start;
4809 if (start < 0)
4810 start = 0;
4811 }
4812
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004813 for (idx = start; idx < blob_len(b); ++idx)
4814 {
4815 tv.v_type = VAR_NUMBER;
4816 tv.vval.v_number = blob_get(b, idx);
4817 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4818 {
4819 rettv->vval.v_number = idx;
4820 return;
4821 }
4822 }
4823 return;
4824 }
4825 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004826 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004827 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828 return;
4829 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004830
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004831 l = argvars[0].vval.v_list;
4832 if (l != NULL)
4833 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004834 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004835 item = l->lv_first;
4836 if (argvars[2].v_type != VAR_UNKNOWN)
4837 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004838 // Start at specified item. Use the cached index that list_find()
4839 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004840 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004841 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004842 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004843 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004844 if (error)
4845 item = NULL;
4846 }
4847
4848 for ( ; item != NULL; item = item->li_next, ++idx)
4849 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4850 {
4851 rettv->vval.v_number = idx;
4852 break;
4853 }
4854 }
4855}
4856
4857static int inputsecret_flag = 0;
4858
4859/*
4860 * "input()" function
4861 * Also handles inputsecret() when inputsecret is set.
4862 */
4863 static void
4864f_input(typval_T *argvars, typval_T *rettv)
4865{
4866 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4867}
4868
4869/*
4870 * "inputdialog()" function
4871 */
4872 static void
4873f_inputdialog(typval_T *argvars, typval_T *rettv)
4874{
4875#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004876 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004877 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4878 {
4879 char_u *message;
4880 char_u buf[NUMBUFLEN];
4881 char_u *defstr = (char_u *)"";
4882
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004883 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004884 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004885 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004886 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4887 else
4888 IObuff[0] = NUL;
4889 if (message != NULL && defstr != NULL
4890 && do_dialog(VIM_QUESTION, NULL, message,
4891 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4892 rettv->vval.v_string = vim_strsave(IObuff);
4893 else
4894 {
4895 if (message != NULL && defstr != NULL
4896 && argvars[1].v_type != VAR_UNKNOWN
4897 && argvars[2].v_type != VAR_UNKNOWN)
4898 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004899 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004900 else
4901 rettv->vval.v_string = NULL;
4902 }
4903 rettv->v_type = VAR_STRING;
4904 }
4905 else
4906#endif
4907 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4908}
4909
4910/*
4911 * "inputlist()" function
4912 */
4913 static void
4914f_inputlist(typval_T *argvars, typval_T *rettv)
4915{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004916 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917 listitem_T *li;
4918 int selected;
4919 int mouse_used;
4920
4921#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004922 // While starting up, there is no place to enter text. When running tests
4923 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004924 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004925 return;
4926#endif
4927 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4928 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004929 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930 return;
4931 }
4932
4933 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004934 msg_row = Rows - 1; // for when 'cmdheight' > 1
4935 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004936 msg_scroll = TRUE;
4937 msg_clr_eos();
4938
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004939 l = argvars[0].vval.v_list;
4940 range_list_materialize(l);
4941 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004943 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004944 msg_putchar('\n');
4945 }
4946
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004947 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004948 selected = prompt_for_number(&mouse_used);
4949 if (mouse_used)
4950 selected -= lines_left;
4951
4952 rettv->vval.v_number = selected;
4953}
4954
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4956
4957/*
4958 * "inputrestore()" function
4959 */
4960 static void
4961f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4962{
4963 if (ga_userinput.ga_len > 0)
4964 {
4965 --ga_userinput.ga_len;
4966 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4967 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004968 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004969 }
4970 else if (p_verbose > 1)
4971 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004972 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004973 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004974 }
4975}
4976
4977/*
4978 * "inputsave()" function
4979 */
4980 static void
4981f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4982{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004983 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004984 if (ga_grow(&ga_userinput, 1) == OK)
4985 {
4986 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4987 + ga_userinput.ga_len);
4988 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004989 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004990 }
4991 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004992 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004993}
4994
4995/*
4996 * "inputsecret()" function
4997 */
4998 static void
4999f_inputsecret(typval_T *argvars, typval_T *rettv)
5000{
5001 ++cmdline_star;
5002 ++inputsecret_flag;
5003 f_input(argvars, rettv);
5004 --cmdline_star;
5005 --inputsecret_flag;
5006}
5007
5008/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01005009 * "interrupt()" function
5010 */
5011 static void
5012f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5013{
5014 got_int = TRUE;
5015}
5016
5017/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005018 * "invert(expr)" function
5019 */
5020 static void
5021f_invert(typval_T *argvars, typval_T *rettv)
5022{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005023 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005024}
5025
5026/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005027 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
5028 * or it refers to a List or Dictionary that is locked.
5029 */
5030 static int
5031tv_islocked(typval_T *tv)
5032{
5033 return (tv->v_lock & VAR_LOCKED)
5034 || (tv->v_type == VAR_LIST
5035 && tv->vval.v_list != NULL
5036 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
5037 || (tv->v_type == VAR_DICT
5038 && tv->vval.v_dict != NULL
5039 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
5040}
5041
5042/*
5043 * "islocked()" function
5044 */
5045 static void
5046f_islocked(typval_T *argvars, typval_T *rettv)
5047{
5048 lval_T lv;
5049 char_u *end;
5050 dictitem_T *di;
5051
5052 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005053 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005054 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005055 if (end != NULL && lv.ll_name != NULL)
5056 {
5057 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005058 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005059 else
5060 {
5061 if (lv.ll_tv == NULL)
5062 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005063 di = find_var(lv.ll_name, NULL, TRUE);
5064 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005065 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005066 // Consider a variable locked when:
5067 // 1. the variable itself is locked
5068 // 2. the value of the variable is locked.
5069 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01005070 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5071 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005072 }
5073 }
5074 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005075 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005076 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005077 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005078 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005079 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005080 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5081 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005082 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005083 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5084 }
5085 }
5086
5087 clear_lval(&lv);
5088}
5089
5090#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5091/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005092 * "isinf()" function
5093 */
5094 static void
5095f_isinf(typval_T *argvars, typval_T *rettv)
5096{
5097 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5098 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5099}
5100
5101/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005102 * "isnan()" function
5103 */
5104 static void
5105f_isnan(typval_T *argvars, typval_T *rettv)
5106{
5107 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5108 && isnan(argvars[0].vval.v_float);
5109}
5110#endif
5111
5112/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005113 * "last_buffer_nr()" function.
5114 */
5115 static void
5116f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5117{
5118 int n = 0;
5119 buf_T *buf;
5120
Bram Moolenaar29323592016-07-24 22:04:11 +02005121 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005122 if (n < buf->b_fnum)
5123 n = buf->b_fnum;
5124
5125 rettv->vval.v_number = n;
5126}
5127
5128/*
5129 * "len()" function
5130 */
5131 static void
5132f_len(typval_T *argvars, typval_T *rettv)
5133{
5134 switch (argvars[0].v_type)
5135 {
5136 case VAR_STRING:
5137 case VAR_NUMBER:
5138 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005139 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005140 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005141 case VAR_BLOB:
5142 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5143 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005144 case VAR_LIST:
5145 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5146 break;
5147 case VAR_DICT:
5148 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5149 break;
5150 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005151 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01005152 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005153 case VAR_SPECIAL:
5154 case VAR_FLOAT:
5155 case VAR_FUNC:
5156 case VAR_PARTIAL:
5157 case VAR_JOB:
5158 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005159 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005160 break;
5161 }
5162}
5163
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005164 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005165libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005166{
5167#ifdef FEAT_LIBCALL
5168 char_u *string_in;
5169 char_u **string_result;
5170 int nr_result;
5171#endif
5172
5173 rettv->v_type = type;
5174 if (type != VAR_NUMBER)
5175 rettv->vval.v_string = NULL;
5176
5177 if (check_restricted() || check_secure())
5178 return;
5179
5180#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005181 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005182 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5183 {
5184 string_in = NULL;
5185 if (argvars[2].v_type == VAR_STRING)
5186 string_in = argvars[2].vval.v_string;
5187 if (type == VAR_NUMBER)
5188 string_result = NULL;
5189 else
5190 string_result = &rettv->vval.v_string;
5191 if (mch_libcall(argvars[0].vval.v_string,
5192 argvars[1].vval.v_string,
5193 string_in,
5194 argvars[2].vval.v_number,
5195 string_result,
5196 &nr_result) == OK
5197 && type == VAR_NUMBER)
5198 rettv->vval.v_number = nr_result;
5199 }
5200#endif
5201}
5202
5203/*
5204 * "libcall()" function
5205 */
5206 static void
5207f_libcall(typval_T *argvars, typval_T *rettv)
5208{
5209 libcall_common(argvars, rettv, VAR_STRING);
5210}
5211
5212/*
5213 * "libcallnr()" function
5214 */
5215 static void
5216f_libcallnr(typval_T *argvars, typval_T *rettv)
5217{
5218 libcall_common(argvars, rettv, VAR_NUMBER);
5219}
5220
5221/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005222 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005223 */
5224 static void
5225f_line(typval_T *argvars, typval_T *rettv)
5226{
5227 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005228 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005229 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005230 int id;
5231 tabpage_T *tp;
5232 win_T *wp;
5233 win_T *save_curwin;
5234 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005235
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005236 if (argvars[1].v_type != VAR_UNKNOWN)
5237 {
5238 // use window specified in the second argument
5239 id = (int)tv_get_number(&argvars[1]);
5240 wp = win_id2wp_tp(id, &tp);
5241 if (wp != NULL && tp != NULL)
5242 {
5243 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5244 == OK)
5245 {
5246 check_cursor();
5247 fp = var2fpos(&argvars[0], TRUE, &fnum);
5248 }
5249 restore_win_noblock(save_curwin, save_curtab, TRUE);
5250 }
5251 }
5252 else
5253 // use current window
5254 fp = var2fpos(&argvars[0], TRUE, &fnum);
5255
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005256 if (fp != NULL)
5257 lnum = fp->lnum;
5258 rettv->vval.v_number = lnum;
5259}
5260
5261/*
5262 * "line2byte(lnum)" function
5263 */
5264 static void
5265f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5266{
5267#ifndef FEAT_BYTEOFF
5268 rettv->vval.v_number = -1;
5269#else
5270 linenr_T lnum;
5271
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005272 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005273 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5274 rettv->vval.v_number = -1;
5275 else
5276 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5277 if (rettv->vval.v_number >= 0)
5278 ++rettv->vval.v_number;
5279#endif
5280}
5281
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005282#ifdef FEAT_FLOAT
5283/*
5284 * "log()" function
5285 */
5286 static void
5287f_log(typval_T *argvars, typval_T *rettv)
5288{
5289 float_T f = 0.0;
5290
5291 rettv->v_type = VAR_FLOAT;
5292 if (get_float_arg(argvars, &f) == OK)
5293 rettv->vval.v_float = log(f);
5294 else
5295 rettv->vval.v_float = 0.0;
5296}
5297
5298/*
5299 * "log10()" function
5300 */
5301 static void
5302f_log10(typval_T *argvars, typval_T *rettv)
5303{
5304 float_T f = 0.0;
5305
5306 rettv->v_type = VAR_FLOAT;
5307 if (get_float_arg(argvars, &f) == OK)
5308 rettv->vval.v_float = log10(f);
5309 else
5310 rettv->vval.v_float = 0.0;
5311}
5312#endif
5313
5314#ifdef FEAT_LUA
5315/*
5316 * "luaeval()" function
5317 */
5318 static void
5319f_luaeval(typval_T *argvars, typval_T *rettv)
5320{
5321 char_u *str;
5322 char_u buf[NUMBUFLEN];
5323
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005324 if (check_restricted() || check_secure())
5325 return;
5326
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005327 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005328 do_luaeval(str, argvars + 1, rettv);
5329}
5330#endif
5331
5332/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005333 * "maparg()" function
5334 */
5335 static void
5336f_maparg(typval_T *argvars, typval_T *rettv)
5337{
5338 get_maparg(argvars, rettv, TRUE);
5339}
5340
5341/*
5342 * "mapcheck()" function
5343 */
5344 static void
5345f_mapcheck(typval_T *argvars, typval_T *rettv)
5346{
5347 get_maparg(argvars, rettv, FALSE);
5348}
5349
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005350typedef enum
5351{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005352 MATCH_END, // matchend()
5353 MATCH_MATCH, // match()
5354 MATCH_STR, // matchstr()
5355 MATCH_LIST, // matchlist()
5356 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005357} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005358
5359 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005360find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005361{
5362 char_u *str = NULL;
5363 long len = 0;
5364 char_u *expr = NULL;
5365 char_u *pat;
5366 regmatch_T regmatch;
5367 char_u patbuf[NUMBUFLEN];
5368 char_u strbuf[NUMBUFLEN];
5369 char_u *save_cpo;
5370 long start = 0;
5371 long nth = 1;
5372 colnr_T startcol = 0;
5373 int match = 0;
5374 list_T *l = NULL;
5375 listitem_T *li = NULL;
5376 long idx = 0;
5377 char_u *tofree = NULL;
5378
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005379 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005380 save_cpo = p_cpo;
5381 p_cpo = (char_u *)"";
5382
5383 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005384 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005385 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005386 // type MATCH_LIST: return empty list when there are no matches.
5387 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005388 if (rettv_list_alloc(rettv) == FAIL)
5389 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005390 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005391 && (list_append_string(rettv->vval.v_list,
5392 (char_u *)"", 0) == FAIL
5393 || list_append_number(rettv->vval.v_list,
5394 (varnumber_T)-1) == FAIL
5395 || list_append_number(rettv->vval.v_list,
5396 (varnumber_T)-1) == FAIL
5397 || list_append_number(rettv->vval.v_list,
5398 (varnumber_T)-1) == FAIL))
5399 {
5400 list_free(rettv->vval.v_list);
5401 rettv->vval.v_list = NULL;
5402 goto theend;
5403 }
5404 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005405 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005406 {
5407 rettv->v_type = VAR_STRING;
5408 rettv->vval.v_string = NULL;
5409 }
5410
5411 if (argvars[0].v_type == VAR_LIST)
5412 {
5413 if ((l = argvars[0].vval.v_list) == NULL)
5414 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005415 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005416 li = l->lv_first;
5417 }
5418 else
5419 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005420 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005421 len = (long)STRLEN(str);
5422 }
5423
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005424 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005425 if (pat == NULL)
5426 goto theend;
5427
5428 if (argvars[2].v_type != VAR_UNKNOWN)
5429 {
5430 int error = FALSE;
5431
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005432 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005433 if (error)
5434 goto theend;
5435 if (l != NULL)
5436 {
5437 li = list_find(l, start);
5438 if (li == NULL)
5439 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005440 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005441 }
5442 else
5443 {
5444 if (start < 0)
5445 start = 0;
5446 if (start > len)
5447 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005448 // When "count" argument is there ignore matches before "start",
5449 // otherwise skip part of the string. Differs when pattern is "^"
5450 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005451 if (argvars[3].v_type != VAR_UNKNOWN)
5452 startcol = start;
5453 else
5454 {
5455 str += start;
5456 len -= start;
5457 }
5458 }
5459
5460 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005461 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005462 if (error)
5463 goto theend;
5464 }
5465
5466 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5467 if (regmatch.regprog != NULL)
5468 {
5469 regmatch.rm_ic = p_ic;
5470
5471 for (;;)
5472 {
5473 if (l != NULL)
5474 {
5475 if (li == NULL)
5476 {
5477 match = FALSE;
5478 break;
5479 }
5480 vim_free(tofree);
5481 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5482 if (str == NULL)
5483 break;
5484 }
5485
5486 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5487
5488 if (match && --nth <= 0)
5489 break;
5490 if (l == NULL && !match)
5491 break;
5492
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005493 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005494 if (l != NULL)
5495 {
5496 li = li->li_next;
5497 ++idx;
5498 }
5499 else
5500 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005501 startcol = (colnr_T)(regmatch.startp[0]
5502 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005503 if (startcol > (colnr_T)len
5504 || str + startcol <= regmatch.startp[0])
5505 {
5506 match = FALSE;
5507 break;
5508 }
5509 }
5510 }
5511
5512 if (match)
5513 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005514 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005515 {
5516 listitem_T *li1 = rettv->vval.v_list->lv_first;
5517 listitem_T *li2 = li1->li_next;
5518 listitem_T *li3 = li2->li_next;
5519 listitem_T *li4 = li3->li_next;
5520
5521 vim_free(li1->li_tv.vval.v_string);
5522 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
5523 (int)(regmatch.endp[0] - regmatch.startp[0]));
5524 li3->li_tv.vval.v_number =
5525 (varnumber_T)(regmatch.startp[0] - expr);
5526 li4->li_tv.vval.v_number =
5527 (varnumber_T)(regmatch.endp[0] - expr);
5528 if (l != NULL)
5529 li2->li_tv.vval.v_number = (varnumber_T)idx;
5530 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005531 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005532 {
5533 int i;
5534
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005535 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005536 for (i = 0; i < NSUBEXP; ++i)
5537 {
5538 if (regmatch.endp[i] == NULL)
5539 {
5540 if (list_append_string(rettv->vval.v_list,
5541 (char_u *)"", 0) == FAIL)
5542 break;
5543 }
5544 else if (list_append_string(rettv->vval.v_list,
5545 regmatch.startp[i],
5546 (int)(regmatch.endp[i] - regmatch.startp[i]))
5547 == FAIL)
5548 break;
5549 }
5550 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005551 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005552 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005553 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005554 if (l != NULL)
5555 copy_tv(&li->li_tv, rettv);
5556 else
5557 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
5558 (int)(regmatch.endp[0] - regmatch.startp[0]));
5559 }
5560 else if (l != NULL)
5561 rettv->vval.v_number = idx;
5562 else
5563 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005564 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005565 rettv->vval.v_number =
5566 (varnumber_T)(regmatch.startp[0] - str);
5567 else
5568 rettv->vval.v_number =
5569 (varnumber_T)(regmatch.endp[0] - str);
5570 rettv->vval.v_number += (varnumber_T)(str - expr);
5571 }
5572 }
5573 vim_regfree(regmatch.regprog);
5574 }
5575
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005576theend:
5577 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005578 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005579 listitem_remove(rettv->vval.v_list,
5580 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005581 vim_free(tofree);
5582 p_cpo = save_cpo;
5583}
5584
5585/*
5586 * "match()" function
5587 */
5588 static void
5589f_match(typval_T *argvars, typval_T *rettv)
5590{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005591 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005592}
5593
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005594/*
5595 * "matchend()" function
5596 */
5597 static void
5598f_matchend(typval_T *argvars, typval_T *rettv)
5599{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005600 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005601}
5602
5603/*
5604 * "matchlist()" function
5605 */
5606 static void
5607f_matchlist(typval_T *argvars, typval_T *rettv)
5608{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005609 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005610}
5611
5612/*
5613 * "matchstr()" function
5614 */
5615 static void
5616f_matchstr(typval_T *argvars, typval_T *rettv)
5617{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005618 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005619}
5620
5621/*
5622 * "matchstrpos()" function
5623 */
5624 static void
5625f_matchstrpos(typval_T *argvars, typval_T *rettv)
5626{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005627 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005628}
5629
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005630 static void
5631max_min(typval_T *argvars, typval_T *rettv, int domax)
5632{
5633 varnumber_T n = 0;
5634 varnumber_T i;
5635 int error = FALSE;
5636
5637 if (argvars[0].v_type == VAR_LIST)
5638 {
5639 list_T *l;
5640 listitem_T *li;
5641
5642 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005643 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005644 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005645 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005646 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005647 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
5648 n = l->lv_u.nonmat.lv_start;
5649 else
5650 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
5651 * l->lv_u.nonmat.lv_stride;
5652 }
5653 else
5654 {
5655 li = l->lv_first;
5656 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005657 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01005658 n = tv_get_number_chk(&li->li_tv, &error);
5659 for (;;)
5660 {
5661 li = li->li_next;
5662 if (li == NULL)
5663 break;
5664 i = tv_get_number_chk(&li->li_tv, &error);
5665 if (domax ? i > n : i < n)
5666 n = i;
5667 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005668 }
5669 }
5670 }
5671 }
5672 else if (argvars[0].v_type == VAR_DICT)
5673 {
5674 dict_T *d;
5675 int first = TRUE;
5676 hashitem_T *hi;
5677 int todo;
5678
5679 d = argvars[0].vval.v_dict;
5680 if (d != NULL)
5681 {
5682 todo = (int)d->dv_hashtab.ht_used;
5683 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5684 {
5685 if (!HASHITEM_EMPTY(hi))
5686 {
5687 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005688 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005689 if (first)
5690 {
5691 n = i;
5692 first = FALSE;
5693 }
5694 else if (domax ? i > n : i < n)
5695 n = i;
5696 }
5697 }
5698 }
5699 }
5700 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005701 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005702 rettv->vval.v_number = error ? 0 : n;
5703}
5704
5705/*
5706 * "max()" function
5707 */
5708 static void
5709f_max(typval_T *argvars, typval_T *rettv)
5710{
5711 max_min(argvars, rettv, TRUE);
5712}
5713
5714/*
5715 * "min()" function
5716 */
5717 static void
5718f_min(typval_T *argvars, typval_T *rettv)
5719{
5720 max_min(argvars, rettv, FALSE);
5721}
5722
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005723#if defined(FEAT_MZSCHEME) || defined(PROTO)
5724/*
5725 * "mzeval()" function
5726 */
5727 static void
5728f_mzeval(typval_T *argvars, typval_T *rettv)
5729{
5730 char_u *str;
5731 char_u buf[NUMBUFLEN];
5732
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005733 if (check_restricted() || check_secure())
5734 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005735 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005736 do_mzeval(str, rettv);
5737}
5738
5739 void
5740mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5741{
5742 typval_T argvars[3];
5743
5744 argvars[0].v_type = VAR_STRING;
5745 argvars[0].vval.v_string = name;
5746 copy_tv(args, &argvars[1]);
5747 argvars[2].v_type = VAR_UNKNOWN;
5748 f_call(argvars, rettv);
5749 clear_tv(&argvars[1]);
5750}
5751#endif
5752
5753/*
5754 * "nextnonblank()" function
5755 */
5756 static void
5757f_nextnonblank(typval_T *argvars, typval_T *rettv)
5758{
5759 linenr_T lnum;
5760
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005761 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005762 {
5763 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5764 {
5765 lnum = 0;
5766 break;
5767 }
5768 if (*skipwhite(ml_get(lnum)) != NUL)
5769 break;
5770 }
5771 rettv->vval.v_number = lnum;
5772}
5773
5774/*
5775 * "nr2char()" function
5776 */
5777 static void
5778f_nr2char(typval_T *argvars, typval_T *rettv)
5779{
5780 char_u buf[NUMBUFLEN];
5781
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005782 if (has_mbyte)
5783 {
5784 int utf8 = 0;
5785
5786 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005787 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005788 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005789 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005790 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005791 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005792 }
5793 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005794 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005795 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005796 buf[1] = NUL;
5797 }
5798 rettv->v_type = VAR_STRING;
5799 rettv->vval.v_string = vim_strsave(buf);
5800}
5801
5802/*
5803 * "or(expr, expr)" function
5804 */
5805 static void
5806f_or(typval_T *argvars, typval_T *rettv)
5807{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005808 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5809 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005810}
5811
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005812#ifdef FEAT_PERL
5813/*
5814 * "perleval()" function
5815 */
5816 static void
5817f_perleval(typval_T *argvars, typval_T *rettv)
5818{
5819 char_u *str;
5820 char_u buf[NUMBUFLEN];
5821
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005822 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005823 do_perleval(str, rettv);
5824}
5825#endif
5826
5827#ifdef FEAT_FLOAT
5828/*
5829 * "pow()" function
5830 */
5831 static void
5832f_pow(typval_T *argvars, typval_T *rettv)
5833{
5834 float_T fx = 0.0, fy = 0.0;
5835
5836 rettv->v_type = VAR_FLOAT;
5837 if (get_float_arg(argvars, &fx) == OK
5838 && get_float_arg(&argvars[1], &fy) == OK)
5839 rettv->vval.v_float = pow(fx, fy);
5840 else
5841 rettv->vval.v_float = 0.0;
5842}
5843#endif
5844
5845/*
5846 * "prevnonblank()" function
5847 */
5848 static void
5849f_prevnonblank(typval_T *argvars, typval_T *rettv)
5850{
5851 linenr_T lnum;
5852
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005853 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005854 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5855 lnum = 0;
5856 else
5857 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5858 --lnum;
5859 rettv->vval.v_number = lnum;
5860}
5861
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005862// This dummy va_list is here because:
5863// - passing a NULL pointer doesn't work when va_list isn't a pointer
5864// - locally in the function results in a "used before set" warning
5865// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005866static va_list ap;
5867
5868/*
5869 * "printf()" function
5870 */
5871 static void
5872f_printf(typval_T *argvars, typval_T *rettv)
5873{
5874 char_u buf[NUMBUFLEN];
5875 int len;
5876 char_u *s;
5877 int saved_did_emsg = did_emsg;
5878 char *fmt;
5879
5880 rettv->v_type = VAR_STRING;
5881 rettv->vval.v_string = NULL;
5882
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005883 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005884 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005885 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005886 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005887 if (!did_emsg)
5888 {
5889 s = alloc(len + 1);
5890 if (s != NULL)
5891 {
5892 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005893 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5894 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005895 }
5896 }
5897 did_emsg |= saved_did_emsg;
5898}
5899
5900/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005901 * "pum_getpos()" function
5902 */
5903 static void
5904f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5905{
5906 if (rettv_dict_alloc(rettv) != OK)
5907 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005908 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005909}
5910
5911/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005912 * "pumvisible()" function
5913 */
5914 static void
5915f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5916{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005917 if (pum_visible())
5918 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005919}
5920
5921#ifdef FEAT_PYTHON3
5922/*
5923 * "py3eval()" function
5924 */
5925 static void
5926f_py3eval(typval_T *argvars, typval_T *rettv)
5927{
5928 char_u *str;
5929 char_u buf[NUMBUFLEN];
5930
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005931 if (check_restricted() || check_secure())
5932 return;
5933
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005934 if (p_pyx == 0)
5935 p_pyx = 3;
5936
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005937 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005938 do_py3eval(str, rettv);
5939}
5940#endif
5941
5942#ifdef FEAT_PYTHON
5943/*
5944 * "pyeval()" function
5945 */
5946 static void
5947f_pyeval(typval_T *argvars, typval_T *rettv)
5948{
5949 char_u *str;
5950 char_u buf[NUMBUFLEN];
5951
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005952 if (check_restricted() || check_secure())
5953 return;
5954
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005955 if (p_pyx == 0)
5956 p_pyx = 2;
5957
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005958 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005959 do_pyeval(str, rettv);
5960}
5961#endif
5962
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005963#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5964/*
5965 * "pyxeval()" function
5966 */
5967 static void
5968f_pyxeval(typval_T *argvars, typval_T *rettv)
5969{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005970 if (check_restricted() || check_secure())
5971 return;
5972
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005973# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5974 init_pyxversion();
5975 if (p_pyx == 2)
5976 f_pyeval(argvars, rettv);
5977 else
5978 f_py3eval(argvars, rettv);
5979# elif defined(FEAT_PYTHON)
5980 f_pyeval(argvars, rettv);
5981# elif defined(FEAT_PYTHON3)
5982 f_py3eval(argvars, rettv);
5983# endif
5984}
5985#endif
5986
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005987static UINT32_T srand_seed_for_testing = 0;
5988static int srand_seed_for_testing_is_used = FALSE;
5989
5990 static void
5991f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5992{
5993 if (argvars[0].v_type == VAR_UNKNOWN)
5994 srand_seed_for_testing_is_used = FALSE;
5995 else
5996 {
5997 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5998 srand_seed_for_testing_is_used = TRUE;
5999 }
6000}
6001
6002 static void
6003init_srand(UINT32_T *x)
6004{
6005#ifndef MSWIN
6006 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
6007#endif
6008
6009 if (srand_seed_for_testing_is_used)
6010 {
6011 *x = srand_seed_for_testing;
6012 return;
6013 }
6014#ifndef MSWIN
6015 if (dev_urandom_state != FAIL)
6016 {
6017 int fd = open("/dev/urandom", O_RDONLY);
6018 struct {
6019 union {
6020 UINT32_T number;
6021 char bytes[sizeof(UINT32_T)];
6022 } contents;
6023 } buf;
6024
6025 // Attempt reading /dev/urandom.
6026 if (fd == -1)
6027 dev_urandom_state = FAIL;
6028 else
6029 {
6030 buf.contents.number = 0;
6031 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
6032 != sizeof(UINT32_T))
6033 dev_urandom_state = FAIL;
6034 else
6035 {
6036 dev_urandom_state = OK;
6037 *x = buf.contents.number;
6038 }
6039 close(fd);
6040 }
6041 }
6042 if (dev_urandom_state != OK)
6043 // Reading /dev/urandom doesn't work, fall back to time().
6044#endif
6045 *x = vim_time();
6046}
6047
6048#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
6049#define SPLITMIX32(x, z) ( \
6050 z = (x += 0x9e3779b9), \
6051 z = (z ^ (z >> 16)) * 0x85ebca6b, \
6052 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
6053 z ^ (z >> 16) \
6054 )
6055#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
6056 result = ROTL(y * 5, 7) * 9; \
6057 t = y << 9; \
6058 z ^= x; \
6059 w ^= y; \
6060 y ^= z, x ^= w; \
6061 z ^= t; \
6062 w = ROTL(w, 11);
6063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006064/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006065 * "rand()" function
6066 */
6067 static void
6068f_rand(typval_T *argvars, typval_T *rettv)
6069{
6070 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006071 static UINT32_T gx, gy, gz, gw;
6072 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006073 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006074 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006075
6076 if (argvars[0].v_type == VAR_UNKNOWN)
6077 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006078 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006079 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006080 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006081 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006082 init_srand(&x);
6083
6084 gx = SPLITMIX32(x, z);
6085 gy = SPLITMIX32(x, z);
6086 gz = SPLITMIX32(x, z);
6087 gw = SPLITMIX32(x, z);
6088 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006089 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006090
6091 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006092 }
6093 else if (argvars[0].v_type == VAR_LIST)
6094 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006095 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006096 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006097 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006098
6099 lx = list_find(l, 0L);
6100 ly = list_find(l, 1L);
6101 lz = list_find(l, 2L);
6102 lw = list_find(l, 3L);
6103 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
6104 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
6105 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
6106 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
6107 x = (UINT32_T)lx->li_tv.vval.v_number;
6108 y = (UINT32_T)ly->li_tv.vval.v_number;
6109 z = (UINT32_T)lz->li_tv.vval.v_number;
6110 w = (UINT32_T)lw->li_tv.vval.v_number;
6111
6112 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
6113
6114 lx->li_tv.vval.v_number = (varnumber_T)x;
6115 ly->li_tv.vval.v_number = (varnumber_T)y;
6116 lz->li_tv.vval.v_number = (varnumber_T)z;
6117 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006118 }
6119 else
6120 goto theend;
6121
6122 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006123 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006124 return;
6125
6126theend:
6127 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01006128 rettv->v_type = VAR_NUMBER;
6129 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01006130}
6131
6132/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01006133 * "srand()" function
6134 */
6135 static void
6136f_srand(typval_T *argvars, typval_T *rettv)
6137{
6138 UINT32_T x = 0, z;
6139
6140 if (rettv_list_alloc(rettv) == FAIL)
6141 return;
6142 if (argvars[0].v_type == VAR_UNKNOWN)
6143 {
6144 init_srand(&x);
6145 }
6146 else
6147 {
6148 int error = FALSE;
6149
6150 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
6151 if (error)
6152 return;
6153 }
6154
6155 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6156 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6157 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6158 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
6159}
6160
6161#undef ROTL
6162#undef SPLITMIX32
6163#undef SHUFFLE_XOSHIRO128STARSTAR
6164
6165/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006166 * "range()" function
6167 */
6168 static void
6169f_range(typval_T *argvars, typval_T *rettv)
6170{
6171 varnumber_T start;
6172 varnumber_T end;
6173 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006174 int error = FALSE;
6175
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006176 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006177 if (argvars[1].v_type == VAR_UNKNOWN)
6178 {
6179 end = start - 1;
6180 start = 0;
6181 }
6182 else
6183 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006184 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006186 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006187 }
6188
6189 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006190 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006191 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006192 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006193 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006194 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006195 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006197 list_T *list = rettv->vval.v_list;
6198
6199 // Create a non-materialized list. This is much more efficient and
6200 // works with ":for". If used otherwise range_list_materialize() must
6201 // be called.
6202 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006203 list->lv_u.nonmat.lv_start = start;
6204 list->lv_u.nonmat.lv_end = end;
6205 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006206 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006207 }
6208}
6209
6210/*
6211 * If "list" is a non-materialized list then materialize it now.
6212 */
6213 void
6214range_list_materialize(list_T *list)
6215{
6216 if (list->lv_first == &range_list_item)
6217 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006218 varnumber_T start = list->lv_u.nonmat.lv_start;
6219 varnumber_T end = list->lv_u.nonmat.lv_end;
6220 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006221 varnumber_T i;
6222
6223 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006224 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006225 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01006226 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01006227 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6228 if (list_append_number(list, (varnumber_T)i) == FAIL)
6229 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006230 }
6231}
6232
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006233 static void
6234return_register(int regname, typval_T *rettv)
6235{
6236 char_u buf[2] = {0, 0};
6237
6238 buf[0] = (char_u)regname;
6239 rettv->v_type = VAR_STRING;
6240 rettv->vval.v_string = vim_strsave(buf);
6241}
6242
6243/*
6244 * "reg_executing()" function
6245 */
6246 static void
6247f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6248{
6249 return_register(reg_executing, rettv);
6250}
6251
6252/*
6253 * "reg_recording()" function
6254 */
6255 static void
6256f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6257{
6258 return_register(reg_recording, rettv);
6259}
6260
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006261#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006262 static void
6263make_connection(void)
6264{
6265 if (X_DISPLAY == NULL
6266# ifdef FEAT_GUI
6267 && !gui.in_use
6268# endif
6269 )
6270 {
6271 x_force_connect = TRUE;
6272 setup_term_clip();
6273 x_force_connect = FALSE;
6274 }
6275}
6276
6277 static int
6278check_connection(void)
6279{
6280 make_connection();
6281 if (X_DISPLAY == NULL)
6282 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006283 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006284 return FAIL;
6285 }
6286 return OK;
6287}
6288#endif
6289
6290#ifdef FEAT_CLIENTSERVER
6291 static void
6292remote_common(typval_T *argvars, typval_T *rettv, int expr)
6293{
6294 char_u *server_name;
6295 char_u *keys;
6296 char_u *r = NULL;
6297 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006298 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006299# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006300 HWND w;
6301# else
6302 Window w;
6303# endif
6304
6305 if (check_restricted() || check_secure())
6306 return;
6307
6308# ifdef FEAT_X11
6309 if (check_connection() == FAIL)
6310 return;
6311# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006312 if (argvars[2].v_type != VAR_UNKNOWN
6313 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006314 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006316 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006317 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006318 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006319 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01006320# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006321 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006322# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006323 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
6324 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325# endif
6326 {
6327 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006328 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006329 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006330 vim_free(r);
6331 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006332 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006333 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006334 return;
6335 }
6336
6337 rettv->vval.v_string = r;
6338
6339 if (argvars[2].v_type != VAR_UNKNOWN)
6340 {
6341 dictitem_T v;
6342 char_u str[30];
6343 char_u *idvar;
6344
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006345 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006346 if (idvar != NULL && *idvar != NUL)
6347 {
6348 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
6349 v.di_tv.v_type = VAR_STRING;
6350 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006352 vim_free(v.di_tv.vval.v_string);
6353 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006354 }
6355}
6356#endif
6357
6358/*
6359 * "remote_expr()" function
6360 */
6361 static void
6362f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
6363{
6364 rettv->v_type = VAR_STRING;
6365 rettv->vval.v_string = NULL;
6366#ifdef FEAT_CLIENTSERVER
6367 remote_common(argvars, rettv, TRUE);
6368#endif
6369}
6370
6371/*
6372 * "remote_foreground()" function
6373 */
6374 static void
6375f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6376{
6377#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006378# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006379 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006380 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006381 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006382
6383 if (server_name != NULL)
6384 serverForeground(server_name);
6385 }
6386# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006387 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006388 argvars[1].v_type = VAR_STRING;
6389 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
6390 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006391 rettv->v_type = VAR_STRING;
6392 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393 remote_common(argvars, rettv, TRUE);
6394 vim_free(argvars[1].vval.v_string);
6395# endif
6396#endif
6397}
6398
6399 static void
6400f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
6401{
6402#ifdef FEAT_CLIENTSERVER
6403 dictitem_T v;
6404 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006405# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406 long_u n = 0;
6407# endif
6408 char_u *serverid;
6409
6410 if (check_restricted() || check_secure())
6411 {
6412 rettv->vval.v_number = -1;
6413 return;
6414 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006415 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 if (serverid == NULL)
6417 {
6418 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006419 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006420 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01006421# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
6423 if (n == 0)
6424 rettv->vval.v_number = -1;
6425 else
6426 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006427 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006428 rettv->vval.v_number = (s != NULL);
6429 }
6430# else
6431 if (check_connection() == FAIL)
6432 return;
6433
6434 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
6435 serverStrToWin(serverid), &s);
6436# endif
6437
6438 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
6439 {
6440 char_u *retvar;
6441
6442 v.di_tv.v_type = VAR_STRING;
6443 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006444 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006445 if (retvar != NULL)
6446 set_var(retvar, &v.di_tv, FALSE);
6447 vim_free(v.di_tv.vval.v_string);
6448 }
6449#else
6450 rettv->vval.v_number = -1;
6451#endif
6452}
6453
6454 static void
6455f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
6456{
6457 char_u *r = NULL;
6458
6459#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006460 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006461
6462 if (serverid != NULL && !check_restricted() && !check_secure())
6463 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006464 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006465# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006466 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01006467 long_u n = 0;
6468# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006469
6470 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006471 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006472
Bram Moolenaar4f974752019-02-17 17:44:42 +01006473# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
6475 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006476 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006477 if (r == NULL)
6478# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006479 if (check_connection() == FAIL
6480 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
6481 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006482# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006483 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 }
6485#endif
6486 rettv->v_type = VAR_STRING;
6487 rettv->vval.v_string = r;
6488}
6489
6490/*
6491 * "remote_send()" function
6492 */
6493 static void
6494f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
6495{
6496 rettv->v_type = VAR_STRING;
6497 rettv->vval.v_string = NULL;
6498#ifdef FEAT_CLIENTSERVER
6499 remote_common(argvars, rettv, FALSE);
6500#endif
6501}
6502
6503/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006504 * "remote_startserver()" function
6505 */
6506 static void
6507f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6508{
6509#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006510 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006511
6512 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006513 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006514 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006515 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006516 else
6517 {
6518# ifdef FEAT_X11
6519 if (check_connection() == OK)
6520 serverRegisterName(X_DISPLAY, server);
6521# else
6522 serverSetName(server);
6523# endif
6524 }
6525#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006526 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006527#endif
6528}
6529
6530/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006531 * "rename({from}, {to})" function
6532 */
6533 static void
6534f_rename(typval_T *argvars, typval_T *rettv)
6535{
6536 char_u buf[NUMBUFLEN];
6537
6538 if (check_restricted() || check_secure())
6539 rettv->vval.v_number = -1;
6540 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006541 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
6542 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006543}
6544
6545/*
6546 * "repeat()" function
6547 */
6548 static void
6549f_repeat(typval_T *argvars, typval_T *rettv)
6550{
6551 char_u *p;
6552 int n;
6553 int slen;
6554 int len;
6555 char_u *r;
6556 int i;
6557
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006558 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006559 if (argvars[0].v_type == VAR_LIST)
6560 {
6561 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
6562 while (n-- > 0)
6563 if (list_extend(rettv->vval.v_list,
6564 argvars[0].vval.v_list, NULL) == FAIL)
6565 break;
6566 }
6567 else
6568 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006569 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 rettv->v_type = VAR_STRING;
6571 rettv->vval.v_string = NULL;
6572
6573 slen = (int)STRLEN(p);
6574 len = slen * n;
6575 if (len <= 0)
6576 return;
6577
6578 r = alloc(len + 1);
6579 if (r != NULL)
6580 {
6581 for (i = 0; i < n; i++)
6582 mch_memmove(r + i * slen, p, (size_t)slen);
6583 r[len] = NUL;
6584 }
6585
6586 rettv->vval.v_string = r;
6587 }
6588}
6589
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006590#define SP_NOMOVE 0x01 // don't move cursor
6591#define SP_REPEAT 0x02 // repeat to find outer pair
6592#define SP_RETCOUNT 0x04 // return matchcount
6593#define SP_SETPCMARK 0x08 // set previous context mark
6594#define SP_START 0x10 // accept match at start position
6595#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
6596#define SP_END 0x40 // leave cursor at end of match
6597#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006598
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006599/*
6600 * Get flags for a search function.
6601 * Possibly sets "p_ws".
6602 * Returns BACKWARD, FORWARD or zero (for an error).
6603 */
6604 static int
6605get_search_arg(typval_T *varp, int *flagsp)
6606{
6607 int dir = FORWARD;
6608 char_u *flags;
6609 char_u nbuf[NUMBUFLEN];
6610 int mask;
6611
6612 if (varp->v_type != VAR_UNKNOWN)
6613 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006614 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006615 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006616 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006617 while (*flags != NUL)
6618 {
6619 switch (*flags)
6620 {
6621 case 'b': dir = BACKWARD; break;
6622 case 'w': p_ws = TRUE; break;
6623 case 'W': p_ws = FALSE; break;
6624 default: mask = 0;
6625 if (flagsp != NULL)
6626 switch (*flags)
6627 {
6628 case 'c': mask = SP_START; break;
6629 case 'e': mask = SP_END; break;
6630 case 'm': mask = SP_RETCOUNT; break;
6631 case 'n': mask = SP_NOMOVE; break;
6632 case 'p': mask = SP_SUBPAT; break;
6633 case 'r': mask = SP_REPEAT; break;
6634 case 's': mask = SP_SETPCMARK; break;
6635 case 'z': mask = SP_COLUMN; break;
6636 }
6637 if (mask == 0)
6638 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006639 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640 dir = 0;
6641 }
6642 else
6643 *flagsp |= mask;
6644 }
6645 if (dir == 0)
6646 break;
6647 ++flags;
6648 }
6649 }
6650 return dir;
6651}
6652
6653/*
6654 * Shared by search() and searchpos() functions.
6655 */
6656 static int
6657search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6658{
6659 int flags;
6660 char_u *pat;
6661 pos_T pos;
6662 pos_T save_cursor;
6663 int save_p_ws = p_ws;
6664 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006665 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006666 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006667#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006668 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006669 long time_limit = 0;
6670#endif
6671 int options = SEARCH_KEEP;
6672 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006673 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006674
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006675 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006676 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006677 if (dir == 0)
6678 goto theend;
6679 flags = *flagsp;
6680 if (flags & SP_START)
6681 options |= SEARCH_START;
6682 if (flags & SP_END)
6683 options |= SEARCH_END;
6684 if (flags & SP_COLUMN)
6685 options |= SEARCH_COL;
6686
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006687 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6689 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006690 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006691 if (lnum_stop < 0)
6692 goto theend;
6693#ifdef FEAT_RELTIME
6694 if (argvars[3].v_type != VAR_UNKNOWN)
6695 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006696 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006697 if (time_limit < 0)
6698 goto theend;
6699 }
6700#endif
6701 }
6702
6703#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006704 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006705 profile_setlimit(time_limit, &tm);
6706#endif
6707
6708 /*
6709 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6710 * Check to make sure only those flags are set.
6711 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6712 * flags cannot be set. Check for that condition also.
6713 */
6714 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6715 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6716 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006717 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006718 goto theend;
6719 }
6720
6721 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006722 vim_memset(&sia, 0, sizeof(sia));
6723 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6724#ifdef FEAT_RELTIME
6725 sia.sa_tm = &tm;
6726#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006727 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006728 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006729 if (subpatnum != FAIL)
6730 {
6731 if (flags & SP_SUBPAT)
6732 retval = subpatnum;
6733 else
6734 retval = pos.lnum;
6735 if (flags & SP_SETPCMARK)
6736 setpcmark();
6737 curwin->w_cursor = pos;
6738 if (match_pos != NULL)
6739 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006740 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741 match_pos->lnum = pos.lnum;
6742 match_pos->col = pos.col + 1;
6743 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006744 // "/$" will put the cursor after the end of the line, may need to
6745 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006746 check_cursor();
6747 }
6748
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006749 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006750 if (flags & SP_NOMOVE)
6751 curwin->w_cursor = save_cursor;
6752 else
6753 curwin->w_set_curswant = TRUE;
6754theend:
6755 p_ws = save_p_ws;
6756
6757 return retval;
6758}
6759
6760#ifdef FEAT_FLOAT
6761
6762/*
6763 * round() is not in C90, use ceil() or floor() instead.
6764 */
6765 float_T
6766vim_round(float_T f)
6767{
6768 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6769}
6770
6771/*
6772 * "round({float})" function
6773 */
6774 static void
6775f_round(typval_T *argvars, typval_T *rettv)
6776{
6777 float_T f = 0.0;
6778
6779 rettv->v_type = VAR_FLOAT;
6780 if (get_float_arg(argvars, &f) == OK)
6781 rettv->vval.v_float = vim_round(f);
6782 else
6783 rettv->vval.v_float = 0.0;
6784}
6785#endif
6786
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006787#ifdef FEAT_RUBY
6788/*
6789 * "rubyeval()" function
6790 */
6791 static void
6792f_rubyeval(typval_T *argvars, typval_T *rettv)
6793{
6794 char_u *str;
6795 char_u buf[NUMBUFLEN];
6796
6797 str = tv_get_string_buf(&argvars[0], buf);
6798 do_rubyeval(str, rettv);
6799}
6800#endif
6801
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802/*
6803 * "screenattr()" function
6804 */
6805 static void
6806f_screenattr(typval_T *argvars, typval_T *rettv)
6807{
6808 int row;
6809 int col;
6810 int c;
6811
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006812 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6813 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006814 if (row < 0 || row >= screen_Rows
6815 || col < 0 || col >= screen_Columns)
6816 c = -1;
6817 else
6818 c = ScreenAttrs[LineOffset[row] + col];
6819 rettv->vval.v_number = c;
6820}
6821
6822/*
6823 * "screenchar()" function
6824 */
6825 static void
6826f_screenchar(typval_T *argvars, typval_T *rettv)
6827{
6828 int row;
6829 int col;
6830 int off;
6831 int c;
6832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006833 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6834 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006835 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836 c = -1;
6837 else
6838 {
6839 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006840 if (enc_utf8 && ScreenLinesUC[off] != 0)
6841 c = ScreenLinesUC[off];
6842 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006843 c = ScreenLines[off];
6844 }
6845 rettv->vval.v_number = c;
6846}
6847
6848/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006849 * "screenchars()" function
6850 */
6851 static void
6852f_screenchars(typval_T *argvars, typval_T *rettv)
6853{
6854 int row;
6855 int col;
6856 int off;
6857 int c;
6858 int i;
6859
6860 if (rettv_list_alloc(rettv) == FAIL)
6861 return;
6862 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6863 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6864 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6865 return;
6866
6867 off = LineOffset[row] + col;
6868 if (enc_utf8 && ScreenLinesUC[off] != 0)
6869 c = ScreenLinesUC[off];
6870 else
6871 c = ScreenLines[off];
6872 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6873
6874 if (enc_utf8)
6875
6876 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6877 list_append_number(rettv->vval.v_list,
6878 (varnumber_T)ScreenLinesC[i][off]);
6879}
6880
6881/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006882 * "screencol()" function
6883 *
6884 * First column is 1 to be consistent with virtcol().
6885 */
6886 static void
6887f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6888{
6889 rettv->vval.v_number = screen_screencol() + 1;
6890}
6891
6892/*
6893 * "screenrow()" function
6894 */
6895 static void
6896f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6897{
6898 rettv->vval.v_number = screen_screenrow() + 1;
6899}
6900
6901/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006902 * "screenstring()" function
6903 */
6904 static void
6905f_screenstring(typval_T *argvars, typval_T *rettv)
6906{
6907 int row;
6908 int col;
6909 int off;
6910 int c;
6911 int i;
6912 char_u buf[MB_MAXBYTES + 1];
6913 int buflen = 0;
6914
6915 rettv->vval.v_string = NULL;
6916 rettv->v_type = VAR_STRING;
6917
6918 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6919 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6920 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6921 return;
6922
6923 off = LineOffset[row] + col;
6924 if (enc_utf8 && ScreenLinesUC[off] != 0)
6925 c = ScreenLinesUC[off];
6926 else
6927 c = ScreenLines[off];
6928 buflen += mb_char2bytes(c, buf);
6929
6930 if (enc_utf8)
6931 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6932 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6933
6934 buf[buflen] = NUL;
6935 rettv->vval.v_string = vim_strsave(buf);
6936}
6937
6938/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006939 * "search()" function
6940 */
6941 static void
6942f_search(typval_T *argvars, typval_T *rettv)
6943{
6944 int flags = 0;
6945
6946 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6947}
6948
6949/*
6950 * "searchdecl()" function
6951 */
6952 static void
6953f_searchdecl(typval_T *argvars, typval_T *rettv)
6954{
6955 int locally = 1;
6956 int thisblock = 0;
6957 int error = FALSE;
6958 char_u *name;
6959
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006960 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006962 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006963 if (argvars[1].v_type != VAR_UNKNOWN)
6964 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006965 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006967 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006968 }
6969 if (!error && name != NULL)
6970 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6971 locally, thisblock, SEARCH_KEEP) == FAIL;
6972}
6973
6974/*
6975 * Used by searchpair() and searchpairpos()
6976 */
6977 static int
6978searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6979{
6980 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006981 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006982 int save_p_ws = p_ws;
6983 int dir;
6984 int flags = 0;
6985 char_u nbuf1[NUMBUFLEN];
6986 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006987 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006988 long lnum_stop = 0;
6989 long time_limit = 0;
6990
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006991 // Get the three pattern arguments: start, middle, end. Will result in an
6992 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006993 spat = tv_get_string_chk(&argvars[0]);
6994 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6995 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006996 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006997 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006998
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006999 // Handle the optional fourth argument: flags
7000 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007001 if (dir == 0)
7002 goto theend;
7003
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007004 // Don't accept SP_END or SP_SUBPAT.
7005 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007006 if ((flags & (SP_END | SP_SUBPAT)) != 0
7007 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7008 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007009 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 goto theend;
7011 }
7012
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007013 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007014 if (flags & SP_REPEAT)
7015 p_ws = FALSE;
7016
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007017 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007018 if (argvars[3].v_type == VAR_UNKNOWN
7019 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01007020 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007021 else
7022 {
Bram Moolenaar48570482017-10-30 21:48:41 +01007023 skip = &argvars[4];
7024 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
7025 && skip->v_type != VAR_STRING)
7026 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007027 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007028 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01007029 goto theend;
7030 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007031 if (argvars[5].v_type != VAR_UNKNOWN)
7032 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007033 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007035 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007036 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007037 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007038 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039#ifdef FEAT_RELTIME
7040 if (argvars[6].v_type != VAR_UNKNOWN)
7041 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007042 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007043 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007044 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007045 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007046 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007047 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007048 }
7049#endif
7050 }
7051 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007052
7053 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
7054 match_pos, lnum_stop, time_limit);
7055
7056theend:
7057 p_ws = save_p_ws;
7058
7059 return retval;
7060}
7061
7062/*
7063 * "searchpair()" function
7064 */
7065 static void
7066f_searchpair(typval_T *argvars, typval_T *rettv)
7067{
7068 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
7069}
7070
7071/*
7072 * "searchpairpos()" function
7073 */
7074 static void
7075f_searchpairpos(typval_T *argvars, typval_T *rettv)
7076{
7077 pos_T match_pos;
7078 int lnum = 0;
7079 int col = 0;
7080
7081 if (rettv_list_alloc(rettv) == FAIL)
7082 return;
7083
7084 if (searchpair_cmn(argvars, &match_pos) > 0)
7085 {
7086 lnum = match_pos.lnum;
7087 col = match_pos.col;
7088 }
7089
7090 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7091 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7092}
7093
7094/*
7095 * Search for a start/middle/end thing.
7096 * Used by searchpair(), see its documentation for the details.
7097 * Returns 0 or -1 for no match,
7098 */
7099 long
7100do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007101 char_u *spat, // start pattern
7102 char_u *mpat, // middle pattern
7103 char_u *epat, // end pattern
7104 int dir, // BACKWARD or FORWARD
7105 typval_T *skip, // skip expression
7106 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007107 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007108 linenr_T lnum_stop, // stop at this line if not zero
7109 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007110{
7111 char_u *save_cpo;
7112 char_u *pat, *pat2 = NULL, *pat3 = NULL;
7113 long retval = 0;
7114 pos_T pos;
7115 pos_T firstpos;
7116 pos_T foundpos;
7117 pos_T save_cursor;
7118 pos_T save_pos;
7119 int n;
7120 int r;
7121 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01007122 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007123 int err;
7124 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007125#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007126 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007127#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007128
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007129 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007130 save_cpo = p_cpo;
7131 p_cpo = empty_option;
7132
7133#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007134 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 profile_setlimit(time_limit, &tm);
7136#endif
7137
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007138 // Make two search patterns: start/end (pat2, for in nested pairs) and
7139 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02007140 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
7141 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142 if (pat2 == NULL || pat3 == NULL)
7143 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007144 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007145 if (*mpat == NUL)
7146 STRCPY(pat3, pat2);
7147 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007148 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007149 spat, epat, mpat);
7150 if (flags & SP_START)
7151 options |= SEARCH_START;
7152
Bram Moolenaar48570482017-10-30 21:48:41 +01007153 if (skip != NULL)
7154 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007155 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01007156 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
7157 use_skip = skip->vval.v_string != NULL
7158 && *skip->vval.v_string != NUL;
7159 }
7160
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007161 save_cursor = curwin->w_cursor;
7162 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007163 CLEAR_POS(&firstpos);
7164 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007165 pat = pat3;
7166 for (;;)
7167 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007168 searchit_arg_T sia;
7169
7170 vim_memset(&sia, 0, sizeof(sia));
7171 sia.sa_stop_lnum = lnum_stop;
7172#ifdef FEAT_RELTIME
7173 sia.sa_tm = &tm;
7174#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007175 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02007176 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007177 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007178 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007179 break;
7180
7181 if (firstpos.lnum == 0)
7182 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007183 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007184 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007185 // Found the same position again. Can happen with a pattern that
7186 // has "\zs" at the end and searching backwards. Advance one
7187 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188 if (dir == BACKWARD)
7189 decl(&pos);
7190 else
7191 incl(&pos);
7192 }
7193 foundpos = pos;
7194
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007195 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007196 options &= ~SEARCH_START;
7197
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007198 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01007199 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007200 {
7201 save_pos = curwin->w_cursor;
7202 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007203 err = FALSE;
7204 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007205 curwin->w_cursor = save_pos;
7206 if (err)
7207 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007208 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007209 curwin->w_cursor = save_cursor;
7210 retval = -1;
7211 break;
7212 }
7213 if (r)
7214 continue;
7215 }
7216
7217 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7218 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007219 // Found end when searching backwards or start when searching
7220 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007221 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007222 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007223 }
7224 else
7225 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007226 // Found end when searching forward or start when searching
7227 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007229 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230 }
7231
7232 if (nest == 0)
7233 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007234 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007235 if (flags & SP_RETCOUNT)
7236 ++retval;
7237 else
7238 retval = pos.lnum;
7239 if (flags & SP_SETPCMARK)
7240 setpcmark();
7241 curwin->w_cursor = pos;
7242 if (!(flags & SP_REPEAT))
7243 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007244 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007245 }
7246 }
7247
7248 if (match_pos != NULL)
7249 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007250 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007251 match_pos->lnum = curwin->w_cursor.lnum;
7252 match_pos->col = curwin->w_cursor.col + 1;
7253 }
7254
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007255 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007256 if ((flags & SP_NOMOVE) || retval == 0)
7257 curwin->w_cursor = save_cursor;
7258
7259theend:
7260 vim_free(pat2);
7261 vim_free(pat3);
7262 if (p_cpo == empty_option)
7263 p_cpo = save_cpo;
7264 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007265 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007266 free_string_option(save_cpo);
7267
7268 return retval;
7269}
7270
7271/*
7272 * "searchpos()" function
7273 */
7274 static void
7275f_searchpos(typval_T *argvars, typval_T *rettv)
7276{
7277 pos_T match_pos;
7278 int lnum = 0;
7279 int col = 0;
7280 int n;
7281 int flags = 0;
7282
7283 if (rettv_list_alloc(rettv) == FAIL)
7284 return;
7285
7286 n = search_cmn(argvars, &match_pos, &flags);
7287 if (n > 0)
7288 {
7289 lnum = match_pos.lnum;
7290 col = match_pos.col;
7291 }
7292
7293 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7294 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7295 if (flags & SP_SUBPAT)
7296 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7297}
7298
7299 static void
7300f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
7301{
7302#ifdef FEAT_CLIENTSERVER
7303 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007304 char_u *server = tv_get_string_chk(&argvars[0]);
7305 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007306
7307 rettv->vval.v_number = -1;
7308 if (server == NULL || reply == NULL)
7309 return;
7310 if (check_restricted() || check_secure())
7311 return;
7312# ifdef FEAT_X11
7313 if (check_connection() == FAIL)
7314 return;
7315# endif
7316
7317 if (serverSendReply(server, reply) < 0)
7318 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007319 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007320 return;
7321 }
7322 rettv->vval.v_number = 0;
7323#else
7324 rettv->vval.v_number = -1;
7325#endif
7326}
7327
7328 static void
7329f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
7330{
7331 char_u *r = NULL;
7332
7333#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01007334# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007335 r = serverGetVimNames();
7336# else
7337 make_connection();
7338 if (X_DISPLAY != NULL)
7339 r = serverGetVimNames(X_DISPLAY);
7340# endif
7341#endif
7342 rettv->v_type = VAR_STRING;
7343 rettv->vval.v_string = r;
7344}
7345
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007346 static void
7347f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7348{
7349 dict_T *d;
7350 dictitem_T *di;
7351 char_u *csearch;
7352
7353 if (argvars[0].v_type != VAR_DICT)
7354 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007355 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356 return;
7357 }
7358
7359 if ((d = argvars[0].vval.v_dict) != NULL)
7360 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007361 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007362 if (csearch != NULL)
7363 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364 if (enc_utf8)
7365 {
7366 int pcc[MAX_MCO];
7367 int c = utfc_ptr2char(csearch, pcc);
7368
7369 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7370 }
7371 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007372 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02007373 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374 }
7375
7376 di = dict_find(d, (char_u *)"forward", -1);
7377 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007378 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007379 ? FORWARD : BACKWARD);
7380
7381 di = dict_find(d, (char_u *)"until", -1);
7382 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007383 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007384 }
7385}
7386
7387/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007388 * "setenv()" function
7389 */
7390 static void
7391f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7392{
7393 char_u namebuf[NUMBUFLEN];
7394 char_u valbuf[NUMBUFLEN];
7395 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7396
7397 if (argvars[1].v_type == VAR_SPECIAL
7398 && argvars[1].vval.v_number == VVAL_NULL)
7399 vim_unsetenv(name);
7400 else
7401 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7402}
7403
7404/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405 * "setfperm({fname}, {mode})" function
7406 */
7407 static void
7408f_setfperm(typval_T *argvars, typval_T *rettv)
7409{
7410 char_u *fname;
7411 char_u modebuf[NUMBUFLEN];
7412 char_u *mode_str;
7413 int i;
7414 int mask;
7415 int mode = 0;
7416
7417 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007418 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007419 if (fname == NULL)
7420 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007421 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007422 if (mode_str == NULL)
7423 return;
7424 if (STRLEN(mode_str) != 9)
7425 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007426 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427 return;
7428 }
7429
7430 mask = 1;
7431 for (i = 8; i >= 0; --i)
7432 {
7433 if (mode_str[i] != '-')
7434 mode |= mask;
7435 mask = mask << 1;
7436 }
7437 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7438}
7439
7440/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441 * "setpos()" function
7442 */
7443 static void
7444f_setpos(typval_T *argvars, typval_T *rettv)
7445{
7446 pos_T pos;
7447 int fnum;
7448 char_u *name;
7449 colnr_T curswant = -1;
7450
7451 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007452 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007453 if (name != NULL)
7454 {
7455 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7456 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01007457 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007458 pos.col = 0;
7459 if (name[0] == '.' && name[1] == NUL)
7460 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007461 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007462 curwin->w_cursor = pos;
7463 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007465 curwin->w_curswant = curswant - 1;
7466 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007467 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007468 check_cursor();
7469 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007470 }
7471 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7472 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007473 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007474 if (setmark_pos(name[1], &pos, fnum) == OK)
7475 rettv->vval.v_number = 0;
7476 }
7477 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007478 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007479 }
7480 }
7481}
7482
7483/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007484 * "setreg()" function
7485 */
7486 static void
7487f_setreg(typval_T *argvars, typval_T *rettv)
7488{
7489 int regname;
7490 char_u *strregname;
7491 char_u *stropt;
7492 char_u *strval;
7493 int append;
7494 char_u yank_type;
7495 long block_len;
7496
7497 block_len = -1;
7498 yank_type = MAUTO;
7499 append = FALSE;
7500
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007501 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007502 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007503
7504 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007505 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007506 regname = *strregname;
7507 if (regname == 0 || regname == '@')
7508 regname = '"';
7509
7510 if (argvars[2].v_type != VAR_UNKNOWN)
7511 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007512 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007513 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007514 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007515 for (; *stropt != NUL; ++stropt)
7516 switch (*stropt)
7517 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007518 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519 append = TRUE;
7520 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007521 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522 yank_type = MCHAR;
7523 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007524 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007525 yank_type = MLINE;
7526 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007527 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007528 yank_type = MBLOCK;
7529 if (VIM_ISDIGIT(stropt[1]))
7530 {
7531 ++stropt;
7532 block_len = getdigits(&stropt) - 1;
7533 --stropt;
7534 }
7535 break;
7536 }
7537 }
7538
7539 if (argvars[1].v_type == VAR_LIST)
7540 {
7541 char_u **lstval;
7542 char_u **allocval;
7543 char_u buf[NUMBUFLEN];
7544 char_u **curval;
7545 char_u **curallocval;
7546 list_T *ll = argvars[1].vval.v_list;
7547 listitem_T *li;
7548 int len;
7549
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007550 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007551 len = ll == NULL ? 0 : ll->lv_len;
7552
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007553 // First half: use for pointers to result lines; second half: use for
7554 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007555 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007556 if (lstval == NULL)
7557 return;
7558 curval = lstval;
7559 allocval = lstval + len + 2;
7560 curallocval = allocval;
7561
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007562 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007563 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007564 range_list_materialize(ll);
7565 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007566 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007567 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007568 if (strval == NULL)
7569 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01007570 if (strval == buf)
7571 {
7572 // Need to make a copy, next tv_get_string_buf_chk() will
7573 // overwrite the string.
7574 strval = vim_strsave(buf);
7575 if (strval == NULL)
7576 goto free_lstval;
7577 *curallocval++ = strval;
7578 }
7579 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007580 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007581 }
7582 *curval++ = NULL;
7583
7584 write_reg_contents_lst(regname, lstval, -1,
7585 append, yank_type, block_len);
7586free_lstval:
7587 while (curallocval > allocval)
7588 vim_free(*--curallocval);
7589 vim_free(lstval);
7590 }
7591 else
7592 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007593 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007594 if (strval == NULL)
7595 return;
7596 write_reg_contents_ex(regname, strval, -1,
7597 append, yank_type, block_len);
7598 }
7599 rettv->vval.v_number = 0;
7600}
7601
7602/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007603 * "settagstack()" function
7604 */
7605 static void
7606f_settagstack(typval_T *argvars, typval_T *rettv)
7607{
7608 static char *e_invact2 = N_("E962: Invalid action: '%s'");
7609 win_T *wp;
7610 dict_T *d;
7611 int action = 'r';
7612
7613 rettv->vval.v_number = -1;
7614
7615 // first argument: window number or id
7616 wp = find_win_by_nr_or_id(&argvars[0]);
7617 if (wp == NULL)
7618 return;
7619
7620 // second argument: dict with items to set in the tag stack
7621 if (argvars[1].v_type != VAR_DICT)
7622 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007623 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007624 return;
7625 }
7626 d = argvars[1].vval.v_dict;
7627 if (d == NULL)
7628 return;
7629
7630 // third argument: action - 'a' for append and 'r' for replace.
7631 // default is to replace the stack.
7632 if (argvars[2].v_type == VAR_UNKNOWN)
7633 action = 'r';
7634 else if (argvars[2].v_type == VAR_STRING)
7635 {
7636 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007637 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007638 if (actstr == NULL)
7639 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01007640 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
7641 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007642 action = *actstr;
7643 else
7644 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007645 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007646 return;
7647 }
7648 }
7649 else
7650 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007651 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007652 return;
7653 }
7654
7655 if (set_tagstack(wp, d, action) == OK)
7656 rettv->vval.v_number = 0;
7657}
7658
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007659#ifdef FEAT_CRYPT
7660/*
7661 * "sha256({string})" function
7662 */
7663 static void
7664f_sha256(typval_T *argvars, typval_T *rettv)
7665{
7666 char_u *p;
7667
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007668 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007669 rettv->vval.v_string = vim_strsave(
7670 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7671 rettv->v_type = VAR_STRING;
7672}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007673#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007674
7675/*
7676 * "shellescape({string})" function
7677 */
7678 static void
7679f_shellescape(typval_T *argvars, typval_T *rettv)
7680{
Bram Moolenaar20615522017-06-05 18:46:26 +02007681 int do_special = non_zero_arg(&argvars[1]);
7682
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007683 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007684 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007685 rettv->v_type = VAR_STRING;
7686}
7687
7688/*
7689 * shiftwidth() function
7690 */
7691 static void
7692f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7693{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007694 rettv->vval.v_number = 0;
7695
7696 if (argvars[0].v_type != VAR_UNKNOWN)
7697 {
7698 long col;
7699
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007700 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007701 if (col < 0)
7702 return; // type error; errmsg already given
7703#ifdef FEAT_VARTABS
7704 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7705 return;
7706#endif
7707 }
7708
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007709 rettv->vval.v_number = get_sw_value(curbuf);
7710}
7711
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007712#ifdef FEAT_FLOAT
7713/*
7714 * "sin()" function
7715 */
7716 static void
7717f_sin(typval_T *argvars, typval_T *rettv)
7718{
7719 float_T f = 0.0;
7720
7721 rettv->v_type = VAR_FLOAT;
7722 if (get_float_arg(argvars, &f) == OK)
7723 rettv->vval.v_float = sin(f);
7724 else
7725 rettv->vval.v_float = 0.0;
7726}
7727
7728/*
7729 * "sinh()" function
7730 */
7731 static void
7732f_sinh(typval_T *argvars, typval_T *rettv)
7733{
7734 float_T f = 0.0;
7735
7736 rettv->v_type = VAR_FLOAT;
7737 if (get_float_arg(argvars, &f) == OK)
7738 rettv->vval.v_float = sinh(f);
7739 else
7740 rettv->vval.v_float = 0.0;
7741}
7742#endif
7743
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744/*
7745 * "soundfold({word})" function
7746 */
7747 static void
7748f_soundfold(typval_T *argvars, typval_T *rettv)
7749{
7750 char_u *s;
7751
7752 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007753 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007754#ifdef FEAT_SPELL
7755 rettv->vval.v_string = eval_soundfold(s);
7756#else
7757 rettv->vval.v_string = vim_strsave(s);
7758#endif
7759}
7760
7761/*
7762 * "spellbadword()" function
7763 */
7764 static void
7765f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7766{
7767 char_u *word = (char_u *)"";
7768 hlf_T attr = HLF_COUNT;
7769 int len = 0;
7770
7771 if (rettv_list_alloc(rettv) == FAIL)
7772 return;
7773
7774#ifdef FEAT_SPELL
7775 if (argvars[0].v_type == VAR_UNKNOWN)
7776 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007777 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007778 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7779 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007780 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007781 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007782 curwin->w_set_curswant = TRUE;
7783 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007784 }
7785 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7786 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007787 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007788 int capcol = -1;
7789
7790 if (str != NULL)
7791 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007792 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007793 while (*str != NUL)
7794 {
7795 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7796 if (attr != HLF_COUNT)
7797 {
7798 word = str;
7799 break;
7800 }
7801 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007802 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007803 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007804 }
7805 }
7806 }
7807#endif
7808
7809 list_append_string(rettv->vval.v_list, word, len);
7810 list_append_string(rettv->vval.v_list, (char_u *)(
7811 attr == HLF_SPB ? "bad" :
7812 attr == HLF_SPR ? "rare" :
7813 attr == HLF_SPL ? "local" :
7814 attr == HLF_SPC ? "caps" :
7815 ""), -1);
7816}
7817
7818/*
7819 * "spellsuggest()" function
7820 */
7821 static void
7822f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7823{
7824#ifdef FEAT_SPELL
7825 char_u *str;
7826 int typeerr = FALSE;
7827 int maxcount;
7828 garray_T ga;
7829 int i;
7830 listitem_T *li;
7831 int need_capital = FALSE;
7832#endif
7833
7834 if (rettv_list_alloc(rettv) == FAIL)
7835 return;
7836
7837#ifdef FEAT_SPELL
7838 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7839 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007840 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841 if (argvars[1].v_type != VAR_UNKNOWN)
7842 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007843 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007844 if (maxcount <= 0)
7845 return;
7846 if (argvars[2].v_type != VAR_UNKNOWN)
7847 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007848 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007849 if (typeerr)
7850 return;
7851 }
7852 }
7853 else
7854 maxcount = 25;
7855
7856 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7857
7858 for (i = 0; i < ga.ga_len; ++i)
7859 {
7860 str = ((char_u **)ga.ga_data)[i];
7861
7862 li = listitem_alloc();
7863 if (li == NULL)
7864 vim_free(str);
7865 else
7866 {
7867 li->li_tv.v_type = VAR_STRING;
7868 li->li_tv.v_lock = 0;
7869 li->li_tv.vval.v_string = str;
7870 list_append(rettv->vval.v_list, li);
7871 }
7872 }
7873 ga_clear(&ga);
7874 }
7875#endif
7876}
7877
7878 static void
7879f_split(typval_T *argvars, typval_T *rettv)
7880{
7881 char_u *str;
7882 char_u *end;
7883 char_u *pat = NULL;
7884 regmatch_T regmatch;
7885 char_u patbuf[NUMBUFLEN];
7886 char_u *save_cpo;
7887 int match;
7888 colnr_T col = 0;
7889 int keepempty = FALSE;
7890 int typeerr = FALSE;
7891
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007892 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 save_cpo = p_cpo;
7894 p_cpo = (char_u *)"";
7895
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007896 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897 if (argvars[1].v_type != VAR_UNKNOWN)
7898 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007899 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007900 if (pat == NULL)
7901 typeerr = TRUE;
7902 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007903 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 }
7905 if (pat == NULL || *pat == NUL)
7906 pat = (char_u *)"[\\x01- ]\\+";
7907
7908 if (rettv_list_alloc(rettv) == FAIL)
7909 return;
7910 if (typeerr)
7911 return;
7912
7913 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7914 if (regmatch.regprog != NULL)
7915 {
7916 regmatch.rm_ic = FALSE;
7917 while (*str != NUL || keepempty)
7918 {
7919 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007920 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921 else
7922 match = vim_regexec_nl(&regmatch, str, col);
7923 if (match)
7924 end = regmatch.startp[0];
7925 else
7926 end = str + STRLEN(str);
7927 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7928 && *str != NUL && match && end < regmatch.endp[0]))
7929 {
7930 if (list_append_string(rettv->vval.v_list, str,
7931 (int)(end - str)) == FAIL)
7932 break;
7933 }
7934 if (!match)
7935 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007936 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 if (regmatch.endp[0] > str)
7938 col = 0;
7939 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007940 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007941 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942 str = regmatch.endp[0];
7943 }
7944
7945 vim_regfree(regmatch.regprog);
7946 }
7947
7948 p_cpo = save_cpo;
7949}
7950
7951#ifdef FEAT_FLOAT
7952/*
7953 * "sqrt()" function
7954 */
7955 static void
7956f_sqrt(typval_T *argvars, typval_T *rettv)
7957{
7958 float_T f = 0.0;
7959
7960 rettv->v_type = VAR_FLOAT;
7961 if (get_float_arg(argvars, &f) == OK)
7962 rettv->vval.v_float = sqrt(f);
7963 else
7964 rettv->vval.v_float = 0.0;
7965}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007966#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007967
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007968#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007969/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007970 * "str2float()" function
7971 */
7972 static void
7973f_str2float(typval_T *argvars, typval_T *rettv)
7974{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007975 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007976 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007977
Bram Moolenaar08243d22017-01-10 16:12:29 +01007978 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979 p = skipwhite(p + 1);
7980 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007981 if (isneg)
7982 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007983 rettv->v_type = VAR_FLOAT;
7984}
7985#endif
7986
7987/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007988 * "str2list()" function
7989 */
7990 static void
7991f_str2list(typval_T *argvars, typval_T *rettv)
7992{
7993 char_u *p;
7994 int utf8 = FALSE;
7995
7996 if (rettv_list_alloc(rettv) == FAIL)
7997 return;
7998
7999 if (argvars[1].v_type != VAR_UNKNOWN)
8000 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
8001
8002 p = tv_get_string(&argvars[0]);
8003
8004 if (has_mbyte || utf8)
8005 {
8006 int (*ptr2len)(char_u *);
8007 int (*ptr2char)(char_u *);
8008
8009 if (utf8 || enc_utf8)
8010 {
8011 ptr2len = utf_ptr2len;
8012 ptr2char = utf_ptr2char;
8013 }
8014 else
8015 {
8016 ptr2len = mb_ptr2len;
8017 ptr2char = mb_ptr2char;
8018 }
8019
8020 for ( ; *p != NUL; p += (*ptr2len)(p))
8021 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
8022 }
8023 else
8024 for ( ; *p != NUL; ++p)
8025 list_append_number(rettv->vval.v_list, *p);
8026}
8027
8028/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008029 * "str2nr()" function
8030 */
8031 static void
8032f_str2nr(typval_T *argvars, typval_T *rettv)
8033{
8034 int base = 10;
8035 char_u *p;
8036 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008037 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01008038 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039
8040 if (argvars[1].v_type != VAR_UNKNOWN)
8041 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008042 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008043 if (base != 2 && base != 8 && base != 10 && base != 16)
8044 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008045 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008046 return;
8047 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008048 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
8049 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008050 }
8051
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008052 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008053 isneg = (*p == '-');
8054 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008055 p = skipwhite(p + 1);
8056 switch (base)
8057 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02008058 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
8059 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
8060 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008061 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02008062 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
8063 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01008064 if (isneg)
8065 rettv->vval.v_number = -n;
8066 else
8067 rettv->vval.v_number = n;
8068
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069}
8070
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008071/*
8072 * "strgetchar()" function
8073 */
8074 static void
8075f_strgetchar(typval_T *argvars, typval_T *rettv)
8076{
8077 char_u *str;
8078 int len;
8079 int error = FALSE;
8080 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01008081 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082
8083 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008084 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008085 if (str == NULL)
8086 return;
8087 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008088 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008089 if (error)
8090 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008091
Bram Moolenaar13505972019-01-24 15:04:48 +01008092 while (charidx >= 0 && byteidx < len)
8093 {
8094 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008096 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8097 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008098 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008099 --charidx;
8100 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008101 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008102}
8103
8104/*
8105 * "stridx()" function
8106 */
8107 static void
8108f_stridx(typval_T *argvars, typval_T *rettv)
8109{
8110 char_u buf[NUMBUFLEN];
8111 char_u *needle;
8112 char_u *haystack;
8113 char_u *save_haystack;
8114 char_u *pos;
8115 int start_idx;
8116
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008117 needle = tv_get_string_chk(&argvars[1]);
8118 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119 rettv->vval.v_number = -1;
8120 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008121 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122
8123 if (argvars[2].v_type != VAR_UNKNOWN)
8124 {
8125 int error = FALSE;
8126
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008127 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128 if (error || start_idx >= (int)STRLEN(haystack))
8129 return;
8130 if (start_idx >= 0)
8131 haystack += start_idx;
8132 }
8133
8134 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8135 if (pos != NULL)
8136 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8137}
8138
8139/*
8140 * "string()" function
8141 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008142 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008143f_string(typval_T *argvars, typval_T *rettv)
8144{
8145 char_u *tofree;
8146 char_u numbuf[NUMBUFLEN];
8147
8148 rettv->v_type = VAR_STRING;
8149 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8150 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008151 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008152 if (rettv->vval.v_string != NULL && tofree == NULL)
8153 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8154}
8155
8156/*
8157 * "strlen()" function
8158 */
8159 static void
8160f_strlen(typval_T *argvars, typval_T *rettv)
8161{
8162 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008163 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164}
8165
8166/*
8167 * "strchars()" function
8168 */
8169 static void
8170f_strchars(typval_T *argvars, typval_T *rettv)
8171{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008172 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008173 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174 varnumber_T len = 0;
8175 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176
8177 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008178 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008180 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008181 else
8182 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008183 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8184 while (*s != NUL)
8185 {
8186 func_mb_ptr2char_adv(&s);
8187 ++len;
8188 }
8189 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190 }
8191}
8192
8193/*
8194 * "strdisplaywidth()" function
8195 */
8196 static void
8197f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8198{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008199 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008200 int col = 0;
8201
8202 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008203 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008204
8205 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8206}
8207
8208/*
8209 * "strwidth()" function
8210 */
8211 static void
8212f_strwidth(typval_T *argvars, typval_T *rettv)
8213{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008214 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008215
Bram Moolenaar13505972019-01-24 15:04:48 +01008216 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008217}
8218
8219/*
8220 * "strcharpart()" function
8221 */
8222 static void
8223f_strcharpart(typval_T *argvars, typval_T *rettv)
8224{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225 char_u *p;
8226 int nchar;
8227 int nbyte = 0;
8228 int charlen;
8229 int len = 0;
8230 int slen;
8231 int error = FALSE;
8232
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008233 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008234 slen = (int)STRLEN(p);
8235
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008236 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008237 if (!error)
8238 {
8239 if (nchar > 0)
8240 while (nchar > 0 && nbyte < slen)
8241 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008242 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008243 --nchar;
8244 }
8245 else
8246 nbyte = nchar;
8247 if (argvars[2].v_type != VAR_UNKNOWN)
8248 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008249 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008250 while (charlen > 0 && nbyte + len < slen)
8251 {
8252 int off = nbyte + len;
8253
8254 if (off < 0)
8255 len += 1;
8256 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008257 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008258 --charlen;
8259 }
8260 }
8261 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008262 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008263 }
8264
8265 /*
8266 * Only return the overlap between the specified part and the actual
8267 * string.
8268 */
8269 if (nbyte < 0)
8270 {
8271 len += nbyte;
8272 nbyte = 0;
8273 }
8274 else if (nbyte > slen)
8275 nbyte = slen;
8276 if (len < 0)
8277 len = 0;
8278 else if (nbyte + len > slen)
8279 len = slen - nbyte;
8280
8281 rettv->v_type = VAR_STRING;
8282 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008283}
8284
8285/*
8286 * "strpart()" function
8287 */
8288 static void
8289f_strpart(typval_T *argvars, typval_T *rettv)
8290{
8291 char_u *p;
8292 int n;
8293 int len;
8294 int slen;
8295 int error = FALSE;
8296
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008297 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008298 slen = (int)STRLEN(p);
8299
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008300 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008301 if (error)
8302 len = 0;
8303 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008304 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008305 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008306 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008307
8308 /*
8309 * Only return the overlap between the specified part and the actual
8310 * string.
8311 */
8312 if (n < 0)
8313 {
8314 len += n;
8315 n = 0;
8316 }
8317 else if (n > slen)
8318 n = slen;
8319 if (len < 0)
8320 len = 0;
8321 else if (n + len > slen)
8322 len = slen - n;
8323
8324 rettv->v_type = VAR_STRING;
8325 rettv->vval.v_string = vim_strnsave(p + n, len);
8326}
8327
8328/*
8329 * "strridx()" function
8330 */
8331 static void
8332f_strridx(typval_T *argvars, typval_T *rettv)
8333{
8334 char_u buf[NUMBUFLEN];
8335 char_u *needle;
8336 char_u *haystack;
8337 char_u *rest;
8338 char_u *lastmatch = NULL;
8339 int haystack_len, end_idx;
8340
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008341 needle = tv_get_string_chk(&argvars[1]);
8342 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008343
8344 rettv->vval.v_number = -1;
8345 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008346 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008347
8348 haystack_len = (int)STRLEN(haystack);
8349 if (argvars[2].v_type != VAR_UNKNOWN)
8350 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008351 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008352 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008354 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008355 }
8356 else
8357 end_idx = haystack_len;
8358
8359 if (*needle == NUL)
8360 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008361 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008362 lastmatch = haystack + end_idx;
8363 }
8364 else
8365 {
8366 for (rest = haystack; *rest != '\0'; ++rest)
8367 {
8368 rest = (char_u *)strstr((char *)rest, (char *)needle);
8369 if (rest == NULL || rest > haystack + end_idx)
8370 break;
8371 lastmatch = rest;
8372 }
8373 }
8374
8375 if (lastmatch == NULL)
8376 rettv->vval.v_number = -1;
8377 else
8378 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8379}
8380
8381/*
8382 * "strtrans()" function
8383 */
8384 static void
8385f_strtrans(typval_T *argvars, typval_T *rettv)
8386{
8387 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008388 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008389}
8390
8391/*
8392 * "submatch()" function
8393 */
8394 static void
8395f_submatch(typval_T *argvars, typval_T *rettv)
8396{
8397 int error = FALSE;
8398 int no;
8399 int retList = 0;
8400
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008401 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402 if (error)
8403 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008404 if (no < 0 || no >= NSUBEXP)
8405 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008406 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008407 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008408 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008409 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008410 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008411 if (error)
8412 return;
8413
8414 if (retList == 0)
8415 {
8416 rettv->v_type = VAR_STRING;
8417 rettv->vval.v_string = reg_submatch(no);
8418 }
8419 else
8420 {
8421 rettv->v_type = VAR_LIST;
8422 rettv->vval.v_list = reg_submatch_list(no);
8423 }
8424}
8425
8426/*
8427 * "substitute()" function
8428 */
8429 static void
8430f_substitute(typval_T *argvars, typval_T *rettv)
8431{
8432 char_u patbuf[NUMBUFLEN];
8433 char_u subbuf[NUMBUFLEN];
8434 char_u flagsbuf[NUMBUFLEN];
8435
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008436 char_u *str = tv_get_string_chk(&argvars[0]);
8437 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008438 char_u *sub = NULL;
8439 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008440 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008441
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008442 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8443 expr = &argvars[2];
8444 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008445 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008446
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008447 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008448 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8449 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008450 rettv->vval.v_string = NULL;
8451 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008452 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008453}
8454
8455/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008456 * "swapinfo(swap_filename)" function
8457 */
8458 static void
8459f_swapinfo(typval_T *argvars, typval_T *rettv)
8460{
8461 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008462 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008463}
8464
8465/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02008466 * "swapname(expr)" function
8467 */
8468 static void
8469f_swapname(typval_T *argvars, typval_T *rettv)
8470{
8471 buf_T *buf;
8472
8473 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008474 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02008475 if (buf == NULL || buf->b_ml.ml_mfp == NULL
8476 || buf->b_ml.ml_mfp->mf_fname == NULL)
8477 rettv->vval.v_string = NULL;
8478 else
8479 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
8480}
8481
8482/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008483 * "synID(lnum, col, trans)" function
8484 */
8485 static void
8486f_synID(typval_T *argvars UNUSED, typval_T *rettv)
8487{
8488 int id = 0;
8489#ifdef FEAT_SYN_HL
8490 linenr_T lnum;
8491 colnr_T col;
8492 int trans;
8493 int transerr = FALSE;
8494
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008495 lnum = tv_get_lnum(argvars); // -1 on type error
8496 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008497 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008498
8499 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8500 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
8501 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
8502#endif
8503
8504 rettv->vval.v_number = id;
8505}
8506
8507/*
8508 * "synIDattr(id, what [, mode])" function
8509 */
8510 static void
8511f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
8512{
8513 char_u *p = NULL;
8514#ifdef FEAT_SYN_HL
8515 int id;
8516 char_u *what;
8517 char_u *mode;
8518 char_u modebuf[NUMBUFLEN];
8519 int modec;
8520
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008521 id = (int)tv_get_number(&argvars[0]);
8522 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008523 if (argvars[2].v_type != VAR_UNKNOWN)
8524 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008525 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008526 modec = TOLOWER_ASC(mode[0]);
8527 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008528 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008529 }
8530 else
8531 {
8532#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
8533 if (USE_24BIT)
8534 modec = 'g';
8535 else
8536#endif
8537 if (t_colors > 1)
8538 modec = 'c';
8539 else
8540 modec = 't';
8541 }
8542
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008543 switch (TOLOWER_ASC(what[0]))
8544 {
8545 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008546 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008547 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008548 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008549 p = highlight_has_attr(id, HL_BOLD, modec);
8550 break;
8551
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008552 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008553 p = highlight_color(id, what, modec);
8554 break;
8555
8556 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008557 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008558 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008559 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008560 p = highlight_has_attr(id, HL_ITALIC, modec);
8561 break;
8562
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008563 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008564 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008565 break;
8566
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008567 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008568 p = highlight_has_attr(id, HL_INVERSE, modec);
8569 break;
8570
8571 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008572 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008573 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008574 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008575 else if (TOLOWER_ASC(what[1]) == 't' &&
8576 TOLOWER_ASC(what[2]) == 'r')
8577 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008578 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008579 p = highlight_has_attr(id, HL_STANDOUT, modec);
8580 break;
8581
8582 case 'u':
8583 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008584 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008585 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8586 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008587 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008588 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8589 break;
8590 }
8591
8592 if (p != NULL)
8593 p = vim_strsave(p);
8594#endif
8595 rettv->v_type = VAR_STRING;
8596 rettv->vval.v_string = p;
8597}
8598
8599/*
8600 * "synIDtrans(id)" function
8601 */
8602 static void
8603f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8604{
8605 int id;
8606
8607#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008608 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008609
8610 if (id > 0)
8611 id = syn_get_final_id(id);
8612 else
8613#endif
8614 id = 0;
8615
8616 rettv->vval.v_number = id;
8617}
8618
8619/*
8620 * "synconcealed(lnum, col)" function
8621 */
8622 static void
8623f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8624{
8625#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8626 linenr_T lnum;
8627 colnr_T col;
8628 int syntax_flags = 0;
8629 int cchar;
8630 int matchid = 0;
8631 char_u str[NUMBUFLEN];
8632#endif
8633
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008634 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008635
8636#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008637 lnum = tv_get_lnum(argvars); // -1 on type error
8638 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008639
8640 vim_memset(str, NUL, sizeof(str));
8641
8642 if (rettv_list_alloc(rettv) != FAIL)
8643 {
8644 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8645 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8646 && curwin->w_p_cole > 0)
8647 {
8648 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8649 syntax_flags = get_syntax_info(&matchid);
8650
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008651 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008652 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8653 {
8654 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008655 if (cchar == NUL && curwin->w_p_cole == 1)
8656 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008657 if (cchar != NUL)
8658 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008659 if (has_mbyte)
8660 (*mb_char2bytes)(cchar, str);
8661 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008662 str[0] = cchar;
8663 }
8664 }
8665 }
8666
8667 list_append_number(rettv->vval.v_list,
8668 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008669 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008670 list_append_string(rettv->vval.v_list, str, -1);
8671 list_append_number(rettv->vval.v_list, matchid);
8672 }
8673#endif
8674}
8675
8676/*
8677 * "synstack(lnum, col)" function
8678 */
8679 static void
8680f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8681{
8682#ifdef FEAT_SYN_HL
8683 linenr_T lnum;
8684 colnr_T col;
8685 int i;
8686 int id;
8687#endif
8688
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008689 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008690
8691#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008692 lnum = tv_get_lnum(argvars); // -1 on type error
8693 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008694
8695 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8696 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8697 && rettv_list_alloc(rettv) != FAIL)
8698 {
8699 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8700 for (i = 0; ; ++i)
8701 {
8702 id = syn_get_stack_item(i);
8703 if (id < 0)
8704 break;
8705 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8706 break;
8707 }
8708 }
8709#endif
8710}
8711
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008712/*
8713 * "tabpagebuflist()" function
8714 */
8715 static void
8716f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8717{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008718 tabpage_T *tp;
8719 win_T *wp = NULL;
8720
8721 if (argvars[0].v_type == VAR_UNKNOWN)
8722 wp = firstwin;
8723 else
8724 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008725 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008726 if (tp != NULL)
8727 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8728 }
8729 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8730 {
8731 for (; wp != NULL; wp = wp->w_next)
8732 if (list_append_number(rettv->vval.v_list,
8733 wp->w_buffer->b_fnum) == FAIL)
8734 break;
8735 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008736}
8737
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008738/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008739 * "tagfiles()" function
8740 */
8741 static void
8742f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8743{
8744 char_u *fname;
8745 tagname_T tn;
8746 int first;
8747
8748 if (rettv_list_alloc(rettv) == FAIL)
8749 return;
8750 fname = alloc(MAXPATHL);
8751 if (fname == NULL)
8752 return;
8753
8754 for (first = TRUE; ; first = FALSE)
8755 if (get_tagfname(&tn, first, fname) == FAIL
8756 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8757 break;
8758 tagname_free(&tn);
8759 vim_free(fname);
8760}
8761
8762/*
8763 * "taglist()" function
8764 */
8765 static void
8766f_taglist(typval_T *argvars, typval_T *rettv)
8767{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008768 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008769 char_u *tag_pattern;
8770
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008771 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008772
8773 rettv->vval.v_number = FALSE;
8774 if (*tag_pattern == NUL)
8775 return;
8776
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008777 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008778 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008779 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008780 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008781}
8782
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008783#ifdef FEAT_FLOAT
8784/*
8785 * "tan()" function
8786 */
8787 static void
8788f_tan(typval_T *argvars, typval_T *rettv)
8789{
8790 float_T f = 0.0;
8791
8792 rettv->v_type = VAR_FLOAT;
8793 if (get_float_arg(argvars, &f) == OK)
8794 rettv->vval.v_float = tan(f);
8795 else
8796 rettv->vval.v_float = 0.0;
8797}
8798
8799/*
8800 * "tanh()" function
8801 */
8802 static void
8803f_tanh(typval_T *argvars, typval_T *rettv)
8804{
8805 float_T f = 0.0;
8806
8807 rettv->v_type = VAR_FLOAT;
8808 if (get_float_arg(argvars, &f) == OK)
8809 rettv->vval.v_float = tanh(f);
8810 else
8811 rettv->vval.v_float = 0.0;
8812}
8813#endif
8814
8815/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008816 * "tolower(string)" function
8817 */
8818 static void
8819f_tolower(typval_T *argvars, typval_T *rettv)
8820{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008821 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008822 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008823}
8824
8825/*
8826 * "toupper(string)" function
8827 */
8828 static void
8829f_toupper(typval_T *argvars, typval_T *rettv)
8830{
8831 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008832 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008833}
8834
8835/*
8836 * "tr(string, fromstr, tostr)" function
8837 */
8838 static void
8839f_tr(typval_T *argvars, typval_T *rettv)
8840{
8841 char_u *in_str;
8842 char_u *fromstr;
8843 char_u *tostr;
8844 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008845 int inlen;
8846 int fromlen;
8847 int tolen;
8848 int idx;
8849 char_u *cpstr;
8850 int cplen;
8851 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008852 char_u buf[NUMBUFLEN];
8853 char_u buf2[NUMBUFLEN];
8854 garray_T ga;
8855
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008856 in_str = tv_get_string(&argvars[0]);
8857 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8858 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008859
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008860 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008861 rettv->v_type = VAR_STRING;
8862 rettv->vval.v_string = NULL;
8863 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008864 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008865 ga_init2(&ga, (int)sizeof(char), 80);
8866
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008867 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008868 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008869 if (STRLEN(fromstr) != STRLEN(tostr))
8870 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008871error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008872 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008873 ga_clear(&ga);
8874 return;
8875 }
8876
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008877 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008878 while (*in_str != NUL)
8879 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008880 if (has_mbyte)
8881 {
8882 inlen = (*mb_ptr2len)(in_str);
8883 cpstr = in_str;
8884 cplen = inlen;
8885 idx = 0;
8886 for (p = fromstr; *p != NUL; p += fromlen)
8887 {
8888 fromlen = (*mb_ptr2len)(p);
8889 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8890 {
8891 for (p = tostr; *p != NUL; p += tolen)
8892 {
8893 tolen = (*mb_ptr2len)(p);
8894 if (idx-- == 0)
8895 {
8896 cplen = tolen;
8897 cpstr = p;
8898 break;
8899 }
8900 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008901 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008902 goto error;
8903 break;
8904 }
8905 ++idx;
8906 }
8907
8908 if (first && cpstr == in_str)
8909 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008910 // Check that fromstr and tostr have the same number of
8911 // (multi-byte) characters. Done only once when a character
8912 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008913 first = FALSE;
8914 for (p = tostr; *p != NUL; p += tolen)
8915 {
8916 tolen = (*mb_ptr2len)(p);
8917 --idx;
8918 }
8919 if (idx != 0)
8920 goto error;
8921 }
8922
8923 (void)ga_grow(&ga, cplen);
8924 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8925 ga.ga_len += cplen;
8926
8927 in_str += inlen;
8928 }
8929 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008930 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008931 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008932 p = vim_strchr(fromstr, *in_str);
8933 if (p != NULL)
8934 ga_append(&ga, tostr[p - fromstr]);
8935 else
8936 ga_append(&ga, *in_str);
8937 ++in_str;
8938 }
8939 }
8940
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008941 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008942 (void)ga_grow(&ga, 1);
8943 ga_append(&ga, NUL);
8944
8945 rettv->vval.v_string = ga.ga_data;
8946}
8947
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008948/*
8949 * "trim({expr})" function
8950 */
8951 static void
8952f_trim(typval_T *argvars, typval_T *rettv)
8953{
8954 char_u buf1[NUMBUFLEN];
8955 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008956 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008957 char_u *mask = NULL;
8958 char_u *tail;
8959 char_u *prev;
8960 char_u *p;
8961 int c1;
8962
8963 rettv->v_type = VAR_STRING;
8964 if (head == NULL)
8965 {
8966 rettv->vval.v_string = NULL;
8967 return;
8968 }
8969
8970 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008971 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008972
8973 while (*head != NUL)
8974 {
8975 c1 = PTR2CHAR(head);
8976 if (mask == NULL)
8977 {
8978 if (c1 > ' ' && c1 != 0xa0)
8979 break;
8980 }
8981 else
8982 {
8983 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8984 if (c1 == PTR2CHAR(p))
8985 break;
8986 if (*p == NUL)
8987 break;
8988 }
8989 MB_PTR_ADV(head);
8990 }
8991
8992 for (tail = head + STRLEN(head); tail > head; tail = prev)
8993 {
8994 prev = tail;
8995 MB_PTR_BACK(head, prev);
8996 c1 = PTR2CHAR(prev);
8997 if (mask == NULL)
8998 {
8999 if (c1 > ' ' && c1 != 0xa0)
9000 break;
9001 }
9002 else
9003 {
9004 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9005 if (c1 == PTR2CHAR(p))
9006 break;
9007 if (*p == NUL)
9008 break;
9009 }
9010 }
9011 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
9012}
9013
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009014#ifdef FEAT_FLOAT
9015/*
9016 * "trunc({float})" function
9017 */
9018 static void
9019f_trunc(typval_T *argvars, typval_T *rettv)
9020{
9021 float_T f = 0.0;
9022
9023 rettv->v_type = VAR_FLOAT;
9024 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009025 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009026 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
9027 else
9028 rettv->vval.v_float = 0.0;
9029}
9030#endif
9031
9032/*
9033 * "type(expr)" function
9034 */
9035 static void
9036f_type(typval_T *argvars, typval_T *rettv)
9037{
9038 int n = -1;
9039
9040 switch (argvars[0].v_type)
9041 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009042 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
9043 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009044 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01009045 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
9046 case VAR_LIST: n = VAR_TYPE_LIST; break;
9047 case VAR_DICT: n = VAR_TYPE_DICT; break;
9048 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
9049 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
9050 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02009051 case VAR_JOB: n = VAR_TYPE_JOB; break;
9052 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009053 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009054 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01009055 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01009056 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009057 n = -1;
9058 break;
9059 }
9060 rettv->vval.v_number = n;
9061}
9062
9063/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009064 * "virtcol(string)" function
9065 */
9066 static void
9067f_virtcol(typval_T *argvars, typval_T *rettv)
9068{
9069 colnr_T vcol = 0;
9070 pos_T *fp;
9071 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009072 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009073
9074 fp = var2fpos(&argvars[0], FALSE, &fnum);
9075 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9076 && fnum == curbuf->b_fnum)
9077 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01009078 // Limit the column to a valid value, getvvcol() doesn't check.
9079 if (fp->col < 0)
9080 fp->col = 0;
9081 else
9082 {
9083 len = (int)STRLEN(ml_get(fp->lnum));
9084 if (fp->col > len)
9085 fp->col = len;
9086 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009087 getvvcol(curwin, fp, NULL, NULL, &vcol);
9088 ++vcol;
9089 }
9090
9091 rettv->vval.v_number = vcol;
9092}
9093
9094/*
9095 * "visualmode()" function
9096 */
9097 static void
9098f_visualmode(typval_T *argvars, typval_T *rettv)
9099{
9100 char_u str[2];
9101
9102 rettv->v_type = VAR_STRING;
9103 str[0] = curbuf->b_visual_mode_eval;
9104 str[1] = NUL;
9105 rettv->vval.v_string = vim_strsave(str);
9106
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009107 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009108 if (non_zero_arg(&argvars[0]))
9109 curbuf->b_visual_mode_eval = NUL;
9110}
9111
9112/*
9113 * "wildmenumode()" function
9114 */
9115 static void
9116f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9117{
9118#ifdef FEAT_WILDMENU
9119 if (wild_menu_showing)
9120 rettv->vval.v_number = 1;
9121#endif
9122}
9123
9124/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01009125 * "windowsversion()" function
9126 */
9127 static void
9128f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9129{
9130 rettv->v_type = VAR_STRING;
9131 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
9132}
9133
9134/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009135 * "wordcount()" function
9136 */
9137 static void
9138f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
9139{
9140 if (rettv_dict_alloc(rettv) == FAIL)
9141 return;
9142 cursor_pos_info(rettv->vval.v_dict);
9143}
9144
9145/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009146 * "xor(expr, expr)" function
9147 */
9148 static void
9149f_xor(typval_T *argvars, typval_T *rettv)
9150{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009151 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
9152 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009153}
9154
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01009155#endif // FEAT_EVAL