blob: 0f99c6dab8e835300ec26b3c57be400364f049f5 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020023#ifdef FEAT_FLOAT
24static void f_abs(typval_T *argvars, typval_T *rettv);
25static void f_acos(typval_T *argvars, typval_T *rettv);
26#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028#ifdef FEAT_FLOAT
29static void f_asin(typval_T *argvars, typval_T *rettv);
30static void f_atan(typval_T *argvars, typval_T *rettv);
31static void f_atan2(typval_T *argvars, typval_T *rettv);
32#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010033#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020034static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010035static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010036# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010037static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010038# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020040static void f_byte2line(typval_T *argvars, typval_T *rettv);
41static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
42static void f_byteidx(typval_T *argvars, typval_T *rettv);
43static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
44static void f_call(typval_T *argvars, typval_T *rettv);
45#ifdef FEAT_FLOAT
46static void f_ceil(typval_T *argvars, typval_T *rettv);
47#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_changenr(typval_T *argvars, typval_T *rettv);
49static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_confirm(typval_T *argvars, typval_T *rettv);
52static void f_copy(typval_T *argvars, typval_T *rettv);
53#ifdef FEAT_FLOAT
54static void f_cos(typval_T *argvars, typval_T *rettv);
55static void f_cosh(typval_T *argvars, typval_T *rettv);
56#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010058#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020059static void f_debugbreak(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4132eb52020-02-14 16:53:00 +010063static void f_echoraw(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020064static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020065static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_escape(typval_T *argvars, typval_T *rettv);
67static void f_eval(typval_T *argvars, typval_T *rettv);
68static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_exists(typval_T *argvars, typval_T *rettv);
71#ifdef FEAT_FLOAT
72static void f_exp(typval_T *argvars, typval_T *rettv);
73#endif
74static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020075static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077#ifdef FEAT_FLOAT
78static void f_float2nr(typval_T *argvars, typval_T *rettv);
79static void f_floor(typval_T *argvars, typval_T *rettv);
80static void f_fmod(typval_T *argvars, typval_T *rettv);
81#endif
82static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020084static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_function(typval_T *argvars, typval_T *rettv);
86static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
87static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010088static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020090static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010092static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getpid(typval_T *argvars, typval_T *rettv);
94static void f_getcurpos(typval_T *argvars, typval_T *rettv);
95static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getreg(typval_T *argvars, typval_T *rettv);
97static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010098static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
100static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_hlID(typval_T *argvars, typval_T *rettv);
102static void f_hlexists(typval_T *argvars, typval_T *rettv);
103static void f_hostname(typval_T *argvars, typval_T *rettv);
104static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_index(typval_T *argvars, typval_T *rettv);
106static void f_input(typval_T *argvars, typval_T *rettv);
107static void f_inputdialog(typval_T *argvars, typval_T *rettv);
108static void f_inputlist(typval_T *argvars, typval_T *rettv);
109static void f_inputrestore(typval_T *argvars, typval_T *rettv);
110static void f_inputsave(typval_T *argvars, typval_T *rettv);
111static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100112static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200113static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200114static void f_islocked(typval_T *argvars, typval_T *rettv);
115#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200116static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_isnan(typval_T *argvars, typval_T *rettv);
118#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
120static void f_len(typval_T *argvars, typval_T *rettv);
121static void f_libcall(typval_T *argvars, typval_T *rettv);
122static void f_libcallnr(typval_T *argvars, typval_T *rettv);
123static void f_line(typval_T *argvars, typval_T *rettv);
124static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125#ifdef FEAT_FLOAT
126static void f_log(typval_T *argvars, typval_T *rettv);
127static void f_log10(typval_T *argvars, typval_T *rettv);
128#endif
129#ifdef FEAT_LUA
130static void f_luaeval(typval_T *argvars, typval_T *rettv);
131#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_maparg(typval_T *argvars, typval_T *rettv);
133static void f_mapcheck(typval_T *argvars, typval_T *rettv);
134static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_matchend(typval_T *argvars, typval_T *rettv);
136static void f_matchlist(typval_T *argvars, typval_T *rettv);
137static void f_matchstr(typval_T *argvars, typval_T *rettv);
138static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
139static void f_max(typval_T *argvars, typval_T *rettv);
140static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141#ifdef FEAT_MZSCHEME
142static void f_mzeval(typval_T *argvars, typval_T *rettv);
143#endif
144static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
145static void f_nr2char(typval_T *argvars, typval_T *rettv);
146static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_PERL
148static void f_perleval(typval_T *argvars, typval_T *rettv);
149#endif
150#ifdef FEAT_FLOAT
151static void f_pow(typval_T *argvars, typval_T *rettv);
152#endif
153static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
154static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200155static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_pumvisible(typval_T *argvars, typval_T *rettv);
157#ifdef FEAT_PYTHON3
158static void f_py3eval(typval_T *argvars, typval_T *rettv);
159#endif
160#ifdef FEAT_PYTHON
161static void f_pyeval(typval_T *argvars, typval_T *rettv);
162#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100163#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
164static void f_pyxeval(typval_T *argvars, typval_T *rettv);
165#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100166static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100167static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200169static void f_reg_executing(typval_T *argvars, typval_T *rettv);
170static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_remote_expr(typval_T *argvars, typval_T *rettv);
172static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
173static void f_remote_peek(typval_T *argvars, typval_T *rettv);
174static void f_remote_read(typval_T *argvars, typval_T *rettv);
175static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100176static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_rename(typval_T *argvars, typval_T *rettv);
178static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179#ifdef FEAT_FLOAT
180static void f_round(typval_T *argvars, typval_T *rettv);
181#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100182#ifdef FEAT_RUBY
183static void f_rubyeval(typval_T *argvars, typval_T *rettv);
184#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_screenattr(typval_T *argvars, typval_T *rettv);
186static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100187static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_screencol(typval_T *argvars, typval_T *rettv);
189static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100190static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_search(typval_T *argvars, typval_T *rettv);
192static void f_searchdecl(typval_T *argvars, typval_T *rettv);
193static void f_searchpair(typval_T *argvars, typval_T *rettv);
194static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
195static void f_searchpos(typval_T *argvars, typval_T *rettv);
196static void f_server2client(typval_T *argvars, typval_T *rettv);
197static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200199static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100203static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204#ifdef FEAT_CRYPT
205static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_shellescape(typval_T *argvars, typval_T *rettv);
208static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209#ifdef FEAT_FLOAT
210static void f_sin(typval_T *argvars, typval_T *rettv);
211static void f_sinh(typval_T *argvars, typval_T *rettv);
212#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_soundfold(typval_T *argvars, typval_T *rettv);
214static void f_spellbadword(typval_T *argvars, typval_T *rettv);
215static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
216static void f_split(typval_T *argvars, typval_T *rettv);
217#ifdef FEAT_FLOAT
218static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100219#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100220static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100221#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_str2float(typval_T *argvars, typval_T *rettv);
223#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200224static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_str2nr(typval_T *argvars, typval_T *rettv);
226static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200227static void f_strgetchar(typval_T *argvars, typval_T *rettv);
228static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200229static void f_strlen(typval_T *argvars, typval_T *rettv);
230static void f_strcharpart(typval_T *argvars, typval_T *rettv);
231static void f_strpart(typval_T *argvars, typval_T *rettv);
232static void f_strridx(typval_T *argvars, typval_T *rettv);
233static void f_strtrans(typval_T *argvars, typval_T *rettv);
234static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
235static void f_strwidth(typval_T *argvars, typval_T *rettv);
236static void f_submatch(typval_T *argvars, typval_T *rettv);
237static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200238static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200239static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_synID(typval_T *argvars, typval_T *rettv);
241static void f_synIDattr(typval_T *argvars, typval_T *rettv);
242static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
243static void f_synstack(typval_T *argvars, typval_T *rettv);
244static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_taglist(typval_T *argvars, typval_T *rettv);
247static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248#ifdef FEAT_FLOAT
249static void f_tan(typval_T *argvars, typval_T *rettv);
250static void f_tanh(typval_T *argvars, typval_T *rettv);
251#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200252static void f_tolower(typval_T *argvars, typval_T *rettv);
253static void f_toupper(typval_T *argvars, typval_T *rettv);
254static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100255static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256#ifdef FEAT_FLOAT
257static void f_trunc(typval_T *argvars, typval_T *rettv);
258#endif
259static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_virtcol(typval_T *argvars, typval_T *rettv);
261static void f_visualmode(typval_T *argvars, typval_T *rettv);
262static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100263static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264static void f_wordcount(typval_T *argvars, typval_T *rettv);
265static void f_xor(typval_T *argvars, typval_T *rettv);
266
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100267
268 static type_T *
269ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
270{
271 return &t_void;
272}
273 static type_T *
274ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
275{
276 return &t_any;
277}
278 static type_T *
279ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
280{
281 return &t_number;
282}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100283#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100284 static type_T *
285ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
286{
287 return &t_float;
288}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100289#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100290 static type_T *
291ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
292{
293 return &t_string;
294}
295 static type_T * ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
296{
297 return &t_list_any;
298}
299 static type_T *
300ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
301{
302 return &t_list_number;
303}
304 static type_T *
305ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
306{
307 return &t_list_string;
308}
309 static type_T *
310ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
311{
312 return &t_list_dict_any;
313}
314 static type_T *
315ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
316{
317 return &t_dict_any;
318}
319 static type_T *
320ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
321{
322 return &t_dict_number;
323}
324 static type_T *
325ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
326{
327 return &t_dict_string;
328}
329 static type_T *
330ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
331{
332 return &t_blob;
333}
334 static type_T *
335ret_partial_void(int argcount UNUSED, type_T **argtypes UNUSED)
336{
337 return &t_partial_void;
338}
339#ifdef FEAT_JOB_CHANNEL
340 static type_T *
341ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
342{
343 return &t_channel;
344}
345 static type_T *
346ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
347{
348 return &t_job;
349}
350#endif
351
352static type_T *ret_f_function(int argcount, type_T **argtypes);
353
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200354/*
355 * Array with names and number of arguments of all internal functions
356 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
357 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200358typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200360 char *f_name; // function name
361 char f_min_argc; // minimal number of arguments
362 char f_max_argc; // maximal number of arguments
363 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100364 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
365 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200367 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200368} funcentry_T;
369
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200370// values for f_argtype; zero means it cannot be used as a method
371#define FEARG_1 1 // base is the first argument
372#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200373#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200374#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200375#define FEARG_LAST 9 // base is the last argument
376
Bram Moolenaarac92e252019-08-03 21:58:38 +0200377static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378{
379#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100380 {"abs", 1, 1, FEARG_1, ret_any, f_abs},
381 {"acos", 1, 1, FEARG_1, ret_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200382#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100383 {"add", 2, 2, FEARG_1, ret_any, f_add},
384 {"and", 2, 2, FEARG_1, ret_number, f_and},
385 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
386 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
387 {"argc", 0, 1, 0, ret_number, f_argc},
388 {"argidx", 0, 0, 0, ret_number, f_argidx},
389 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
390 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100392 {"asin", 1, 1, FEARG_1, ret_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200393#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100394 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
395 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
396 {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile},
397 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
398 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
399 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
400 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
401 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
402 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
403 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
404 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
405 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200406#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100407 {"atan", 1, 1, FEARG_1, ret_float, f_atan},
408 {"atan2", 2, 2, FEARG_1, ret_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100410#ifdef FEAT_BEVAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100411 {"balloon_gettext", 0, 0, 0, ret_string, f_balloon_gettext},
412 {"balloon_show", 1, 1, FEARG_1, ret_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100413# if defined(FEAT_BEVAL_TERM)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100414 {"balloon_split", 1, 1, FEARG_1, ret_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100415# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100416#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100417 {"browse", 4, 4, 0, ret_string, f_browse},
418 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
419 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
420 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
421 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
422 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
423 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
424 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
425 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
426 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
427 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
428 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
429 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
430 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
431 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
432 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
433 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
434 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100436 {"ceil", 1, 1, FEARG_1, ret_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437#endif
438#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100439 {"ch_canread", 1, 1, FEARG_1, ret_number, f_ch_canread},
440 {"ch_close", 1, 1, FEARG_1, ret_void, f_ch_close},
441 {"ch_close_in", 1, 1, FEARG_1, ret_void, f_ch_close_in},
442 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, f_ch_evalexpr},
443 {"ch_evalraw", 2, 3, FEARG_1, ret_any, f_ch_evalraw},
444 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, f_ch_getbufnr},
445 {"ch_getjob", 1, 1, FEARG_1, ret_job, f_ch_getjob},
446 {"ch_info", 1, 1, FEARG_1, ret_dict_any, f_ch_info},
447 {"ch_log", 1, 2, FEARG_1, ret_void, f_ch_log},
448 {"ch_logfile", 1, 2, FEARG_1, ret_void, f_ch_logfile},
449 {"ch_open", 1, 2, FEARG_1, ret_channel, f_ch_open},
450 {"ch_read", 1, 2, FEARG_1, ret_string, f_ch_read},
451 {"ch_readblob", 1, 2, FEARG_1, ret_blob, f_ch_readblob},
452 {"ch_readraw", 1, 2, FEARG_1, ret_string, f_ch_readraw},
453 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, f_ch_sendexpr},
454 {"ch_sendraw", 2, 3, FEARG_1, ret_void, f_ch_sendraw},
455 {"ch_setoptions", 2, 2, FEARG_1, ret_void, f_ch_setoptions},
456 {"ch_status", 1, 2, FEARG_1, ret_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200457#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100458 {"changenr", 0, 0, 0, ret_number, f_changenr},
459 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
460 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
461 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
462 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
463 {"col", 1, 1, FEARG_1, ret_number, f_col},
464 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
465 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
466 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
467 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
468 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
469 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200470#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100471 {"cos", 1, 1, FEARG_1, ret_float, f_cos},
472 {"cosh", 1, 1, FEARG_1, ret_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100474 {"count", 2, 4, FEARG_1, ret_number, f_count},
475 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
476 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100477#ifdef MSWIN
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100478 {"debugbreak", 1, 1, FEARG_1, ret_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200479#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100480 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
481 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
482 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
483 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
484 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
485 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
486 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
487 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
488 {"environ", 0, 0, 0, ret_dict_string, f_environ},
489 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
490 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
491 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
492 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
493 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
494 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
495 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200496#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"exp", 1, 1, FEARG_1, ret_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100499 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
500 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
501 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
502 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
503 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
504 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
505 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
506 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
507 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
508 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100510 {"float2nr", 1, 1, FEARG_1, ret_number, f_float2nr},
511 {"floor", 1, 1, FEARG_1, ret_float, f_floor},
512 {"fmod", 2, 2, FEARG_1, ret_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100514 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
515 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
516 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
517 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
518 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
519 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
520 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
521 {"foreground", 0, 0, 0, ret_void, f_foreground},
522 {"funcref", 1, 3, FEARG_1, ret_partial_void, f_funcref},
523 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
524 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
525 {"get", 2, 3, FEARG_1, ret_any, f_get},
526 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
527 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
528 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
529 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
530 {"getchar", 0, 1, 0, ret_number, f_getchar},
531 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
532 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
533 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
534 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
535 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
536 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
537 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
538 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
539 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
540 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
541 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
542 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
543 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
544 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
545 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
546 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
547 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
548 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
549 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
550 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
551 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
552 {"getpid", 0, 0, 0, ret_number, f_getpid},
553 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
554 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
555 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
556 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
557 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
558 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
559 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
560 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
561 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
562 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
563 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
564 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
565 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
566 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
567 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
568 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
569 {"has", 1, 1, 0, ret_number, f_has},
570 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
571 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
572 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
573 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
574 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
575 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
576 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
577 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
578 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
579 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
580 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
581 {"hostname", 0, 0, 0, ret_string, f_hostname},
582 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
583 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
584 {"index", 2, 4, FEARG_1, ret_number, f_index},
585 {"input", 1, 3, FEARG_1, ret_string, f_input},
586 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
587 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
588 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
589 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
590 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
591 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
592 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
593 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
594 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200595#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100596 {"isinf", 1, 1, FEARG_1, ret_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200597#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100598 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200599#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100600 {"isnan", 1, 1, FEARG_1, ret_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100602 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100604 {"job_getchannel", 1, 1, FEARG_1, ret_channel, f_job_getchannel},
605 {"job_info", 0, 1, FEARG_1, ret_dict_any, f_job_info},
606 {"job_setoptions", 2, 2, FEARG_1, ret_void, f_job_setoptions},
607 {"job_start", 1, 2, FEARG_1, ret_job, f_job_start},
608 {"job_status", 1, 1, FEARG_1, ret_string, f_job_status},
609 {"job_stop", 1, 2, FEARG_1, ret_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200610#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100611 {"join", 1, 2, FEARG_1, ret_string, f_join},
612 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
613 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
614 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
615 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
616 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
617 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
618 {"len", 1, 1, FEARG_1, ret_number, f_len},
619 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
620 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
621 {"line", 1, 2, FEARG_1, ret_number, f_line},
622 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
623 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
624 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
625 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
626 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
627 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
628 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200629#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100630 {"log", 1, 1, FEARG_1, ret_float, f_log},
631 {"log10", 1, 1, FEARG_1, ret_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632#endif
633#ifdef FEAT_LUA
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100634 {"luaeval", 1, 2, FEARG_1, ret_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100636 {"map", 2, 2, FEARG_1, ret_any, f_map},
637 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
638 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
639 {"match", 2, 4, FEARG_1, ret_any, f_match},
640 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
641 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
642 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
643 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
644 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
645 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
646 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
647 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
648 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram 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;
3360 int n = FALSE;
3361 static char *(has_list[]) =
3362 {
3363#ifdef AMIGA
3364 "amiga",
3365# ifdef FEAT_ARP
3366 "arp",
3367# endif
3368#endif
3369#ifdef __BEOS__
3370 "beos",
3371#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003372#ifdef __HAIKU__
3373 "haiku",
3374#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003375#if defined(BSD) && !defined(MACOS_X)
3376 "bsd",
3377#endif
3378#ifdef hpux
3379 "hpux",
3380#endif
3381#ifdef __linux__
3382 "linux",
3383#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003384#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003385 "mac", // Mac OS X (and, once, Mac OS Classic)
3386 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003387# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003388 "macunix", // Mac OS X, with the darwin feature
3389 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003390# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391#endif
3392#ifdef __QNX__
3393 "qnx",
3394#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003395#ifdef SUN_SYSTEM
3396 "sun",
3397#else
3398 "moon",
3399#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400#ifdef UNIX
3401 "unix",
3402#endif
3403#ifdef VMS
3404 "vms",
3405#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003406#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003407 "win32",
3408#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003409#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003410 "win32unix",
3411#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003412#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003413 "win64",
3414#endif
3415#ifdef EBCDIC
3416 "ebcdic",
3417#endif
3418#ifndef CASE_INSENSITIVE_FILENAME
3419 "fname_case",
3420#endif
3421#ifdef HAVE_ACL
3422 "acl",
3423#endif
3424#ifdef FEAT_ARABIC
3425 "arabic",
3426#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003427 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003428#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003429 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003430#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003431#ifdef FEAT_AUTOSERVERNAME
3432 "autoservername",
3433#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003434#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003435 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003436# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003437 "balloon_multiline",
3438# endif
3439#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003440#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003441 "balloon_eval_term",
3442#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003443#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3444 "builtin_terms",
3445# ifdef ALL_BUILTIN_TCAPS
3446 "all_builtin_terms",
3447# endif
3448#endif
3449#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003450 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003451 || defined(FEAT_GUI_MOTIF))
3452 "browsefilter",
3453#endif
3454#ifdef FEAT_BYTEOFF
3455 "byte_offset",
3456#endif
3457#ifdef FEAT_JOB_CHANNEL
3458 "channel",
3459#endif
3460#ifdef FEAT_CINDENT
3461 "cindent",
3462#endif
3463#ifdef FEAT_CLIENTSERVER
3464 "clientserver",
3465#endif
3466#ifdef FEAT_CLIPBOARD
3467 "clipboard",
3468#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003469 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472#ifdef FEAT_CONCEAL
3473 "conceal",
3474#endif
3475#ifdef FEAT_CRYPT
3476 "cryptv",
3477 "crypt-blowfish",
3478 "crypt-blowfish2",
3479#endif
3480#ifdef FEAT_CSCOPE
3481 "cscope",
3482#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003484#ifdef CURSOR_SHAPE
3485 "cursorshape",
3486#endif
3487#ifdef DEBUG
3488 "debug",
3489#endif
3490#ifdef FEAT_CON_DIALOG
3491 "dialog_con",
3492#endif
3493#ifdef FEAT_GUI_DIALOG
3494 "dialog_gui",
3495#endif
3496#ifdef FEAT_DIFF
3497 "diff",
3498#endif
3499#ifdef FEAT_DIGRAPHS
3500 "digraphs",
3501#endif
3502#ifdef FEAT_DIRECTX
3503 "directx",
3504#endif
3505#ifdef FEAT_DND
3506 "dnd",
3507#endif
3508#ifdef FEAT_EMACS_TAGS
3509 "emacs_tags",
3510#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003511 "eval", // always present, of course!
3512 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003513#ifdef FEAT_SEARCH_EXTRA
3514 "extra_search",
3515#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003516#ifdef FEAT_SEARCHPATH
3517 "file_in_path",
3518#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003519#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520 "filterpipe",
3521#endif
3522#ifdef FEAT_FIND_ID
3523 "find_in_path",
3524#endif
3525#ifdef FEAT_FLOAT
3526 "float",
3527#endif
3528#ifdef FEAT_FOLDING
3529 "folding",
3530#endif
3531#ifdef FEAT_FOOTER
3532 "footer",
3533#endif
3534#if !defined(USE_SYSTEM) && defined(UNIX)
3535 "fork",
3536#endif
3537#ifdef FEAT_GETTEXT
3538 "gettext",
3539#endif
3540#ifdef FEAT_GUI
3541 "gui",
3542#endif
3543#ifdef FEAT_GUI_ATHENA
3544# ifdef FEAT_GUI_NEXTAW
3545 "gui_neXtaw",
3546# else
3547 "gui_athena",
3548# endif
3549#endif
3550#ifdef FEAT_GUI_GTK
3551 "gui_gtk",
3552# ifdef USE_GTK3
3553 "gui_gtk3",
3554# else
3555 "gui_gtk2",
3556# endif
3557#endif
3558#ifdef FEAT_GUI_GNOME
3559 "gui_gnome",
3560#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003561#ifdef FEAT_GUI_HAIKU
3562 "gui_haiku",
3563#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003564#ifdef FEAT_GUI_MAC
3565 "gui_mac",
3566#endif
3567#ifdef FEAT_GUI_MOTIF
3568 "gui_motif",
3569#endif
3570#ifdef FEAT_GUI_PHOTON
3571 "gui_photon",
3572#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003573#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003574 "gui_win32",
3575#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003576#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3577 "iconv",
3578#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003579 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003580#ifdef FEAT_JOB_CHANNEL
3581 "job",
3582#endif
3583#ifdef FEAT_JUMPLIST
3584 "jumplist",
3585#endif
3586#ifdef FEAT_KEYMAP
3587 "keymap",
3588#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003589 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003590#ifdef FEAT_LANGMAP
3591 "langmap",
3592#endif
3593#ifdef FEAT_LIBCALL
3594 "libcall",
3595#endif
3596#ifdef FEAT_LINEBREAK
3597 "linebreak",
3598#endif
3599#ifdef FEAT_LISP
3600 "lispindent",
3601#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003604#ifdef FEAT_LUA
3605# ifndef DYNAMIC_LUA
3606 "lua",
3607# endif
3608#endif
3609#ifdef FEAT_MENU
3610 "menu",
3611#endif
3612#ifdef FEAT_SESSION
3613 "mksession",
3614#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003615 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003616 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003617#ifdef FEAT_MOUSESHAPE
3618 "mouseshape",
3619#endif
3620#if defined(UNIX) || defined(VMS)
3621# ifdef FEAT_MOUSE_DEC
3622 "mouse_dec",
3623# endif
3624# ifdef FEAT_MOUSE_GPM
3625 "mouse_gpm",
3626# endif
3627# ifdef FEAT_MOUSE_JSB
3628 "mouse_jsbterm",
3629# endif
3630# ifdef FEAT_MOUSE_NET
3631 "mouse_netterm",
3632# endif
3633# ifdef FEAT_MOUSE_PTERM
3634 "mouse_pterm",
3635# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003636# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637 "mouse_sgr",
3638# endif
3639# ifdef FEAT_SYSMOUSE
3640 "mouse_sysmouse",
3641# endif
3642# ifdef FEAT_MOUSE_URXVT
3643 "mouse_urxvt",
3644# endif
3645# ifdef FEAT_MOUSE_XTERM
3646 "mouse_xterm",
3647# endif
3648#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003650#ifdef FEAT_MBYTE_IME
3651 "multi_byte_ime",
3652#endif
3653#ifdef FEAT_MULTI_LANG
3654 "multi_lang",
3655#endif
3656#ifdef FEAT_MZSCHEME
3657#ifndef DYNAMIC_MZSCHEME
3658 "mzscheme",
3659#endif
3660#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003661 "num64",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003662#ifdef FEAT_OLE
3663 "ole",
3664#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003665#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003666 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003667#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003668#ifdef FEAT_PATH_EXTRA
3669 "path_extra",
3670#endif
3671#ifdef FEAT_PERL
3672#ifndef DYNAMIC_PERL
3673 "perl",
3674#endif
3675#endif
3676#ifdef FEAT_PERSISTENT_UNDO
3677 "persistent_undo",
3678#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003679#if defined(FEAT_PYTHON)
3680 "python_compiled",
3681# if defined(DYNAMIC_PYTHON)
3682 "python_dynamic",
3683# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003684 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003685 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003686# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003687#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003688#if defined(FEAT_PYTHON3)
3689 "python3_compiled",
3690# if defined(DYNAMIC_PYTHON3)
3691 "python3_dynamic",
3692# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003693 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003694 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003695# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003696#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003697#ifdef FEAT_PROP_POPUP
3698 "popupwin",
3699#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003700#ifdef FEAT_POSTSCRIPT
3701 "postscript",
3702#endif
3703#ifdef FEAT_PRINTER
3704 "printer",
3705#endif
3706#ifdef FEAT_PROFILE
3707 "profile",
3708#endif
3709#ifdef FEAT_RELTIME
3710 "reltime",
3711#endif
3712#ifdef FEAT_QUICKFIX
3713 "quickfix",
3714#endif
3715#ifdef FEAT_RIGHTLEFT
3716 "rightleft",
3717#endif
3718#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3719 "ruby",
3720#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003721 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722#ifdef FEAT_CMDL_INFO
3723 "showcmd",
3724 "cmdline_info",
3725#endif
3726#ifdef FEAT_SIGNS
3727 "signs",
3728#endif
3729#ifdef FEAT_SMARTINDENT
3730 "smartindent",
3731#endif
3732#ifdef STARTUPTIME
3733 "startuptime",
3734#endif
3735#ifdef FEAT_STL_OPT
3736 "statusline",
3737#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003738#ifdef FEAT_NETBEANS_INTG
3739 "netbeans_intg",
3740#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003741#ifdef FEAT_SOUND
3742 "sound",
3743#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003744#ifdef FEAT_SPELL
3745 "spell",
3746#endif
3747#ifdef FEAT_SYN_HL
3748 "syntax",
3749#endif
3750#if defined(USE_SYSTEM) || !defined(UNIX)
3751 "system",
3752#endif
3753#ifdef FEAT_TAG_BINS
3754 "tag_binary",
3755#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003756#ifdef FEAT_TCL
3757# ifndef DYNAMIC_TCL
3758 "tcl",
3759# endif
3760#endif
3761#ifdef FEAT_TERMGUICOLORS
3762 "termguicolors",
3763#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003764#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003765 "terminal",
3766#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767#ifdef TERMINFO
3768 "terminfo",
3769#endif
3770#ifdef FEAT_TERMRESPONSE
3771 "termresponse",
3772#endif
3773#ifdef FEAT_TEXTOBJ
3774 "textobjects",
3775#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003776#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003777 "textprop",
3778#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003779#ifdef HAVE_TGETENT
3780 "tgetent",
3781#endif
3782#ifdef FEAT_TIMERS
3783 "timers",
3784#endif
3785#ifdef FEAT_TITLE
3786 "title",
3787#endif
3788#ifdef FEAT_TOOLBAR
3789 "toolbar",
3790#endif
3791#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3792 "unnamedplus",
3793#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003794 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003795 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003796#ifdef FEAT_VARTABS
3797 "vartabs",
3798#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003799 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003800#ifdef FEAT_VIMINFO
3801 "viminfo",
3802#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003803 "vimscript-1",
3804 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003805 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003806 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003807 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003808 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003809 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003810 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003811#ifdef FEAT_VTP
3812 "vtp",
3813#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003814#ifdef FEAT_WILDIGN
3815 "wildignore",
3816#endif
3817#ifdef FEAT_WILDMENU
3818 "wildmenu",
3819#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003820 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003821#ifdef FEAT_WAK
3822 "winaltkeys",
3823#endif
3824#ifdef FEAT_WRITEBACKUP
3825 "writebackup",
3826#endif
3827#ifdef FEAT_XIM
3828 "xim",
3829#endif
3830#ifdef FEAT_XFONTSET
3831 "xfontset",
3832#endif
3833#ifdef FEAT_XPM_W32
3834 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003835 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003836#else
3837# if defined(HAVE_XPM)
3838 "xpm",
3839# endif
3840#endif
3841#ifdef USE_XSMP
3842 "xsmp",
3843#endif
3844#ifdef USE_XSMP_INTERACT
3845 "xsmp_interact",
3846#endif
3847#ifdef FEAT_XCLIPBOARD
3848 "xterm_clipboard",
3849#endif
3850#ifdef FEAT_XTERM_SAVE
3851 "xterm_save",
3852#endif
3853#if defined(UNIX) && defined(FEAT_X11)
3854 "X11",
3855#endif
3856 NULL
3857 };
3858
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003859 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003860 for (i = 0; has_list[i] != NULL; ++i)
3861 if (STRICMP(name, has_list[i]) == 0)
3862 {
3863 n = TRUE;
3864 break;
3865 }
3866
3867 if (n == FALSE)
3868 {
3869 if (STRNICMP(name, "patch", 5) == 0)
3870 {
3871 if (name[5] == '-'
3872 && STRLEN(name) >= 11
3873 && vim_isdigit(name[6])
3874 && vim_isdigit(name[8])
3875 && vim_isdigit(name[10]))
3876 {
3877 int major = atoi((char *)name + 6);
3878 int minor = atoi((char *)name + 8);
3879
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003880 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003881 n = (major < VIM_VERSION_MAJOR
3882 || (major == VIM_VERSION_MAJOR
3883 && (minor < VIM_VERSION_MINOR
3884 || (minor == VIM_VERSION_MINOR
3885 && has_patch(atoi((char *)name + 10))))));
3886 }
3887 else
3888 n = has_patch(atoi((char *)name + 5));
3889 }
3890 else if (STRICMP(name, "vim_starting") == 0)
3891 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003892 else if (STRICMP(name, "ttyin") == 0)
3893 n = mch_input_isatty();
3894 else if (STRICMP(name, "ttyout") == 0)
3895 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003896 else if (STRICMP(name, "multi_byte_encoding") == 0)
3897 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003898#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003899 else if (STRICMP(name, "balloon_multiline") == 0)
3900 n = multiline_balloon_available();
3901#endif
3902#ifdef DYNAMIC_TCL
3903 else if (STRICMP(name, "tcl") == 0)
3904 n = tcl_enabled(FALSE);
3905#endif
3906#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3907 else if (STRICMP(name, "iconv") == 0)
3908 n = iconv_enabled(FALSE);
3909#endif
3910#ifdef DYNAMIC_LUA
3911 else if (STRICMP(name, "lua") == 0)
3912 n = lua_enabled(FALSE);
3913#endif
3914#ifdef DYNAMIC_MZSCHEME
3915 else if (STRICMP(name, "mzscheme") == 0)
3916 n = mzscheme_enabled(FALSE);
3917#endif
3918#ifdef DYNAMIC_RUBY
3919 else if (STRICMP(name, "ruby") == 0)
3920 n = ruby_enabled(FALSE);
3921#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003922#ifdef DYNAMIC_PYTHON
3923 else if (STRICMP(name, "python") == 0)
3924 n = python_enabled(FALSE);
3925#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003926#ifdef DYNAMIC_PYTHON3
3927 else if (STRICMP(name, "python3") == 0)
3928 n = python3_enabled(FALSE);
3929#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003930#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3931 else if (STRICMP(name, "pythonx") == 0)
3932 {
3933# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3934 if (p_pyx == 0)
3935 n = python3_enabled(FALSE) || python_enabled(FALSE);
3936 else if (p_pyx == 3)
3937 n = python3_enabled(FALSE);
3938 else if (p_pyx == 2)
3939 n = python_enabled(FALSE);
3940# elif defined(DYNAMIC_PYTHON)
3941 n = python_enabled(FALSE);
3942# elif defined(DYNAMIC_PYTHON3)
3943 n = python3_enabled(FALSE);
3944# endif
3945 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003946#endif
3947#ifdef DYNAMIC_PERL
3948 else if (STRICMP(name, "perl") == 0)
3949 n = perl_enabled(FALSE);
3950#endif
3951#ifdef FEAT_GUI
3952 else if (STRICMP(name, "gui_running") == 0)
3953 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003954# ifdef FEAT_BROWSE
3955 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003956 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003957# endif
3958#endif
3959#ifdef FEAT_SYN_HL
3960 else if (STRICMP(name, "syntax_items") == 0)
3961 n = syntax_present(curwin);
3962#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003963#ifdef FEAT_VTP
3964 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003965 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003966#endif
3967#ifdef FEAT_NETBEANS_INTG
3968 else if (STRICMP(name, "netbeans_enabled") == 0)
3969 n = netbeans_active();
3970#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003971#ifdef FEAT_MOUSE_GPM
3972 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3973 n = gpm_enabled();
3974#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003975#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003976 else if (STRICMP(name, "terminal") == 0)
3977 n = terminal_enabled();
3978#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003979#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003980 else if (STRICMP(name, "conpty") == 0)
3981 n = use_conpty();
3982#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003983#ifdef FEAT_CLIPBOARD
3984 else if (STRICMP(name, "clipboard_working") == 0)
3985 n = clip_star.available;
3986#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003987#ifdef VIMDLL
3988 else if (STRICMP(name, "filterpipe") == 0)
3989 n = gui.in_use || gui.starting;
3990#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003991 }
3992
3993 rettv->vval.v_number = n;
3994}
3995
3996/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003997 * "haslocaldir()" function
3998 */
3999 static void
4000f_haslocaldir(typval_T *argvars, typval_T *rettv)
4001{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004002 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004003 win_T *wp = NULL;
4004
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004005 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4006
4007 // Check for window-local and tab-local directories
4008 if (wp != NULL && wp->w_localdir != NULL)
4009 rettv->vval.v_number = 1;
4010 else if (tp != NULL && tp->tp_localdir != NULL)
4011 rettv->vval.v_number = 2;
4012 else
4013 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004014}
4015
4016/*
4017 * "hasmapto()" function
4018 */
4019 static void
4020f_hasmapto(typval_T *argvars, typval_T *rettv)
4021{
4022 char_u *name;
4023 char_u *mode;
4024 char_u buf[NUMBUFLEN];
4025 int abbr = FALSE;
4026
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004027 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004028 if (argvars[1].v_type == VAR_UNKNOWN)
4029 mode = (char_u *)"nvo";
4030 else
4031 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004032 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004033 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004034 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004035 }
4036
4037 if (map_to_exists(name, mode, abbr))
4038 rettv->vval.v_number = TRUE;
4039 else
4040 rettv->vval.v_number = FALSE;
4041}
4042
4043/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004044 * "highlightID(name)" function
4045 */
4046 static void
4047f_hlID(typval_T *argvars, typval_T *rettv)
4048{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004049 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004050}
4051
4052/*
4053 * "highlight_exists()" function
4054 */
4055 static void
4056f_hlexists(typval_T *argvars, typval_T *rettv)
4057{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004058 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004059}
4060
4061/*
4062 * "hostname()" function
4063 */
4064 static void
4065f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4066{
4067 char_u hostname[256];
4068
4069 mch_get_host_name(hostname, 256);
4070 rettv->v_type = VAR_STRING;
4071 rettv->vval.v_string = vim_strsave(hostname);
4072}
4073
4074/*
4075 * iconv() function
4076 */
4077 static void
4078f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4079{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004080 char_u buf1[NUMBUFLEN];
4081 char_u buf2[NUMBUFLEN];
4082 char_u *from, *to, *str;
4083 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004084
4085 rettv->v_type = VAR_STRING;
4086 rettv->vval.v_string = NULL;
4087
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004088 str = tv_get_string(&argvars[0]);
4089 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4090 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004091 vimconv.vc_type = CONV_NONE;
4092 convert_setup(&vimconv, from, to);
4093
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004094 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004095 if (vimconv.vc_type == CONV_NONE)
4096 rettv->vval.v_string = vim_strsave(str);
4097 else
4098 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4099
4100 convert_setup(&vimconv, NULL, NULL);
4101 vim_free(from);
4102 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004103}
4104
4105/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004106 * "index()" function
4107 */
4108 static void
4109f_index(typval_T *argvars, typval_T *rettv)
4110{
4111 list_T *l;
4112 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004113 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004114 long idx = 0;
4115 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004116 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004117
4118 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004119 if (argvars[0].v_type == VAR_BLOB)
4120 {
4121 typval_T tv;
4122 int start = 0;
4123
4124 if (argvars[2].v_type != VAR_UNKNOWN)
4125 {
4126 start = tv_get_number_chk(&argvars[2], &error);
4127 if (error)
4128 return;
4129 }
4130 b = argvars[0].vval.v_blob;
4131 if (b == NULL)
4132 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004133 if (start < 0)
4134 {
4135 start = blob_len(b) + start;
4136 if (start < 0)
4137 start = 0;
4138 }
4139
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004140 for (idx = start; idx < blob_len(b); ++idx)
4141 {
4142 tv.v_type = VAR_NUMBER;
4143 tv.vval.v_number = blob_get(b, idx);
4144 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4145 {
4146 rettv->vval.v_number = idx;
4147 return;
4148 }
4149 }
4150 return;
4151 }
4152 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004153 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004154 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004155 return;
4156 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004157
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004158 l = argvars[0].vval.v_list;
4159 if (l != NULL)
4160 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004161 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004162 item = l->lv_first;
4163 if (argvars[2].v_type != VAR_UNKNOWN)
4164 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004165 // Start at specified item. Use the cached index that list_find()
4166 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004167 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004168 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004169 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004170 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004171 if (error)
4172 item = NULL;
4173 }
4174
4175 for ( ; item != NULL; item = item->li_next, ++idx)
4176 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4177 {
4178 rettv->vval.v_number = idx;
4179 break;
4180 }
4181 }
4182}
4183
4184static int inputsecret_flag = 0;
4185
4186/*
4187 * "input()" function
4188 * Also handles inputsecret() when inputsecret is set.
4189 */
4190 static void
4191f_input(typval_T *argvars, typval_T *rettv)
4192{
4193 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4194}
4195
4196/*
4197 * "inputdialog()" function
4198 */
4199 static void
4200f_inputdialog(typval_T *argvars, typval_T *rettv)
4201{
4202#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004203 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004204 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4205 {
4206 char_u *message;
4207 char_u buf[NUMBUFLEN];
4208 char_u *defstr = (char_u *)"";
4209
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004210 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004211 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004212 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004213 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4214 else
4215 IObuff[0] = NUL;
4216 if (message != NULL && defstr != NULL
4217 && do_dialog(VIM_QUESTION, NULL, message,
4218 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4219 rettv->vval.v_string = vim_strsave(IObuff);
4220 else
4221 {
4222 if (message != NULL && defstr != NULL
4223 && argvars[1].v_type != VAR_UNKNOWN
4224 && argvars[2].v_type != VAR_UNKNOWN)
4225 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004226 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004227 else
4228 rettv->vval.v_string = NULL;
4229 }
4230 rettv->v_type = VAR_STRING;
4231 }
4232 else
4233#endif
4234 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4235}
4236
4237/*
4238 * "inputlist()" function
4239 */
4240 static void
4241f_inputlist(typval_T *argvars, typval_T *rettv)
4242{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004243 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004244 listitem_T *li;
4245 int selected;
4246 int mouse_used;
4247
4248#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004249 // While starting up, there is no place to enter text. When running tests
4250 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004251 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004252 return;
4253#endif
4254 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4255 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004256 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004257 return;
4258 }
4259
4260 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004261 msg_row = Rows - 1; // for when 'cmdheight' > 1
4262 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004263 msg_scroll = TRUE;
4264 msg_clr_eos();
4265
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004266 l = argvars[0].vval.v_list;
4267 range_list_materialize(l);
4268 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004269 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004270 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004271 msg_putchar('\n');
4272 }
4273
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004274 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004275 selected = prompt_for_number(&mouse_used);
4276 if (mouse_used)
4277 selected -= lines_left;
4278
4279 rettv->vval.v_number = selected;
4280}
4281
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004282static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4283
4284/*
4285 * "inputrestore()" function
4286 */
4287 static void
4288f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4289{
4290 if (ga_userinput.ga_len > 0)
4291 {
4292 --ga_userinput.ga_len;
4293 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4294 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004295 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004296 }
4297 else if (p_verbose > 1)
4298 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004299 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004300 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004301 }
4302}
4303
4304/*
4305 * "inputsave()" function
4306 */
4307 static void
4308f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4309{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004310 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004311 if (ga_grow(&ga_userinput, 1) == OK)
4312 {
4313 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4314 + ga_userinput.ga_len);
4315 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004316 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004317 }
4318 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004319 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004320}
4321
4322/*
4323 * "inputsecret()" function
4324 */
4325 static void
4326f_inputsecret(typval_T *argvars, typval_T *rettv)
4327{
4328 ++cmdline_star;
4329 ++inputsecret_flag;
4330 f_input(argvars, rettv);
4331 --cmdline_star;
4332 --inputsecret_flag;
4333}
4334
4335/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004336 * "interrupt()" function
4337 */
4338 static void
4339f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4340{
4341 got_int = TRUE;
4342}
4343
4344/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004345 * "invert(expr)" function
4346 */
4347 static void
4348f_invert(typval_T *argvars, typval_T *rettv)
4349{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004350 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004351}
4352
4353/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004354 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4355 * or it refers to a List or Dictionary that is locked.
4356 */
4357 static int
4358tv_islocked(typval_T *tv)
4359{
4360 return (tv->v_lock & VAR_LOCKED)
4361 || (tv->v_type == VAR_LIST
4362 && tv->vval.v_list != NULL
4363 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4364 || (tv->v_type == VAR_DICT
4365 && tv->vval.v_dict != NULL
4366 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4367}
4368
4369/*
4370 * "islocked()" function
4371 */
4372 static void
4373f_islocked(typval_T *argvars, typval_T *rettv)
4374{
4375 lval_T lv;
4376 char_u *end;
4377 dictitem_T *di;
4378
4379 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004380 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004381 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004382 if (end != NULL && lv.ll_name != NULL)
4383 {
4384 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004385 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004386 else
4387 {
4388 if (lv.ll_tv == NULL)
4389 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004390 di = find_var(lv.ll_name, NULL, TRUE);
4391 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004392 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004393 // Consider a variable locked when:
4394 // 1. the variable itself is locked
4395 // 2. the value of the variable is locked.
4396 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004397 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4398 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004399 }
4400 }
4401 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004402 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004403 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004404 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004405 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004406 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004407 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4408 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004409 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004410 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4411 }
4412 }
4413
4414 clear_lval(&lv);
4415}
4416
4417#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4418/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004419 * "isinf()" function
4420 */
4421 static void
4422f_isinf(typval_T *argvars, typval_T *rettv)
4423{
4424 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4425 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4426}
4427
4428/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004429 * "isnan()" function
4430 */
4431 static void
4432f_isnan(typval_T *argvars, typval_T *rettv)
4433{
4434 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4435 && isnan(argvars[0].vval.v_float);
4436}
4437#endif
4438
4439/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004440 * "last_buffer_nr()" function.
4441 */
4442 static void
4443f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4444{
4445 int n = 0;
4446 buf_T *buf;
4447
Bram Moolenaar29323592016-07-24 22:04:11 +02004448 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004449 if (n < buf->b_fnum)
4450 n = buf->b_fnum;
4451
4452 rettv->vval.v_number = n;
4453}
4454
4455/*
4456 * "len()" function
4457 */
4458 static void
4459f_len(typval_T *argvars, typval_T *rettv)
4460{
4461 switch (argvars[0].v_type)
4462 {
4463 case VAR_STRING:
4464 case VAR_NUMBER:
4465 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004466 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004467 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004468 case VAR_BLOB:
4469 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4470 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004471 case VAR_LIST:
4472 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4473 break;
4474 case VAR_DICT:
4475 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4476 break;
4477 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004478 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004479 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004480 case VAR_SPECIAL:
4481 case VAR_FLOAT:
4482 case VAR_FUNC:
4483 case VAR_PARTIAL:
4484 case VAR_JOB:
4485 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004486 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487 break;
4488 }
4489}
4490
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004491 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004492libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004493{
4494#ifdef FEAT_LIBCALL
4495 char_u *string_in;
4496 char_u **string_result;
4497 int nr_result;
4498#endif
4499
4500 rettv->v_type = type;
4501 if (type != VAR_NUMBER)
4502 rettv->vval.v_string = NULL;
4503
4504 if (check_restricted() || check_secure())
4505 return;
4506
4507#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004508 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004509 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4510 {
4511 string_in = NULL;
4512 if (argvars[2].v_type == VAR_STRING)
4513 string_in = argvars[2].vval.v_string;
4514 if (type == VAR_NUMBER)
4515 string_result = NULL;
4516 else
4517 string_result = &rettv->vval.v_string;
4518 if (mch_libcall(argvars[0].vval.v_string,
4519 argvars[1].vval.v_string,
4520 string_in,
4521 argvars[2].vval.v_number,
4522 string_result,
4523 &nr_result) == OK
4524 && type == VAR_NUMBER)
4525 rettv->vval.v_number = nr_result;
4526 }
4527#endif
4528}
4529
4530/*
4531 * "libcall()" function
4532 */
4533 static void
4534f_libcall(typval_T *argvars, typval_T *rettv)
4535{
4536 libcall_common(argvars, rettv, VAR_STRING);
4537}
4538
4539/*
4540 * "libcallnr()" function
4541 */
4542 static void
4543f_libcallnr(typval_T *argvars, typval_T *rettv)
4544{
4545 libcall_common(argvars, rettv, VAR_NUMBER);
4546}
4547
4548/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004549 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004550 */
4551 static void
4552f_line(typval_T *argvars, typval_T *rettv)
4553{
4554 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004555 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004556 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004557 int id;
4558 tabpage_T *tp;
4559 win_T *wp;
4560 win_T *save_curwin;
4561 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004562
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004563 if (argvars[1].v_type != VAR_UNKNOWN)
4564 {
4565 // use window specified in the second argument
4566 id = (int)tv_get_number(&argvars[1]);
4567 wp = win_id2wp_tp(id, &tp);
4568 if (wp != NULL && tp != NULL)
4569 {
4570 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4571 == OK)
4572 {
4573 check_cursor();
4574 fp = var2fpos(&argvars[0], TRUE, &fnum);
4575 }
4576 restore_win_noblock(save_curwin, save_curtab, TRUE);
4577 }
4578 }
4579 else
4580 // use current window
4581 fp = var2fpos(&argvars[0], TRUE, &fnum);
4582
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004583 if (fp != NULL)
4584 lnum = fp->lnum;
4585 rettv->vval.v_number = lnum;
4586}
4587
4588/*
4589 * "line2byte(lnum)" function
4590 */
4591 static void
4592f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4593{
4594#ifndef FEAT_BYTEOFF
4595 rettv->vval.v_number = -1;
4596#else
4597 linenr_T lnum;
4598
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004599 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004600 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4601 rettv->vval.v_number = -1;
4602 else
4603 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4604 if (rettv->vval.v_number >= 0)
4605 ++rettv->vval.v_number;
4606#endif
4607}
4608
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004609#ifdef FEAT_FLOAT
4610/*
4611 * "log()" function
4612 */
4613 static void
4614f_log(typval_T *argvars, typval_T *rettv)
4615{
4616 float_T f = 0.0;
4617
4618 rettv->v_type = VAR_FLOAT;
4619 if (get_float_arg(argvars, &f) == OK)
4620 rettv->vval.v_float = log(f);
4621 else
4622 rettv->vval.v_float = 0.0;
4623}
4624
4625/*
4626 * "log10()" function
4627 */
4628 static void
4629f_log10(typval_T *argvars, typval_T *rettv)
4630{
4631 float_T f = 0.0;
4632
4633 rettv->v_type = VAR_FLOAT;
4634 if (get_float_arg(argvars, &f) == OK)
4635 rettv->vval.v_float = log10(f);
4636 else
4637 rettv->vval.v_float = 0.0;
4638}
4639#endif
4640
4641#ifdef FEAT_LUA
4642/*
4643 * "luaeval()" function
4644 */
4645 static void
4646f_luaeval(typval_T *argvars, typval_T *rettv)
4647{
4648 char_u *str;
4649 char_u buf[NUMBUFLEN];
4650
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004651 if (check_restricted() || check_secure())
4652 return;
4653
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004654 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004655 do_luaeval(str, argvars + 1, rettv);
4656}
4657#endif
4658
4659/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004660 * "maparg()" function
4661 */
4662 static void
4663f_maparg(typval_T *argvars, typval_T *rettv)
4664{
4665 get_maparg(argvars, rettv, TRUE);
4666}
4667
4668/*
4669 * "mapcheck()" function
4670 */
4671 static void
4672f_mapcheck(typval_T *argvars, typval_T *rettv)
4673{
4674 get_maparg(argvars, rettv, FALSE);
4675}
4676
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004677typedef enum
4678{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004679 MATCH_END, // matchend()
4680 MATCH_MATCH, // match()
4681 MATCH_STR, // matchstr()
4682 MATCH_LIST, // matchlist()
4683 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004684} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004685
4686 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004687find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004688{
4689 char_u *str = NULL;
4690 long len = 0;
4691 char_u *expr = NULL;
4692 char_u *pat;
4693 regmatch_T regmatch;
4694 char_u patbuf[NUMBUFLEN];
4695 char_u strbuf[NUMBUFLEN];
4696 char_u *save_cpo;
4697 long start = 0;
4698 long nth = 1;
4699 colnr_T startcol = 0;
4700 int match = 0;
4701 list_T *l = NULL;
4702 listitem_T *li = NULL;
4703 long idx = 0;
4704 char_u *tofree = NULL;
4705
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004706 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004707 save_cpo = p_cpo;
4708 p_cpo = (char_u *)"";
4709
4710 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004711 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004712 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004713 // type MATCH_LIST: return empty list when there are no matches.
4714 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004715 if (rettv_list_alloc(rettv) == FAIL)
4716 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004717 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718 && (list_append_string(rettv->vval.v_list,
4719 (char_u *)"", 0) == FAIL
4720 || list_append_number(rettv->vval.v_list,
4721 (varnumber_T)-1) == FAIL
4722 || list_append_number(rettv->vval.v_list,
4723 (varnumber_T)-1) == FAIL
4724 || list_append_number(rettv->vval.v_list,
4725 (varnumber_T)-1) == FAIL))
4726 {
4727 list_free(rettv->vval.v_list);
4728 rettv->vval.v_list = NULL;
4729 goto theend;
4730 }
4731 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004732 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733 {
4734 rettv->v_type = VAR_STRING;
4735 rettv->vval.v_string = NULL;
4736 }
4737
4738 if (argvars[0].v_type == VAR_LIST)
4739 {
4740 if ((l = argvars[0].vval.v_list) == NULL)
4741 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004742 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004743 li = l->lv_first;
4744 }
4745 else
4746 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004747 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004748 len = (long)STRLEN(str);
4749 }
4750
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004751 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004752 if (pat == NULL)
4753 goto theend;
4754
4755 if (argvars[2].v_type != VAR_UNKNOWN)
4756 {
4757 int error = FALSE;
4758
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004759 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004760 if (error)
4761 goto theend;
4762 if (l != NULL)
4763 {
4764 li = list_find(l, start);
4765 if (li == NULL)
4766 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004767 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768 }
4769 else
4770 {
4771 if (start < 0)
4772 start = 0;
4773 if (start > len)
4774 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004775 // When "count" argument is there ignore matches before "start",
4776 // otherwise skip part of the string. Differs when pattern is "^"
4777 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004778 if (argvars[3].v_type != VAR_UNKNOWN)
4779 startcol = start;
4780 else
4781 {
4782 str += start;
4783 len -= start;
4784 }
4785 }
4786
4787 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004788 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004789 if (error)
4790 goto theend;
4791 }
4792
4793 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4794 if (regmatch.regprog != NULL)
4795 {
4796 regmatch.rm_ic = p_ic;
4797
4798 for (;;)
4799 {
4800 if (l != NULL)
4801 {
4802 if (li == NULL)
4803 {
4804 match = FALSE;
4805 break;
4806 }
4807 vim_free(tofree);
4808 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4809 if (str == NULL)
4810 break;
4811 }
4812
4813 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4814
4815 if (match && --nth <= 0)
4816 break;
4817 if (l == NULL && !match)
4818 break;
4819
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004820 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004821 if (l != NULL)
4822 {
4823 li = li->li_next;
4824 ++idx;
4825 }
4826 else
4827 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828 startcol = (colnr_T)(regmatch.startp[0]
4829 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004830 if (startcol > (colnr_T)len
4831 || str + startcol <= regmatch.startp[0])
4832 {
4833 match = FALSE;
4834 break;
4835 }
4836 }
4837 }
4838
4839 if (match)
4840 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004841 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004842 {
4843 listitem_T *li1 = rettv->vval.v_list->lv_first;
4844 listitem_T *li2 = li1->li_next;
4845 listitem_T *li3 = li2->li_next;
4846 listitem_T *li4 = li3->li_next;
4847
4848 vim_free(li1->li_tv.vval.v_string);
4849 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4850 (int)(regmatch.endp[0] - regmatch.startp[0]));
4851 li3->li_tv.vval.v_number =
4852 (varnumber_T)(regmatch.startp[0] - expr);
4853 li4->li_tv.vval.v_number =
4854 (varnumber_T)(regmatch.endp[0] - expr);
4855 if (l != NULL)
4856 li2->li_tv.vval.v_number = (varnumber_T)idx;
4857 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004858 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859 {
4860 int i;
4861
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004862 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004863 for (i = 0; i < NSUBEXP; ++i)
4864 {
4865 if (regmatch.endp[i] == NULL)
4866 {
4867 if (list_append_string(rettv->vval.v_list,
4868 (char_u *)"", 0) == FAIL)
4869 break;
4870 }
4871 else if (list_append_string(rettv->vval.v_list,
4872 regmatch.startp[i],
4873 (int)(regmatch.endp[i] - regmatch.startp[i]))
4874 == FAIL)
4875 break;
4876 }
4877 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004878 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004879 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004880 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004881 if (l != NULL)
4882 copy_tv(&li->li_tv, rettv);
4883 else
4884 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4885 (int)(regmatch.endp[0] - regmatch.startp[0]));
4886 }
4887 else if (l != NULL)
4888 rettv->vval.v_number = idx;
4889 else
4890 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004891 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004892 rettv->vval.v_number =
4893 (varnumber_T)(regmatch.startp[0] - str);
4894 else
4895 rettv->vval.v_number =
4896 (varnumber_T)(regmatch.endp[0] - str);
4897 rettv->vval.v_number += (varnumber_T)(str - expr);
4898 }
4899 }
4900 vim_regfree(regmatch.regprog);
4901 }
4902
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004903theend:
4904 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004905 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004906 listitem_remove(rettv->vval.v_list,
4907 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908 vim_free(tofree);
4909 p_cpo = save_cpo;
4910}
4911
4912/*
4913 * "match()" function
4914 */
4915 static void
4916f_match(typval_T *argvars, typval_T *rettv)
4917{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004918 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004919}
4920
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004921/*
4922 * "matchend()" function
4923 */
4924 static void
4925f_matchend(typval_T *argvars, typval_T *rettv)
4926{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004927 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004928}
4929
4930/*
4931 * "matchlist()" function
4932 */
4933 static void
4934f_matchlist(typval_T *argvars, typval_T *rettv)
4935{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004936 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004937}
4938
4939/*
4940 * "matchstr()" function
4941 */
4942 static void
4943f_matchstr(typval_T *argvars, typval_T *rettv)
4944{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004945 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004946}
4947
4948/*
4949 * "matchstrpos()" function
4950 */
4951 static void
4952f_matchstrpos(typval_T *argvars, typval_T *rettv)
4953{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004954 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955}
4956
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004957 static void
4958max_min(typval_T *argvars, typval_T *rettv, int domax)
4959{
4960 varnumber_T n = 0;
4961 varnumber_T i;
4962 int error = FALSE;
4963
4964 if (argvars[0].v_type == VAR_LIST)
4965 {
4966 list_T *l;
4967 listitem_T *li;
4968
4969 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004970 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004971 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004972 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004973 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004974 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4975 n = l->lv_u.nonmat.lv_start;
4976 else
4977 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4978 * l->lv_u.nonmat.lv_stride;
4979 }
4980 else
4981 {
4982 li = l->lv_first;
4983 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004984 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004985 n = tv_get_number_chk(&li->li_tv, &error);
4986 for (;;)
4987 {
4988 li = li->li_next;
4989 if (li == NULL)
4990 break;
4991 i = tv_get_number_chk(&li->li_tv, &error);
4992 if (domax ? i > n : i < n)
4993 n = i;
4994 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004995 }
4996 }
4997 }
4998 }
4999 else if (argvars[0].v_type == VAR_DICT)
5000 {
5001 dict_T *d;
5002 int first = TRUE;
5003 hashitem_T *hi;
5004 int todo;
5005
5006 d = argvars[0].vval.v_dict;
5007 if (d != NULL)
5008 {
5009 todo = (int)d->dv_hashtab.ht_used;
5010 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5011 {
5012 if (!HASHITEM_EMPTY(hi))
5013 {
5014 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005015 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005016 if (first)
5017 {
5018 n = i;
5019 first = FALSE;
5020 }
5021 else if (domax ? i > n : i < n)
5022 n = i;
5023 }
5024 }
5025 }
5026 }
5027 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005028 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005029 rettv->vval.v_number = error ? 0 : n;
5030}
5031
5032/*
5033 * "max()" function
5034 */
5035 static void
5036f_max(typval_T *argvars, typval_T *rettv)
5037{
5038 max_min(argvars, rettv, TRUE);
5039}
5040
5041/*
5042 * "min()" function
5043 */
5044 static void
5045f_min(typval_T *argvars, typval_T *rettv)
5046{
5047 max_min(argvars, rettv, FALSE);
5048}
5049
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005050#if defined(FEAT_MZSCHEME) || defined(PROTO)
5051/*
5052 * "mzeval()" function
5053 */
5054 static void
5055f_mzeval(typval_T *argvars, typval_T *rettv)
5056{
5057 char_u *str;
5058 char_u buf[NUMBUFLEN];
5059
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005060 if (check_restricted() || check_secure())
5061 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005062 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005063 do_mzeval(str, rettv);
5064}
5065
5066 void
5067mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5068{
5069 typval_T argvars[3];
5070
5071 argvars[0].v_type = VAR_STRING;
5072 argvars[0].vval.v_string = name;
5073 copy_tv(args, &argvars[1]);
5074 argvars[2].v_type = VAR_UNKNOWN;
5075 f_call(argvars, rettv);
5076 clear_tv(&argvars[1]);
5077}
5078#endif
5079
5080/*
5081 * "nextnonblank()" function
5082 */
5083 static void
5084f_nextnonblank(typval_T *argvars, typval_T *rettv)
5085{
5086 linenr_T lnum;
5087
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005088 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005089 {
5090 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5091 {
5092 lnum = 0;
5093 break;
5094 }
5095 if (*skipwhite(ml_get(lnum)) != NUL)
5096 break;
5097 }
5098 rettv->vval.v_number = lnum;
5099}
5100
5101/*
5102 * "nr2char()" function
5103 */
5104 static void
5105f_nr2char(typval_T *argvars, typval_T *rettv)
5106{
5107 char_u buf[NUMBUFLEN];
5108
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109 if (has_mbyte)
5110 {
5111 int utf8 = 0;
5112
5113 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005114 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005116 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005118 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005119 }
5120 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005121 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005122 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005123 buf[1] = NUL;
5124 }
5125 rettv->v_type = VAR_STRING;
5126 rettv->vval.v_string = vim_strsave(buf);
5127}
5128
5129/*
5130 * "or(expr, expr)" function
5131 */
5132 static void
5133f_or(typval_T *argvars, typval_T *rettv)
5134{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005135 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5136 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137}
5138
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005139#ifdef FEAT_PERL
5140/*
5141 * "perleval()" function
5142 */
5143 static void
5144f_perleval(typval_T *argvars, typval_T *rettv)
5145{
5146 char_u *str;
5147 char_u buf[NUMBUFLEN];
5148
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005149 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005150 do_perleval(str, rettv);
5151}
5152#endif
5153
5154#ifdef FEAT_FLOAT
5155/*
5156 * "pow()" function
5157 */
5158 static void
5159f_pow(typval_T *argvars, typval_T *rettv)
5160{
5161 float_T fx = 0.0, fy = 0.0;
5162
5163 rettv->v_type = VAR_FLOAT;
5164 if (get_float_arg(argvars, &fx) == OK
5165 && get_float_arg(&argvars[1], &fy) == OK)
5166 rettv->vval.v_float = pow(fx, fy);
5167 else
5168 rettv->vval.v_float = 0.0;
5169}
5170#endif
5171
5172/*
5173 * "prevnonblank()" function
5174 */
5175 static void
5176f_prevnonblank(typval_T *argvars, typval_T *rettv)
5177{
5178 linenr_T lnum;
5179
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005180 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005181 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5182 lnum = 0;
5183 else
5184 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5185 --lnum;
5186 rettv->vval.v_number = lnum;
5187}
5188
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005189// This dummy va_list is here because:
5190// - passing a NULL pointer doesn't work when va_list isn't a pointer
5191// - locally in the function results in a "used before set" warning
5192// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005193static va_list ap;
5194
5195/*
5196 * "printf()" function
5197 */
5198 static void
5199f_printf(typval_T *argvars, typval_T *rettv)
5200{
5201 char_u buf[NUMBUFLEN];
5202 int len;
5203 char_u *s;
5204 int saved_did_emsg = did_emsg;
5205 char *fmt;
5206
5207 rettv->v_type = VAR_STRING;
5208 rettv->vval.v_string = NULL;
5209
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005210 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005211 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005212 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005213 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005214 if (!did_emsg)
5215 {
5216 s = alloc(len + 1);
5217 if (s != NULL)
5218 {
5219 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005220 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5221 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005222 }
5223 }
5224 did_emsg |= saved_did_emsg;
5225}
5226
5227/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005228 * "pum_getpos()" function
5229 */
5230 static void
5231f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5232{
5233 if (rettv_dict_alloc(rettv) != OK)
5234 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005235 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005236}
5237
5238/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005239 * "pumvisible()" function
5240 */
5241 static void
5242f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5243{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244 if (pum_visible())
5245 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005246}
5247
5248#ifdef FEAT_PYTHON3
5249/*
5250 * "py3eval()" function
5251 */
5252 static void
5253f_py3eval(typval_T *argvars, typval_T *rettv)
5254{
5255 char_u *str;
5256 char_u buf[NUMBUFLEN];
5257
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005258 if (check_restricted() || check_secure())
5259 return;
5260
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005261 if (p_pyx == 0)
5262 p_pyx = 3;
5263
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005264 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005265 do_py3eval(str, rettv);
5266}
5267#endif
5268
5269#ifdef FEAT_PYTHON
5270/*
5271 * "pyeval()" function
5272 */
5273 static void
5274f_pyeval(typval_T *argvars, typval_T *rettv)
5275{
5276 char_u *str;
5277 char_u buf[NUMBUFLEN];
5278
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005279 if (check_restricted() || check_secure())
5280 return;
5281
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005282 if (p_pyx == 0)
5283 p_pyx = 2;
5284
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005285 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005286 do_pyeval(str, rettv);
5287}
5288#endif
5289
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005290#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5291/*
5292 * "pyxeval()" function
5293 */
5294 static void
5295f_pyxeval(typval_T *argvars, typval_T *rettv)
5296{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005297 if (check_restricted() || check_secure())
5298 return;
5299
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005300# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5301 init_pyxversion();
5302 if (p_pyx == 2)
5303 f_pyeval(argvars, rettv);
5304 else
5305 f_py3eval(argvars, rettv);
5306# elif defined(FEAT_PYTHON)
5307 f_pyeval(argvars, rettv);
5308# elif defined(FEAT_PYTHON3)
5309 f_py3eval(argvars, rettv);
5310# endif
5311}
5312#endif
5313
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005314static UINT32_T srand_seed_for_testing = 0;
5315static int srand_seed_for_testing_is_used = FALSE;
5316
5317 static void
5318f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5319{
5320 if (argvars[0].v_type == VAR_UNKNOWN)
5321 srand_seed_for_testing_is_used = FALSE;
5322 else
5323 {
5324 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5325 srand_seed_for_testing_is_used = TRUE;
5326 }
5327}
5328
5329 static void
5330init_srand(UINT32_T *x)
5331{
5332#ifndef MSWIN
5333 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
5334#endif
5335
5336 if (srand_seed_for_testing_is_used)
5337 {
5338 *x = srand_seed_for_testing;
5339 return;
5340 }
5341#ifndef MSWIN
5342 if (dev_urandom_state != FAIL)
5343 {
5344 int fd = open("/dev/urandom", O_RDONLY);
5345 struct {
5346 union {
5347 UINT32_T number;
5348 char bytes[sizeof(UINT32_T)];
5349 } contents;
5350 } buf;
5351
5352 // Attempt reading /dev/urandom.
5353 if (fd == -1)
5354 dev_urandom_state = FAIL;
5355 else
5356 {
5357 buf.contents.number = 0;
5358 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
5359 != sizeof(UINT32_T))
5360 dev_urandom_state = FAIL;
5361 else
5362 {
5363 dev_urandom_state = OK;
5364 *x = buf.contents.number;
5365 }
5366 close(fd);
5367 }
5368 }
5369 if (dev_urandom_state != OK)
5370 // Reading /dev/urandom doesn't work, fall back to time().
5371#endif
5372 *x = vim_time();
5373}
5374
5375#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5376#define SPLITMIX32(x, z) ( \
5377 z = (x += 0x9e3779b9), \
5378 z = (z ^ (z >> 16)) * 0x85ebca6b, \
5379 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
5380 z ^ (z >> 16) \
5381 )
5382#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
5383 result = ROTL(y * 5, 7) * 9; \
5384 t = y << 9; \
5385 z ^= x; \
5386 w ^= y; \
5387 y ^= z, x ^= w; \
5388 z ^= t; \
5389 w = ROTL(w, 11);
5390
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005391/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005392 * "rand()" function
5393 */
5394 static void
5395f_rand(typval_T *argvars, typval_T *rettv)
5396{
5397 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005398 static UINT32_T gx, gy, gz, gw;
5399 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005400 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005401 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005402
5403 if (argvars[0].v_type == VAR_UNKNOWN)
5404 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005405 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005406 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005407 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005408 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005409 init_srand(&x);
5410
5411 gx = SPLITMIX32(x, z);
5412 gy = SPLITMIX32(x, z);
5413 gz = SPLITMIX32(x, z);
5414 gw = SPLITMIX32(x, z);
5415 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005416 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005417
5418 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005419 }
5420 else if (argvars[0].v_type == VAR_LIST)
5421 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005422 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005423 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005424 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005425
5426 lx = list_find(l, 0L);
5427 ly = list_find(l, 1L);
5428 lz = list_find(l, 2L);
5429 lw = list_find(l, 3L);
5430 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5431 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5432 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5433 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5434 x = (UINT32_T)lx->li_tv.vval.v_number;
5435 y = (UINT32_T)ly->li_tv.vval.v_number;
5436 z = (UINT32_T)lz->li_tv.vval.v_number;
5437 w = (UINT32_T)lw->li_tv.vval.v_number;
5438
5439 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
5440
5441 lx->li_tv.vval.v_number = (varnumber_T)x;
5442 ly->li_tv.vval.v_number = (varnumber_T)y;
5443 lz->li_tv.vval.v_number = (varnumber_T)z;
5444 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005445 }
5446 else
5447 goto theend;
5448
5449 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005450 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005451 return;
5452
5453theend:
5454 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005455 rettv->v_type = VAR_NUMBER;
5456 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005457}
5458
5459/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005460 * "srand()" function
5461 */
5462 static void
5463f_srand(typval_T *argvars, typval_T *rettv)
5464{
5465 UINT32_T x = 0, z;
5466
5467 if (rettv_list_alloc(rettv) == FAIL)
5468 return;
5469 if (argvars[0].v_type == VAR_UNKNOWN)
5470 {
5471 init_srand(&x);
5472 }
5473 else
5474 {
5475 int error = FALSE;
5476
5477 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
5478 if (error)
5479 return;
5480 }
5481
5482 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5483 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5484 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5485 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5486}
5487
5488#undef ROTL
5489#undef SPLITMIX32
5490#undef SHUFFLE_XOSHIRO128STARSTAR
5491
5492/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005493 * "range()" function
5494 */
5495 static void
5496f_range(typval_T *argvars, typval_T *rettv)
5497{
5498 varnumber_T start;
5499 varnumber_T end;
5500 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005501 int error = FALSE;
5502
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005503 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504 if (argvars[1].v_type == VAR_UNKNOWN)
5505 {
5506 end = start - 1;
5507 start = 0;
5508 }
5509 else
5510 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005511 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005512 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005513 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005514 }
5515
5516 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005517 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005518 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005519 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005520 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005521 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005522 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005523 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005524 list_T *list = rettv->vval.v_list;
5525
5526 // Create a non-materialized list. This is much more efficient and
5527 // works with ":for". If used otherwise range_list_materialize() must
5528 // be called.
5529 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005530 list->lv_u.nonmat.lv_start = start;
5531 list->lv_u.nonmat.lv_end = end;
5532 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005533 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005534 }
5535}
5536
5537/*
5538 * If "list" is a non-materialized list then materialize it now.
5539 */
5540 void
5541range_list_materialize(list_T *list)
5542{
5543 if (list->lv_first == &range_list_item)
5544 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005545 varnumber_T start = list->lv_u.nonmat.lv_start;
5546 varnumber_T end = list->lv_u.nonmat.lv_end;
5547 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005548 varnumber_T i;
5549
5550 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005551 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005552 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005553 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005554 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5555 if (list_append_number(list, (varnumber_T)i) == FAIL)
5556 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005557 }
5558}
5559
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005560 static void
5561return_register(int regname, typval_T *rettv)
5562{
5563 char_u buf[2] = {0, 0};
5564
5565 buf[0] = (char_u)regname;
5566 rettv->v_type = VAR_STRING;
5567 rettv->vval.v_string = vim_strsave(buf);
5568}
5569
5570/*
5571 * "reg_executing()" function
5572 */
5573 static void
5574f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5575{
5576 return_register(reg_executing, rettv);
5577}
5578
5579/*
5580 * "reg_recording()" function
5581 */
5582 static void
5583f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5584{
5585 return_register(reg_recording, rettv);
5586}
5587
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005588#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005589 static void
5590make_connection(void)
5591{
5592 if (X_DISPLAY == NULL
5593# ifdef FEAT_GUI
5594 && !gui.in_use
5595# endif
5596 )
5597 {
5598 x_force_connect = TRUE;
5599 setup_term_clip();
5600 x_force_connect = FALSE;
5601 }
5602}
5603
5604 static int
5605check_connection(void)
5606{
5607 make_connection();
5608 if (X_DISPLAY == NULL)
5609 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005610 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005611 return FAIL;
5612 }
5613 return OK;
5614}
5615#endif
5616
5617#ifdef FEAT_CLIENTSERVER
5618 static void
5619remote_common(typval_T *argvars, typval_T *rettv, int expr)
5620{
5621 char_u *server_name;
5622 char_u *keys;
5623 char_u *r = NULL;
5624 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005625 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005626# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005627 HWND w;
5628# else
5629 Window w;
5630# endif
5631
5632 if (check_restricted() || check_secure())
5633 return;
5634
5635# ifdef FEAT_X11
5636 if (check_connection() == FAIL)
5637 return;
5638# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005639 if (argvars[2].v_type != VAR_UNKNOWN
5640 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005641 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005643 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005644 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005645 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005646 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005647# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005648 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005649# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005650 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5651 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005652# endif
5653 {
5654 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005655 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005656 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005657 vim_free(r);
5658 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005660 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005661 return;
5662 }
5663
5664 rettv->vval.v_string = r;
5665
5666 if (argvars[2].v_type != VAR_UNKNOWN)
5667 {
5668 dictitem_T v;
5669 char_u str[30];
5670 char_u *idvar;
5671
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005672 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005673 if (idvar != NULL && *idvar != NUL)
5674 {
5675 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5676 v.di_tv.v_type = VAR_STRING;
5677 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005678 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005679 vim_free(v.di_tv.vval.v_string);
5680 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005681 }
5682}
5683#endif
5684
5685/*
5686 * "remote_expr()" function
5687 */
5688 static void
5689f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5690{
5691 rettv->v_type = VAR_STRING;
5692 rettv->vval.v_string = NULL;
5693#ifdef FEAT_CLIENTSERVER
5694 remote_common(argvars, rettv, TRUE);
5695#endif
5696}
5697
5698/*
5699 * "remote_foreground()" function
5700 */
5701 static void
5702f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5703{
5704#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005705# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005706 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005707 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005708 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005709
5710 if (server_name != NULL)
5711 serverForeground(server_name);
5712 }
5713# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005714 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005715 argvars[1].v_type = VAR_STRING;
5716 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5717 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005718 rettv->v_type = VAR_STRING;
5719 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005720 remote_common(argvars, rettv, TRUE);
5721 vim_free(argvars[1].vval.v_string);
5722# endif
5723#endif
5724}
5725
5726 static void
5727f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5728{
5729#ifdef FEAT_CLIENTSERVER
5730 dictitem_T v;
5731 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005732# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005733 long_u n = 0;
5734# endif
5735 char_u *serverid;
5736
5737 if (check_restricted() || check_secure())
5738 {
5739 rettv->vval.v_number = -1;
5740 return;
5741 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005742 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005743 if (serverid == NULL)
5744 {
5745 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005746 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005747 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005748# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005749 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5750 if (n == 0)
5751 rettv->vval.v_number = -1;
5752 else
5753 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005754 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005755 rettv->vval.v_number = (s != NULL);
5756 }
5757# else
5758 if (check_connection() == FAIL)
5759 return;
5760
5761 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5762 serverStrToWin(serverid), &s);
5763# endif
5764
5765 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5766 {
5767 char_u *retvar;
5768
5769 v.di_tv.v_type = VAR_STRING;
5770 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005771 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005772 if (retvar != NULL)
5773 set_var(retvar, &v.di_tv, FALSE);
5774 vim_free(v.di_tv.vval.v_string);
5775 }
5776#else
5777 rettv->vval.v_number = -1;
5778#endif
5779}
5780
5781 static void
5782f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5783{
5784 char_u *r = NULL;
5785
5786#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005787 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005788
5789 if (serverid != NULL && !check_restricted() && !check_secure())
5790 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005791 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005792# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005793 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005794 long_u n = 0;
5795# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005796
5797 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005798 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005799
Bram Moolenaar4f974752019-02-17 17:44:42 +01005800# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5802 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005803 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005804 if (r == NULL)
5805# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005806 if (check_connection() == FAIL
5807 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5808 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005809# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005810 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005811 }
5812#endif
5813 rettv->v_type = VAR_STRING;
5814 rettv->vval.v_string = r;
5815}
5816
5817/*
5818 * "remote_send()" function
5819 */
5820 static void
5821f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5822{
5823 rettv->v_type = VAR_STRING;
5824 rettv->vval.v_string = NULL;
5825#ifdef FEAT_CLIENTSERVER
5826 remote_common(argvars, rettv, FALSE);
5827#endif
5828}
5829
5830/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005831 * "remote_startserver()" function
5832 */
5833 static void
5834f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5835{
5836#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005837 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005838
5839 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005840 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005841 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005842 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005843 else
5844 {
5845# ifdef FEAT_X11
5846 if (check_connection() == OK)
5847 serverRegisterName(X_DISPLAY, server);
5848# else
5849 serverSetName(server);
5850# endif
5851 }
5852#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005853 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005854#endif
5855}
5856
5857/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005858 * "rename({from}, {to})" function
5859 */
5860 static void
5861f_rename(typval_T *argvars, typval_T *rettv)
5862{
5863 char_u buf[NUMBUFLEN];
5864
5865 if (check_restricted() || check_secure())
5866 rettv->vval.v_number = -1;
5867 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005868 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5869 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005870}
5871
5872/*
5873 * "repeat()" function
5874 */
5875 static void
5876f_repeat(typval_T *argvars, typval_T *rettv)
5877{
5878 char_u *p;
5879 int n;
5880 int slen;
5881 int len;
5882 char_u *r;
5883 int i;
5884
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005885 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005886 if (argvars[0].v_type == VAR_LIST)
5887 {
5888 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5889 while (n-- > 0)
5890 if (list_extend(rettv->vval.v_list,
5891 argvars[0].vval.v_list, NULL) == FAIL)
5892 break;
5893 }
5894 else
5895 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005896 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005897 rettv->v_type = VAR_STRING;
5898 rettv->vval.v_string = NULL;
5899
5900 slen = (int)STRLEN(p);
5901 len = slen * n;
5902 if (len <= 0)
5903 return;
5904
5905 r = alloc(len + 1);
5906 if (r != NULL)
5907 {
5908 for (i = 0; i < n; i++)
5909 mch_memmove(r + i * slen, p, (size_t)slen);
5910 r[len] = NUL;
5911 }
5912
5913 rettv->vval.v_string = r;
5914 }
5915}
5916
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005917#define SP_NOMOVE 0x01 // don't move cursor
5918#define SP_REPEAT 0x02 // repeat to find outer pair
5919#define SP_RETCOUNT 0x04 // return matchcount
5920#define SP_SETPCMARK 0x08 // set previous context mark
5921#define SP_START 0x10 // accept match at start position
5922#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5923#define SP_END 0x40 // leave cursor at end of match
5924#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005925
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005926/*
5927 * Get flags for a search function.
5928 * Possibly sets "p_ws".
5929 * Returns BACKWARD, FORWARD or zero (for an error).
5930 */
5931 static int
5932get_search_arg(typval_T *varp, int *flagsp)
5933{
5934 int dir = FORWARD;
5935 char_u *flags;
5936 char_u nbuf[NUMBUFLEN];
5937 int mask;
5938
5939 if (varp->v_type != VAR_UNKNOWN)
5940 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005941 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005942 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005943 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005944 while (*flags != NUL)
5945 {
5946 switch (*flags)
5947 {
5948 case 'b': dir = BACKWARD; break;
5949 case 'w': p_ws = TRUE; break;
5950 case 'W': p_ws = FALSE; break;
5951 default: mask = 0;
5952 if (flagsp != NULL)
5953 switch (*flags)
5954 {
5955 case 'c': mask = SP_START; break;
5956 case 'e': mask = SP_END; break;
5957 case 'm': mask = SP_RETCOUNT; break;
5958 case 'n': mask = SP_NOMOVE; break;
5959 case 'p': mask = SP_SUBPAT; break;
5960 case 'r': mask = SP_REPEAT; break;
5961 case 's': mask = SP_SETPCMARK; break;
5962 case 'z': mask = SP_COLUMN; break;
5963 }
5964 if (mask == 0)
5965 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005966 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005967 dir = 0;
5968 }
5969 else
5970 *flagsp |= mask;
5971 }
5972 if (dir == 0)
5973 break;
5974 ++flags;
5975 }
5976 }
5977 return dir;
5978}
5979
5980/*
5981 * Shared by search() and searchpos() functions.
5982 */
5983 static int
5984search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5985{
5986 int flags;
5987 char_u *pat;
5988 pos_T pos;
5989 pos_T save_cursor;
5990 int save_p_ws = p_ws;
5991 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005992 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005993 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005994#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005995 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005996 long time_limit = 0;
5997#endif
5998 int options = SEARCH_KEEP;
5999 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006000 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006001
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006002 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006003 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006004 if (dir == 0)
6005 goto theend;
6006 flags = *flagsp;
6007 if (flags & SP_START)
6008 options |= SEARCH_START;
6009 if (flags & SP_END)
6010 options |= SEARCH_END;
6011 if (flags & SP_COLUMN)
6012 options |= SEARCH_COL;
6013
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006014 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006015 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6016 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006017 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 if (lnum_stop < 0)
6019 goto theend;
6020#ifdef FEAT_RELTIME
6021 if (argvars[3].v_type != VAR_UNKNOWN)
6022 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006023 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006024 if (time_limit < 0)
6025 goto theend;
6026 }
6027#endif
6028 }
6029
6030#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006031 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006032 profile_setlimit(time_limit, &tm);
6033#endif
6034
6035 /*
6036 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6037 * Check to make sure only those flags are set.
6038 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6039 * flags cannot be set. Check for that condition also.
6040 */
6041 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6042 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6043 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006044 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006045 goto theend;
6046 }
6047
6048 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006049 vim_memset(&sia, 0, sizeof(sia));
6050 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6051#ifdef FEAT_RELTIME
6052 sia.sa_tm = &tm;
6053#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006054 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006055 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006056 if (subpatnum != FAIL)
6057 {
6058 if (flags & SP_SUBPAT)
6059 retval = subpatnum;
6060 else
6061 retval = pos.lnum;
6062 if (flags & SP_SETPCMARK)
6063 setpcmark();
6064 curwin->w_cursor = pos;
6065 if (match_pos != NULL)
6066 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006067 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006068 match_pos->lnum = pos.lnum;
6069 match_pos->col = pos.col + 1;
6070 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006071 // "/$" will put the cursor after the end of the line, may need to
6072 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006073 check_cursor();
6074 }
6075
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006076 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006077 if (flags & SP_NOMOVE)
6078 curwin->w_cursor = save_cursor;
6079 else
6080 curwin->w_set_curswant = TRUE;
6081theend:
6082 p_ws = save_p_ws;
6083
6084 return retval;
6085}
6086
6087#ifdef FEAT_FLOAT
6088
6089/*
6090 * round() is not in C90, use ceil() or floor() instead.
6091 */
6092 float_T
6093vim_round(float_T f)
6094{
6095 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6096}
6097
6098/*
6099 * "round({float})" function
6100 */
6101 static void
6102f_round(typval_T *argvars, typval_T *rettv)
6103{
6104 float_T f = 0.0;
6105
6106 rettv->v_type = VAR_FLOAT;
6107 if (get_float_arg(argvars, &f) == OK)
6108 rettv->vval.v_float = vim_round(f);
6109 else
6110 rettv->vval.v_float = 0.0;
6111}
6112#endif
6113
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006114#ifdef FEAT_RUBY
6115/*
6116 * "rubyeval()" function
6117 */
6118 static void
6119f_rubyeval(typval_T *argvars, typval_T *rettv)
6120{
6121 char_u *str;
6122 char_u buf[NUMBUFLEN];
6123
6124 str = tv_get_string_buf(&argvars[0], buf);
6125 do_rubyeval(str, rettv);
6126}
6127#endif
6128
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006129/*
6130 * "screenattr()" function
6131 */
6132 static void
6133f_screenattr(typval_T *argvars, typval_T *rettv)
6134{
6135 int row;
6136 int col;
6137 int c;
6138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006139 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6140 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006141 if (row < 0 || row >= screen_Rows
6142 || col < 0 || col >= screen_Columns)
6143 c = -1;
6144 else
6145 c = ScreenAttrs[LineOffset[row] + col];
6146 rettv->vval.v_number = c;
6147}
6148
6149/*
6150 * "screenchar()" function
6151 */
6152 static void
6153f_screenchar(typval_T *argvars, typval_T *rettv)
6154{
6155 int row;
6156 int col;
6157 int off;
6158 int c;
6159
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006160 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6161 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006162 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006163 c = -1;
6164 else
6165 {
6166 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006167 if (enc_utf8 && ScreenLinesUC[off] != 0)
6168 c = ScreenLinesUC[off];
6169 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006170 c = ScreenLines[off];
6171 }
6172 rettv->vval.v_number = c;
6173}
6174
6175/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006176 * "screenchars()" function
6177 */
6178 static void
6179f_screenchars(typval_T *argvars, typval_T *rettv)
6180{
6181 int row;
6182 int col;
6183 int off;
6184 int c;
6185 int i;
6186
6187 if (rettv_list_alloc(rettv) == FAIL)
6188 return;
6189 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6190 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6191 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6192 return;
6193
6194 off = LineOffset[row] + col;
6195 if (enc_utf8 && ScreenLinesUC[off] != 0)
6196 c = ScreenLinesUC[off];
6197 else
6198 c = ScreenLines[off];
6199 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6200
6201 if (enc_utf8)
6202
6203 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6204 list_append_number(rettv->vval.v_list,
6205 (varnumber_T)ScreenLinesC[i][off]);
6206}
6207
6208/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006209 * "screencol()" function
6210 *
6211 * First column is 1 to be consistent with virtcol().
6212 */
6213 static void
6214f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6215{
6216 rettv->vval.v_number = screen_screencol() + 1;
6217}
6218
6219/*
6220 * "screenrow()" function
6221 */
6222 static void
6223f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6224{
6225 rettv->vval.v_number = screen_screenrow() + 1;
6226}
6227
6228/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006229 * "screenstring()" function
6230 */
6231 static void
6232f_screenstring(typval_T *argvars, typval_T *rettv)
6233{
6234 int row;
6235 int col;
6236 int off;
6237 int c;
6238 int i;
6239 char_u buf[MB_MAXBYTES + 1];
6240 int buflen = 0;
6241
6242 rettv->vval.v_string = NULL;
6243 rettv->v_type = VAR_STRING;
6244
6245 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6246 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6247 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6248 return;
6249
6250 off = LineOffset[row] + col;
6251 if (enc_utf8 && ScreenLinesUC[off] != 0)
6252 c = ScreenLinesUC[off];
6253 else
6254 c = ScreenLines[off];
6255 buflen += mb_char2bytes(c, buf);
6256
6257 if (enc_utf8)
6258 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6259 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6260
6261 buf[buflen] = NUL;
6262 rettv->vval.v_string = vim_strsave(buf);
6263}
6264
6265/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006266 * "search()" function
6267 */
6268 static void
6269f_search(typval_T *argvars, typval_T *rettv)
6270{
6271 int flags = 0;
6272
6273 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6274}
6275
6276/*
6277 * "searchdecl()" function
6278 */
6279 static void
6280f_searchdecl(typval_T *argvars, typval_T *rettv)
6281{
6282 int locally = 1;
6283 int thisblock = 0;
6284 int error = FALSE;
6285 char_u *name;
6286
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006287 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006288
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006289 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 if (argvars[1].v_type != VAR_UNKNOWN)
6291 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006292 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006293 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006294 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006295 }
6296 if (!error && name != NULL)
6297 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6298 locally, thisblock, SEARCH_KEEP) == FAIL;
6299}
6300
6301/*
6302 * Used by searchpair() and searchpairpos()
6303 */
6304 static int
6305searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6306{
6307 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006308 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006309 int save_p_ws = p_ws;
6310 int dir;
6311 int flags = 0;
6312 char_u nbuf1[NUMBUFLEN];
6313 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006314 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315 long lnum_stop = 0;
6316 long time_limit = 0;
6317
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006318 // Get the three pattern arguments: start, middle, end. Will result in an
6319 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006320 spat = tv_get_string_chk(&argvars[0]);
6321 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6322 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006324 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006325
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006326 // Handle the optional fourth argument: flags
6327 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006328 if (dir == 0)
6329 goto theend;
6330
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006331 // Don't accept SP_END or SP_SUBPAT.
6332 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333 if ((flags & (SP_END | SP_SUBPAT)) != 0
6334 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6335 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006336 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006337 goto theend;
6338 }
6339
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006340 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341 if (flags & SP_REPEAT)
6342 p_ws = FALSE;
6343
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006344 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345 if (argvars[3].v_type == VAR_UNKNOWN
6346 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006347 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006348 else
6349 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006350 skip = &argvars[4];
6351 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6352 && skip->v_type != VAR_STRING)
6353 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006354 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006355 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006356 goto theend;
6357 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006358 if (argvars[5].v_type != VAR_UNKNOWN)
6359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006360 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006361 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006362 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006363 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006364 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006365 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006366#ifdef FEAT_RELTIME
6367 if (argvars[6].v_type != VAR_UNKNOWN)
6368 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006369 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006370 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006371 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006372 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006374 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006375 }
6376#endif
6377 }
6378 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006379
6380 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6381 match_pos, lnum_stop, time_limit);
6382
6383theend:
6384 p_ws = save_p_ws;
6385
6386 return retval;
6387}
6388
6389/*
6390 * "searchpair()" function
6391 */
6392 static void
6393f_searchpair(typval_T *argvars, typval_T *rettv)
6394{
6395 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6396}
6397
6398/*
6399 * "searchpairpos()" function
6400 */
6401 static void
6402f_searchpairpos(typval_T *argvars, typval_T *rettv)
6403{
6404 pos_T match_pos;
6405 int lnum = 0;
6406 int col = 0;
6407
6408 if (rettv_list_alloc(rettv) == FAIL)
6409 return;
6410
6411 if (searchpair_cmn(argvars, &match_pos) > 0)
6412 {
6413 lnum = match_pos.lnum;
6414 col = match_pos.col;
6415 }
6416
6417 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6418 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6419}
6420
6421/*
6422 * Search for a start/middle/end thing.
6423 * Used by searchpair(), see its documentation for the details.
6424 * Returns 0 or -1 for no match,
6425 */
6426 long
6427do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006428 char_u *spat, // start pattern
6429 char_u *mpat, // middle pattern
6430 char_u *epat, // end pattern
6431 int dir, // BACKWARD or FORWARD
6432 typval_T *skip, // skip expression
6433 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006434 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006435 linenr_T lnum_stop, // stop at this line if not zero
6436 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006437{
6438 char_u *save_cpo;
6439 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6440 long retval = 0;
6441 pos_T pos;
6442 pos_T firstpos;
6443 pos_T foundpos;
6444 pos_T save_cursor;
6445 pos_T save_pos;
6446 int n;
6447 int r;
6448 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006449 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006450 int err;
6451 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006452#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006453 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006454#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006455
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006456 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006457 save_cpo = p_cpo;
6458 p_cpo = empty_option;
6459
6460#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006461 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 profile_setlimit(time_limit, &tm);
6463#endif
6464
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006465 // Make two search patterns: start/end (pat2, for in nested pairs) and
6466 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006467 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6468 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006469 if (pat2 == NULL || pat3 == NULL)
6470 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006471 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006472 if (*mpat == NUL)
6473 STRCPY(pat3, pat2);
6474 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006475 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 spat, epat, mpat);
6477 if (flags & SP_START)
6478 options |= SEARCH_START;
6479
Bram Moolenaar48570482017-10-30 21:48:41 +01006480 if (skip != NULL)
6481 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006482 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006483 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6484 use_skip = skip->vval.v_string != NULL
6485 && *skip->vval.v_string != NUL;
6486 }
6487
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006488 save_cursor = curwin->w_cursor;
6489 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006490 CLEAR_POS(&firstpos);
6491 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006492 pat = pat3;
6493 for (;;)
6494 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006495 searchit_arg_T sia;
6496
6497 vim_memset(&sia, 0, sizeof(sia));
6498 sia.sa_stop_lnum = lnum_stop;
6499#ifdef FEAT_RELTIME
6500 sia.sa_tm = &tm;
6501#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006502 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006503 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006504 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006505 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006506 break;
6507
6508 if (firstpos.lnum == 0)
6509 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006510 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006511 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006512 // Found the same position again. Can happen with a pattern that
6513 // has "\zs" at the end and searching backwards. Advance one
6514 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006515 if (dir == BACKWARD)
6516 decl(&pos);
6517 else
6518 incl(&pos);
6519 }
6520 foundpos = pos;
6521
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006522 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006523 options &= ~SEARCH_START;
6524
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006525 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006526 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006527 {
6528 save_pos = curwin->w_cursor;
6529 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006530 err = FALSE;
6531 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006532 curwin->w_cursor = save_pos;
6533 if (err)
6534 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006535 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006536 curwin->w_cursor = save_cursor;
6537 retval = -1;
6538 break;
6539 }
6540 if (r)
6541 continue;
6542 }
6543
6544 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6545 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006546 // Found end when searching backwards or start when searching
6547 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006548 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006549 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 }
6551 else
6552 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006553 // Found end when searching forward or start when searching
6554 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006555 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006556 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006557 }
6558
6559 if (nest == 0)
6560 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006561 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006562 if (flags & SP_RETCOUNT)
6563 ++retval;
6564 else
6565 retval = pos.lnum;
6566 if (flags & SP_SETPCMARK)
6567 setpcmark();
6568 curwin->w_cursor = pos;
6569 if (!(flags & SP_REPEAT))
6570 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006571 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006572 }
6573 }
6574
6575 if (match_pos != NULL)
6576 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006577 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006578 match_pos->lnum = curwin->w_cursor.lnum;
6579 match_pos->col = curwin->w_cursor.col + 1;
6580 }
6581
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006582 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583 if ((flags & SP_NOMOVE) || retval == 0)
6584 curwin->w_cursor = save_cursor;
6585
6586theend:
6587 vim_free(pat2);
6588 vim_free(pat3);
6589 if (p_cpo == empty_option)
6590 p_cpo = save_cpo;
6591 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006592 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006593 free_string_option(save_cpo);
6594
6595 return retval;
6596}
6597
6598/*
6599 * "searchpos()" function
6600 */
6601 static void
6602f_searchpos(typval_T *argvars, typval_T *rettv)
6603{
6604 pos_T match_pos;
6605 int lnum = 0;
6606 int col = 0;
6607 int n;
6608 int flags = 0;
6609
6610 if (rettv_list_alloc(rettv) == FAIL)
6611 return;
6612
6613 n = search_cmn(argvars, &match_pos, &flags);
6614 if (n > 0)
6615 {
6616 lnum = match_pos.lnum;
6617 col = match_pos.col;
6618 }
6619
6620 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6621 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6622 if (flags & SP_SUBPAT)
6623 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6624}
6625
6626 static void
6627f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6628{
6629#ifdef FEAT_CLIENTSERVER
6630 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006631 char_u *server = tv_get_string_chk(&argvars[0]);
6632 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006633
6634 rettv->vval.v_number = -1;
6635 if (server == NULL || reply == NULL)
6636 return;
6637 if (check_restricted() || check_secure())
6638 return;
6639# ifdef FEAT_X11
6640 if (check_connection() == FAIL)
6641 return;
6642# endif
6643
6644 if (serverSendReply(server, reply) < 0)
6645 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006646 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006647 return;
6648 }
6649 rettv->vval.v_number = 0;
6650#else
6651 rettv->vval.v_number = -1;
6652#endif
6653}
6654
6655 static void
6656f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6657{
6658 char_u *r = NULL;
6659
6660#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006661# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006662 r = serverGetVimNames();
6663# else
6664 make_connection();
6665 if (X_DISPLAY != NULL)
6666 r = serverGetVimNames(X_DISPLAY);
6667# endif
6668#endif
6669 rettv->v_type = VAR_STRING;
6670 rettv->vval.v_string = r;
6671}
6672
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006673 static void
6674f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6675{
6676 dict_T *d;
6677 dictitem_T *di;
6678 char_u *csearch;
6679
6680 if (argvars[0].v_type != VAR_DICT)
6681 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006682 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683 return;
6684 }
6685
6686 if ((d = argvars[0].vval.v_dict) != NULL)
6687 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006688 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 if (csearch != NULL)
6690 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006691 if (enc_utf8)
6692 {
6693 int pcc[MAX_MCO];
6694 int c = utfc_ptr2char(csearch, pcc);
6695
6696 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6697 }
6698 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006699 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006700 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 }
6702
6703 di = dict_find(d, (char_u *)"forward", -1);
6704 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006705 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006706 ? FORWARD : BACKWARD);
6707
6708 di = dict_find(d, (char_u *)"until", -1);
6709 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006710 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006711 }
6712}
6713
6714/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006715 * "setenv()" function
6716 */
6717 static void
6718f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6719{
6720 char_u namebuf[NUMBUFLEN];
6721 char_u valbuf[NUMBUFLEN];
6722 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6723
6724 if (argvars[1].v_type == VAR_SPECIAL
6725 && argvars[1].vval.v_number == VVAL_NULL)
6726 vim_unsetenv(name);
6727 else
6728 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6729}
6730
6731/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006732 * "setfperm({fname}, {mode})" function
6733 */
6734 static void
6735f_setfperm(typval_T *argvars, typval_T *rettv)
6736{
6737 char_u *fname;
6738 char_u modebuf[NUMBUFLEN];
6739 char_u *mode_str;
6740 int i;
6741 int mask;
6742 int mode = 0;
6743
6744 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006745 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006746 if (fname == NULL)
6747 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006748 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006749 if (mode_str == NULL)
6750 return;
6751 if (STRLEN(mode_str) != 9)
6752 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006753 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006754 return;
6755 }
6756
6757 mask = 1;
6758 for (i = 8; i >= 0; --i)
6759 {
6760 if (mode_str[i] != '-')
6761 mode |= mask;
6762 mask = mask << 1;
6763 }
6764 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6765}
6766
6767/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006768 * "setpos()" function
6769 */
6770 static void
6771f_setpos(typval_T *argvars, typval_T *rettv)
6772{
6773 pos_T pos;
6774 int fnum;
6775 char_u *name;
6776 colnr_T curswant = -1;
6777
6778 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006779 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006780 if (name != NULL)
6781 {
6782 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6783 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006784 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006785 pos.col = 0;
6786 if (name[0] == '.' && name[1] == NUL)
6787 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006788 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006789 curwin->w_cursor = pos;
6790 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006791 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006792 curwin->w_curswant = curswant - 1;
6793 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006795 check_cursor();
6796 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006797 }
6798 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6799 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006800 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006801 if (setmark_pos(name[1], &pos, fnum) == OK)
6802 rettv->vval.v_number = 0;
6803 }
6804 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006805 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006806 }
6807 }
6808}
6809
6810/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006811 * "setreg()" function
6812 */
6813 static void
6814f_setreg(typval_T *argvars, typval_T *rettv)
6815{
6816 int regname;
6817 char_u *strregname;
6818 char_u *stropt;
6819 char_u *strval;
6820 int append;
6821 char_u yank_type;
6822 long block_len;
6823
6824 block_len = -1;
6825 yank_type = MAUTO;
6826 append = FALSE;
6827
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006828 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006829 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830
6831 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006832 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006833 regname = *strregname;
6834 if (regname == 0 || regname == '@')
6835 regname = '"';
6836
6837 if (argvars[2].v_type != VAR_UNKNOWN)
6838 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006839 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006840 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006841 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006842 for (; *stropt != NUL; ++stropt)
6843 switch (*stropt)
6844 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006845 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006846 append = TRUE;
6847 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006848 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006849 yank_type = MCHAR;
6850 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006851 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006852 yank_type = MLINE;
6853 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006854 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006855 yank_type = MBLOCK;
6856 if (VIM_ISDIGIT(stropt[1]))
6857 {
6858 ++stropt;
6859 block_len = getdigits(&stropt) - 1;
6860 --stropt;
6861 }
6862 break;
6863 }
6864 }
6865
6866 if (argvars[1].v_type == VAR_LIST)
6867 {
6868 char_u **lstval;
6869 char_u **allocval;
6870 char_u buf[NUMBUFLEN];
6871 char_u **curval;
6872 char_u **curallocval;
6873 list_T *ll = argvars[1].vval.v_list;
6874 listitem_T *li;
6875 int len;
6876
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006877 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006878 len = ll == NULL ? 0 : ll->lv_len;
6879
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006880 // First half: use for pointers to result lines; second half: use for
6881 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006882 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883 if (lstval == NULL)
6884 return;
6885 curval = lstval;
6886 allocval = lstval + len + 2;
6887 curallocval = allocval;
6888
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006889 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006890 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006891 range_list_materialize(ll);
6892 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006894 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006895 if (strval == NULL)
6896 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006897 if (strval == buf)
6898 {
6899 // Need to make a copy, next tv_get_string_buf_chk() will
6900 // overwrite the string.
6901 strval = vim_strsave(buf);
6902 if (strval == NULL)
6903 goto free_lstval;
6904 *curallocval++ = strval;
6905 }
6906 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006907 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006908 }
6909 *curval++ = NULL;
6910
6911 write_reg_contents_lst(regname, lstval, -1,
6912 append, yank_type, block_len);
6913free_lstval:
6914 while (curallocval > allocval)
6915 vim_free(*--curallocval);
6916 vim_free(lstval);
6917 }
6918 else
6919 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006920 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006921 if (strval == NULL)
6922 return;
6923 write_reg_contents_ex(regname, strval, -1,
6924 append, yank_type, block_len);
6925 }
6926 rettv->vval.v_number = 0;
6927}
6928
6929/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006930 * "settagstack()" function
6931 */
6932 static void
6933f_settagstack(typval_T *argvars, typval_T *rettv)
6934{
6935 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6936 win_T *wp;
6937 dict_T *d;
6938 int action = 'r';
6939
6940 rettv->vval.v_number = -1;
6941
6942 // first argument: window number or id
6943 wp = find_win_by_nr_or_id(&argvars[0]);
6944 if (wp == NULL)
6945 return;
6946
6947 // second argument: dict with items to set in the tag stack
6948 if (argvars[1].v_type != VAR_DICT)
6949 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006950 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006951 return;
6952 }
6953 d = argvars[1].vval.v_dict;
6954 if (d == NULL)
6955 return;
6956
6957 // third argument: action - 'a' for append and 'r' for replace.
6958 // default is to replace the stack.
6959 if (argvars[2].v_type == VAR_UNKNOWN)
6960 action = 'r';
6961 else if (argvars[2].v_type == VAR_STRING)
6962 {
6963 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006964 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006965 if (actstr == NULL)
6966 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006967 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6968 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006969 action = *actstr;
6970 else
6971 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006972 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006973 return;
6974 }
6975 }
6976 else
6977 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006978 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006979 return;
6980 }
6981
6982 if (set_tagstack(wp, d, action) == OK)
6983 rettv->vval.v_number = 0;
6984}
6985
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006986#ifdef FEAT_CRYPT
6987/*
6988 * "sha256({string})" function
6989 */
6990 static void
6991f_sha256(typval_T *argvars, typval_T *rettv)
6992{
6993 char_u *p;
6994
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006995 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006996 rettv->vval.v_string = vim_strsave(
6997 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6998 rettv->v_type = VAR_STRING;
6999}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007000#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007001
7002/*
7003 * "shellescape({string})" function
7004 */
7005 static void
7006f_shellescape(typval_T *argvars, typval_T *rettv)
7007{
Bram Moolenaar20615522017-06-05 18:46:26 +02007008 int do_special = non_zero_arg(&argvars[1]);
7009
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007011 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007012 rettv->v_type = VAR_STRING;
7013}
7014
7015/*
7016 * shiftwidth() function
7017 */
7018 static void
7019f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7020{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007021 rettv->vval.v_number = 0;
7022
7023 if (argvars[0].v_type != VAR_UNKNOWN)
7024 {
7025 long col;
7026
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007027 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007028 if (col < 0)
7029 return; // type error; errmsg already given
7030#ifdef FEAT_VARTABS
7031 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7032 return;
7033#endif
7034 }
7035
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036 rettv->vval.v_number = get_sw_value(curbuf);
7037}
7038
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039#ifdef FEAT_FLOAT
7040/*
7041 * "sin()" function
7042 */
7043 static void
7044f_sin(typval_T *argvars, typval_T *rettv)
7045{
7046 float_T f = 0.0;
7047
7048 rettv->v_type = VAR_FLOAT;
7049 if (get_float_arg(argvars, &f) == OK)
7050 rettv->vval.v_float = sin(f);
7051 else
7052 rettv->vval.v_float = 0.0;
7053}
7054
7055/*
7056 * "sinh()" function
7057 */
7058 static void
7059f_sinh(typval_T *argvars, typval_T *rettv)
7060{
7061 float_T f = 0.0;
7062
7063 rettv->v_type = VAR_FLOAT;
7064 if (get_float_arg(argvars, &f) == OK)
7065 rettv->vval.v_float = sinh(f);
7066 else
7067 rettv->vval.v_float = 0.0;
7068}
7069#endif
7070
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071/*
7072 * "soundfold({word})" function
7073 */
7074 static void
7075f_soundfold(typval_T *argvars, typval_T *rettv)
7076{
7077 char_u *s;
7078
7079 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007080 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007081#ifdef FEAT_SPELL
7082 rettv->vval.v_string = eval_soundfold(s);
7083#else
7084 rettv->vval.v_string = vim_strsave(s);
7085#endif
7086}
7087
7088/*
7089 * "spellbadword()" function
7090 */
7091 static void
7092f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7093{
7094 char_u *word = (char_u *)"";
7095 hlf_T attr = HLF_COUNT;
7096 int len = 0;
7097
7098 if (rettv_list_alloc(rettv) == FAIL)
7099 return;
7100
7101#ifdef FEAT_SPELL
7102 if (argvars[0].v_type == VAR_UNKNOWN)
7103 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007104 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007105 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7106 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007107 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007108 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007109 curwin->w_set_curswant = TRUE;
7110 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007111 }
7112 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7113 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007114 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007115 int capcol = -1;
7116
7117 if (str != NULL)
7118 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007119 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007120 while (*str != NUL)
7121 {
7122 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7123 if (attr != HLF_COUNT)
7124 {
7125 word = str;
7126 break;
7127 }
7128 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007129 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007130 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131 }
7132 }
7133 }
7134#endif
7135
7136 list_append_string(rettv->vval.v_list, word, len);
7137 list_append_string(rettv->vval.v_list, (char_u *)(
7138 attr == HLF_SPB ? "bad" :
7139 attr == HLF_SPR ? "rare" :
7140 attr == HLF_SPL ? "local" :
7141 attr == HLF_SPC ? "caps" :
7142 ""), -1);
7143}
7144
7145/*
7146 * "spellsuggest()" function
7147 */
7148 static void
7149f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7150{
7151#ifdef FEAT_SPELL
7152 char_u *str;
7153 int typeerr = FALSE;
7154 int maxcount;
7155 garray_T ga;
7156 int i;
7157 listitem_T *li;
7158 int need_capital = FALSE;
7159#endif
7160
7161 if (rettv_list_alloc(rettv) == FAIL)
7162 return;
7163
7164#ifdef FEAT_SPELL
7165 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7166 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007167 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007168 if (argvars[1].v_type != VAR_UNKNOWN)
7169 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007170 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007171 if (maxcount <= 0)
7172 return;
7173 if (argvars[2].v_type != VAR_UNKNOWN)
7174 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007175 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007176 if (typeerr)
7177 return;
7178 }
7179 }
7180 else
7181 maxcount = 25;
7182
7183 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7184
7185 for (i = 0; i < ga.ga_len; ++i)
7186 {
7187 str = ((char_u **)ga.ga_data)[i];
7188
7189 li = listitem_alloc();
7190 if (li == NULL)
7191 vim_free(str);
7192 else
7193 {
7194 li->li_tv.v_type = VAR_STRING;
7195 li->li_tv.v_lock = 0;
7196 li->li_tv.vval.v_string = str;
7197 list_append(rettv->vval.v_list, li);
7198 }
7199 }
7200 ga_clear(&ga);
7201 }
7202#endif
7203}
7204
7205 static void
7206f_split(typval_T *argvars, typval_T *rettv)
7207{
7208 char_u *str;
7209 char_u *end;
7210 char_u *pat = NULL;
7211 regmatch_T regmatch;
7212 char_u patbuf[NUMBUFLEN];
7213 char_u *save_cpo;
7214 int match;
7215 colnr_T col = 0;
7216 int keepempty = FALSE;
7217 int typeerr = FALSE;
7218
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007219 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007220 save_cpo = p_cpo;
7221 p_cpo = (char_u *)"";
7222
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007223 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007224 if (argvars[1].v_type != VAR_UNKNOWN)
7225 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007226 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007227 if (pat == NULL)
7228 typeerr = TRUE;
7229 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007230 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007231 }
7232 if (pat == NULL || *pat == NUL)
7233 pat = (char_u *)"[\\x01- ]\\+";
7234
7235 if (rettv_list_alloc(rettv) == FAIL)
7236 return;
7237 if (typeerr)
7238 return;
7239
7240 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7241 if (regmatch.regprog != NULL)
7242 {
7243 regmatch.rm_ic = FALSE;
7244 while (*str != NUL || keepempty)
7245 {
7246 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007247 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007248 else
7249 match = vim_regexec_nl(&regmatch, str, col);
7250 if (match)
7251 end = regmatch.startp[0];
7252 else
7253 end = str + STRLEN(str);
7254 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7255 && *str != NUL && match && end < regmatch.endp[0]))
7256 {
7257 if (list_append_string(rettv->vval.v_list, str,
7258 (int)(end - str)) == FAIL)
7259 break;
7260 }
7261 if (!match)
7262 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007263 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007264 if (regmatch.endp[0] > str)
7265 col = 0;
7266 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007267 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007268 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007269 str = regmatch.endp[0];
7270 }
7271
7272 vim_regfree(regmatch.regprog);
7273 }
7274
7275 p_cpo = save_cpo;
7276}
7277
7278#ifdef FEAT_FLOAT
7279/*
7280 * "sqrt()" function
7281 */
7282 static void
7283f_sqrt(typval_T *argvars, typval_T *rettv)
7284{
7285 float_T f = 0.0;
7286
7287 rettv->v_type = VAR_FLOAT;
7288 if (get_float_arg(argvars, &f) == OK)
7289 rettv->vval.v_float = sqrt(f);
7290 else
7291 rettv->vval.v_float = 0.0;
7292}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007293#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007295#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007296/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007297 * "str2float()" function
7298 */
7299 static void
7300f_str2float(typval_T *argvars, typval_T *rettv)
7301{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007302 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007303 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007304
Bram Moolenaar08243d22017-01-10 16:12:29 +01007305 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007306 p = skipwhite(p + 1);
7307 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007308 if (isneg)
7309 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007310 rettv->v_type = VAR_FLOAT;
7311}
7312#endif
7313
7314/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007315 * "str2list()" function
7316 */
7317 static void
7318f_str2list(typval_T *argvars, typval_T *rettv)
7319{
7320 char_u *p;
7321 int utf8 = FALSE;
7322
7323 if (rettv_list_alloc(rettv) == FAIL)
7324 return;
7325
7326 if (argvars[1].v_type != VAR_UNKNOWN)
7327 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7328
7329 p = tv_get_string(&argvars[0]);
7330
7331 if (has_mbyte || utf8)
7332 {
7333 int (*ptr2len)(char_u *);
7334 int (*ptr2char)(char_u *);
7335
7336 if (utf8 || enc_utf8)
7337 {
7338 ptr2len = utf_ptr2len;
7339 ptr2char = utf_ptr2char;
7340 }
7341 else
7342 {
7343 ptr2len = mb_ptr2len;
7344 ptr2char = mb_ptr2char;
7345 }
7346
7347 for ( ; *p != NUL; p += (*ptr2len)(p))
7348 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7349 }
7350 else
7351 for ( ; *p != NUL; ++p)
7352 list_append_number(rettv->vval.v_list, *p);
7353}
7354
7355/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356 * "str2nr()" function
7357 */
7358 static void
7359f_str2nr(typval_T *argvars, typval_T *rettv)
7360{
7361 int base = 10;
7362 char_u *p;
7363 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007364 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007365 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007366
7367 if (argvars[1].v_type != VAR_UNKNOWN)
7368 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007369 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007370 if (base != 2 && base != 8 && base != 10 && base != 16)
7371 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007372 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007373 return;
7374 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007375 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7376 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 }
7378
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007379 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007380 isneg = (*p == '-');
7381 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 p = skipwhite(p + 1);
7383 switch (base)
7384 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007385 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7386 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7387 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007389 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7390 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007391 if (isneg)
7392 rettv->vval.v_number = -n;
7393 else
7394 rettv->vval.v_number = n;
7395
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007396}
7397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398/*
7399 * "strgetchar()" function
7400 */
7401 static void
7402f_strgetchar(typval_T *argvars, typval_T *rettv)
7403{
7404 char_u *str;
7405 int len;
7406 int error = FALSE;
7407 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007408 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007409
7410 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007411 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412 if (str == NULL)
7413 return;
7414 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007415 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007416 if (error)
7417 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007418
Bram Moolenaar13505972019-01-24 15:04:48 +01007419 while (charidx >= 0 && byteidx < len)
7420 {
7421 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007422 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007423 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7424 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007425 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007426 --charidx;
7427 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007429}
7430
7431/*
7432 * "stridx()" function
7433 */
7434 static void
7435f_stridx(typval_T *argvars, typval_T *rettv)
7436{
7437 char_u buf[NUMBUFLEN];
7438 char_u *needle;
7439 char_u *haystack;
7440 char_u *save_haystack;
7441 char_u *pos;
7442 int start_idx;
7443
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007444 needle = tv_get_string_chk(&argvars[1]);
7445 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007446 rettv->vval.v_number = -1;
7447 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007448 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007449
7450 if (argvars[2].v_type != VAR_UNKNOWN)
7451 {
7452 int error = FALSE;
7453
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007454 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007455 if (error || start_idx >= (int)STRLEN(haystack))
7456 return;
7457 if (start_idx >= 0)
7458 haystack += start_idx;
7459 }
7460
7461 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7462 if (pos != NULL)
7463 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7464}
7465
7466/*
7467 * "string()" function
7468 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007469 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007470f_string(typval_T *argvars, typval_T *rettv)
7471{
7472 char_u *tofree;
7473 char_u numbuf[NUMBUFLEN];
7474
7475 rettv->v_type = VAR_STRING;
7476 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7477 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007478 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007479 if (rettv->vval.v_string != NULL && tofree == NULL)
7480 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7481}
7482
7483/*
7484 * "strlen()" function
7485 */
7486 static void
7487f_strlen(typval_T *argvars, typval_T *rettv)
7488{
7489 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007490 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491}
7492
7493/*
7494 * "strchars()" function
7495 */
7496 static void
7497f_strchars(typval_T *argvars, typval_T *rettv)
7498{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007499 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007500 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501 varnumber_T len = 0;
7502 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007503
7504 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007505 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007506 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007507 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007508 else
7509 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007510 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7511 while (*s != NUL)
7512 {
7513 func_mb_ptr2char_adv(&s);
7514 ++len;
7515 }
7516 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007517 }
7518}
7519
7520/*
7521 * "strdisplaywidth()" function
7522 */
7523 static void
7524f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7525{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007526 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007527 int col = 0;
7528
7529 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007530 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007531
7532 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7533}
7534
7535/*
7536 * "strwidth()" function
7537 */
7538 static void
7539f_strwidth(typval_T *argvars, typval_T *rettv)
7540{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007541 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007542
Bram Moolenaar13505972019-01-24 15:04:48 +01007543 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007544}
7545
7546/*
7547 * "strcharpart()" function
7548 */
7549 static void
7550f_strcharpart(typval_T *argvars, typval_T *rettv)
7551{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007552 char_u *p;
7553 int nchar;
7554 int nbyte = 0;
7555 int charlen;
7556 int len = 0;
7557 int slen;
7558 int error = FALSE;
7559
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007560 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007561 slen = (int)STRLEN(p);
7562
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007563 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007564 if (!error)
7565 {
7566 if (nchar > 0)
7567 while (nchar > 0 && nbyte < slen)
7568 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007569 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007570 --nchar;
7571 }
7572 else
7573 nbyte = nchar;
7574 if (argvars[2].v_type != VAR_UNKNOWN)
7575 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 while (charlen > 0 && nbyte + len < slen)
7578 {
7579 int off = nbyte + len;
7580
7581 if (off < 0)
7582 len += 1;
7583 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007584 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007585 --charlen;
7586 }
7587 }
7588 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007589 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007590 }
7591
7592 /*
7593 * Only return the overlap between the specified part and the actual
7594 * string.
7595 */
7596 if (nbyte < 0)
7597 {
7598 len += nbyte;
7599 nbyte = 0;
7600 }
7601 else if (nbyte > slen)
7602 nbyte = slen;
7603 if (len < 0)
7604 len = 0;
7605 else if (nbyte + len > slen)
7606 len = slen - nbyte;
7607
7608 rettv->v_type = VAR_STRING;
7609 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610}
7611
7612/*
7613 * "strpart()" function
7614 */
7615 static void
7616f_strpart(typval_T *argvars, typval_T *rettv)
7617{
7618 char_u *p;
7619 int n;
7620 int len;
7621 int slen;
7622 int error = FALSE;
7623
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007624 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007625 slen = (int)STRLEN(p);
7626
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007627 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007628 if (error)
7629 len = 0;
7630 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007631 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007633 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007634
7635 /*
7636 * Only return the overlap between the specified part and the actual
7637 * string.
7638 */
7639 if (n < 0)
7640 {
7641 len += n;
7642 n = 0;
7643 }
7644 else if (n > slen)
7645 n = slen;
7646 if (len < 0)
7647 len = 0;
7648 else if (n + len > slen)
7649 len = slen - n;
7650
7651 rettv->v_type = VAR_STRING;
7652 rettv->vval.v_string = vim_strnsave(p + n, len);
7653}
7654
7655/*
7656 * "strridx()" function
7657 */
7658 static void
7659f_strridx(typval_T *argvars, typval_T *rettv)
7660{
7661 char_u buf[NUMBUFLEN];
7662 char_u *needle;
7663 char_u *haystack;
7664 char_u *rest;
7665 char_u *lastmatch = NULL;
7666 int haystack_len, end_idx;
7667
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007668 needle = tv_get_string_chk(&argvars[1]);
7669 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670
7671 rettv->vval.v_number = -1;
7672 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007673 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007674
7675 haystack_len = (int)STRLEN(haystack);
7676 if (argvars[2].v_type != VAR_UNKNOWN)
7677 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007678 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007679 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007680 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007681 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007682 }
7683 else
7684 end_idx = haystack_len;
7685
7686 if (*needle == NUL)
7687 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007688 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007689 lastmatch = haystack + end_idx;
7690 }
7691 else
7692 {
7693 for (rest = haystack; *rest != '\0'; ++rest)
7694 {
7695 rest = (char_u *)strstr((char *)rest, (char *)needle);
7696 if (rest == NULL || rest > haystack + end_idx)
7697 break;
7698 lastmatch = rest;
7699 }
7700 }
7701
7702 if (lastmatch == NULL)
7703 rettv->vval.v_number = -1;
7704 else
7705 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7706}
7707
7708/*
7709 * "strtrans()" function
7710 */
7711 static void
7712f_strtrans(typval_T *argvars, typval_T *rettv)
7713{
7714 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007715 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716}
7717
7718/*
7719 * "submatch()" function
7720 */
7721 static void
7722f_submatch(typval_T *argvars, typval_T *rettv)
7723{
7724 int error = FALSE;
7725 int no;
7726 int retList = 0;
7727
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007728 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007729 if (error)
7730 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007731 if (no < 0 || no >= NSUBEXP)
7732 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007733 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007734 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007735 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007736 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007737 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007738 if (error)
7739 return;
7740
7741 if (retList == 0)
7742 {
7743 rettv->v_type = VAR_STRING;
7744 rettv->vval.v_string = reg_submatch(no);
7745 }
7746 else
7747 {
7748 rettv->v_type = VAR_LIST;
7749 rettv->vval.v_list = reg_submatch_list(no);
7750 }
7751}
7752
7753/*
7754 * "substitute()" function
7755 */
7756 static void
7757f_substitute(typval_T *argvars, typval_T *rettv)
7758{
7759 char_u patbuf[NUMBUFLEN];
7760 char_u subbuf[NUMBUFLEN];
7761 char_u flagsbuf[NUMBUFLEN];
7762
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007763 char_u *str = tv_get_string_chk(&argvars[0]);
7764 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007765 char_u *sub = NULL;
7766 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007767 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007768
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007769 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7770 expr = &argvars[2];
7771 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007772 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007773
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007774 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007775 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7776 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777 rettv->vval.v_string = NULL;
7778 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007779 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780}
7781
7782/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007783 * "swapinfo(swap_filename)" function
7784 */
7785 static void
7786f_swapinfo(typval_T *argvars, typval_T *rettv)
7787{
7788 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007789 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007790}
7791
7792/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007793 * "swapname(expr)" function
7794 */
7795 static void
7796f_swapname(typval_T *argvars, typval_T *rettv)
7797{
7798 buf_T *buf;
7799
7800 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007801 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007802 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7803 || buf->b_ml.ml_mfp->mf_fname == NULL)
7804 rettv->vval.v_string = NULL;
7805 else
7806 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7807}
7808
7809/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007810 * "synID(lnum, col, trans)" function
7811 */
7812 static void
7813f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7814{
7815 int id = 0;
7816#ifdef FEAT_SYN_HL
7817 linenr_T lnum;
7818 colnr_T col;
7819 int trans;
7820 int transerr = FALSE;
7821
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007822 lnum = tv_get_lnum(argvars); // -1 on type error
7823 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007824 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007825
7826 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7827 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7828 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7829#endif
7830
7831 rettv->vval.v_number = id;
7832}
7833
7834/*
7835 * "synIDattr(id, what [, mode])" function
7836 */
7837 static void
7838f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7839{
7840 char_u *p = NULL;
7841#ifdef FEAT_SYN_HL
7842 int id;
7843 char_u *what;
7844 char_u *mode;
7845 char_u modebuf[NUMBUFLEN];
7846 int modec;
7847
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007848 id = (int)tv_get_number(&argvars[0]);
7849 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007850 if (argvars[2].v_type != VAR_UNKNOWN)
7851 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007852 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007853 modec = TOLOWER_ASC(mode[0]);
7854 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007855 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007856 }
7857 else
7858 {
7859#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7860 if (USE_24BIT)
7861 modec = 'g';
7862 else
7863#endif
7864 if (t_colors > 1)
7865 modec = 'c';
7866 else
7867 modec = 't';
7868 }
7869
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007870 switch (TOLOWER_ASC(what[0]))
7871 {
7872 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007873 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007875 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007876 p = highlight_has_attr(id, HL_BOLD, modec);
7877 break;
7878
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007879 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 p = highlight_color(id, what, modec);
7881 break;
7882
7883 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007884 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007886 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 p = highlight_has_attr(id, HL_ITALIC, modec);
7888 break;
7889
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007890 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007891 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007892 break;
7893
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007894 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007895 p = highlight_has_attr(id, HL_INVERSE, modec);
7896 break;
7897
7898 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007899 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007900 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007901 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007902 else if (TOLOWER_ASC(what[1]) == 't' &&
7903 TOLOWER_ASC(what[2]) == 'r')
7904 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007905 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007906 p = highlight_has_attr(id, HL_STANDOUT, modec);
7907 break;
7908
7909 case 'u':
7910 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007911 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007912 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7913 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007914 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007915 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7916 break;
7917 }
7918
7919 if (p != NULL)
7920 p = vim_strsave(p);
7921#endif
7922 rettv->v_type = VAR_STRING;
7923 rettv->vval.v_string = p;
7924}
7925
7926/*
7927 * "synIDtrans(id)" function
7928 */
7929 static void
7930f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7931{
7932 int id;
7933
7934#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007935 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936
7937 if (id > 0)
7938 id = syn_get_final_id(id);
7939 else
7940#endif
7941 id = 0;
7942
7943 rettv->vval.v_number = id;
7944}
7945
7946/*
7947 * "synconcealed(lnum, col)" function
7948 */
7949 static void
7950f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7951{
7952#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7953 linenr_T lnum;
7954 colnr_T col;
7955 int syntax_flags = 0;
7956 int cchar;
7957 int matchid = 0;
7958 char_u str[NUMBUFLEN];
7959#endif
7960
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007961 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007962
7963#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007964 lnum = tv_get_lnum(argvars); // -1 on type error
7965 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007966
7967 vim_memset(str, NUL, sizeof(str));
7968
7969 if (rettv_list_alloc(rettv) != FAIL)
7970 {
7971 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7972 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7973 && curwin->w_p_cole > 0)
7974 {
7975 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7976 syntax_flags = get_syntax_info(&matchid);
7977
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007978 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7980 {
7981 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007982 if (cchar == NUL && curwin->w_p_cole == 1)
7983 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984 if (cchar != NUL)
7985 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007986 if (has_mbyte)
7987 (*mb_char2bytes)(cchar, str);
7988 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007989 str[0] = cchar;
7990 }
7991 }
7992 }
7993
7994 list_append_number(rettv->vval.v_list,
7995 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007996 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997 list_append_string(rettv->vval.v_list, str, -1);
7998 list_append_number(rettv->vval.v_list, matchid);
7999 }
8000#endif
8001}
8002
8003/*
8004 * "synstack(lnum, col)" function
8005 */
8006 static void
8007f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8008{
8009#ifdef FEAT_SYN_HL
8010 linenr_T lnum;
8011 colnr_T col;
8012 int i;
8013 int id;
8014#endif
8015
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008016 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008017
8018#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008019 lnum = tv_get_lnum(argvars); // -1 on type error
8020 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008021
8022 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8023 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8024 && rettv_list_alloc(rettv) != FAIL)
8025 {
8026 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8027 for (i = 0; ; ++i)
8028 {
8029 id = syn_get_stack_item(i);
8030 if (id < 0)
8031 break;
8032 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8033 break;
8034 }
8035 }
8036#endif
8037}
8038
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039/*
8040 * "tabpagebuflist()" function
8041 */
8042 static void
8043f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8044{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008045 tabpage_T *tp;
8046 win_T *wp = NULL;
8047
8048 if (argvars[0].v_type == VAR_UNKNOWN)
8049 wp = firstwin;
8050 else
8051 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008052 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053 if (tp != NULL)
8054 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8055 }
8056 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8057 {
8058 for (; wp != NULL; wp = wp->w_next)
8059 if (list_append_number(rettv->vval.v_list,
8060 wp->w_buffer->b_fnum) == FAIL)
8061 break;
8062 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008063}
8064
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008065/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066 * "tagfiles()" function
8067 */
8068 static void
8069f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8070{
8071 char_u *fname;
8072 tagname_T tn;
8073 int first;
8074
8075 if (rettv_list_alloc(rettv) == FAIL)
8076 return;
8077 fname = alloc(MAXPATHL);
8078 if (fname == NULL)
8079 return;
8080
8081 for (first = TRUE; ; first = FALSE)
8082 if (get_tagfname(&tn, first, fname) == FAIL
8083 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8084 break;
8085 tagname_free(&tn);
8086 vim_free(fname);
8087}
8088
8089/*
8090 * "taglist()" function
8091 */
8092 static void
8093f_taglist(typval_T *argvars, typval_T *rettv)
8094{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008095 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008096 char_u *tag_pattern;
8097
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008098 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008099
8100 rettv->vval.v_number = FALSE;
8101 if (*tag_pattern == NUL)
8102 return;
8103
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008104 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008105 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008107 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008108}
8109
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008110#ifdef FEAT_FLOAT
8111/*
8112 * "tan()" function
8113 */
8114 static void
8115f_tan(typval_T *argvars, typval_T *rettv)
8116{
8117 float_T f = 0.0;
8118
8119 rettv->v_type = VAR_FLOAT;
8120 if (get_float_arg(argvars, &f) == OK)
8121 rettv->vval.v_float = tan(f);
8122 else
8123 rettv->vval.v_float = 0.0;
8124}
8125
8126/*
8127 * "tanh()" function
8128 */
8129 static void
8130f_tanh(typval_T *argvars, typval_T *rettv)
8131{
8132 float_T f = 0.0;
8133
8134 rettv->v_type = VAR_FLOAT;
8135 if (get_float_arg(argvars, &f) == OK)
8136 rettv->vval.v_float = tanh(f);
8137 else
8138 rettv->vval.v_float = 0.0;
8139}
8140#endif
8141
8142/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008143 * "tolower(string)" function
8144 */
8145 static void
8146f_tolower(typval_T *argvars, typval_T *rettv)
8147{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008149 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008150}
8151
8152/*
8153 * "toupper(string)" function
8154 */
8155 static void
8156f_toupper(typval_T *argvars, typval_T *rettv)
8157{
8158 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008159 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160}
8161
8162/*
8163 * "tr(string, fromstr, tostr)" function
8164 */
8165 static void
8166f_tr(typval_T *argvars, typval_T *rettv)
8167{
8168 char_u *in_str;
8169 char_u *fromstr;
8170 char_u *tostr;
8171 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008172 int inlen;
8173 int fromlen;
8174 int tolen;
8175 int idx;
8176 char_u *cpstr;
8177 int cplen;
8178 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 char_u buf[NUMBUFLEN];
8180 char_u buf2[NUMBUFLEN];
8181 garray_T ga;
8182
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008183 in_str = tv_get_string(&argvars[0]);
8184 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8185 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008187 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 rettv->v_type = VAR_STRING;
8189 rettv->vval.v_string = NULL;
8190 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008191 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192 ga_init2(&ga, (int)sizeof(char), 80);
8193
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008194 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008195 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008196 if (STRLEN(fromstr) != STRLEN(tostr))
8197 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008198error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008199 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008200 ga_clear(&ga);
8201 return;
8202 }
8203
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008204 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008205 while (*in_str != NUL)
8206 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008207 if (has_mbyte)
8208 {
8209 inlen = (*mb_ptr2len)(in_str);
8210 cpstr = in_str;
8211 cplen = inlen;
8212 idx = 0;
8213 for (p = fromstr; *p != NUL; p += fromlen)
8214 {
8215 fromlen = (*mb_ptr2len)(p);
8216 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8217 {
8218 for (p = tostr; *p != NUL; p += tolen)
8219 {
8220 tolen = (*mb_ptr2len)(p);
8221 if (idx-- == 0)
8222 {
8223 cplen = tolen;
8224 cpstr = p;
8225 break;
8226 }
8227 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008228 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008229 goto error;
8230 break;
8231 }
8232 ++idx;
8233 }
8234
8235 if (first && cpstr == in_str)
8236 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008237 // Check that fromstr and tostr have the same number of
8238 // (multi-byte) characters. Done only once when a character
8239 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008240 first = FALSE;
8241 for (p = tostr; *p != NUL; p += tolen)
8242 {
8243 tolen = (*mb_ptr2len)(p);
8244 --idx;
8245 }
8246 if (idx != 0)
8247 goto error;
8248 }
8249
8250 (void)ga_grow(&ga, cplen);
8251 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8252 ga.ga_len += cplen;
8253
8254 in_str += inlen;
8255 }
8256 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008258 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008259 p = vim_strchr(fromstr, *in_str);
8260 if (p != NULL)
8261 ga_append(&ga, tostr[p - fromstr]);
8262 else
8263 ga_append(&ga, *in_str);
8264 ++in_str;
8265 }
8266 }
8267
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008268 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008269 (void)ga_grow(&ga, 1);
8270 ga_append(&ga, NUL);
8271
8272 rettv->vval.v_string = ga.ga_data;
8273}
8274
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008275/*
8276 * "trim({expr})" function
8277 */
8278 static void
8279f_trim(typval_T *argvars, typval_T *rettv)
8280{
8281 char_u buf1[NUMBUFLEN];
8282 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008283 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008284 char_u *mask = NULL;
8285 char_u *tail;
8286 char_u *prev;
8287 char_u *p;
8288 int c1;
8289
8290 rettv->v_type = VAR_STRING;
8291 if (head == NULL)
8292 {
8293 rettv->vval.v_string = NULL;
8294 return;
8295 }
8296
8297 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008298 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008299
8300 while (*head != NUL)
8301 {
8302 c1 = PTR2CHAR(head);
8303 if (mask == NULL)
8304 {
8305 if (c1 > ' ' && c1 != 0xa0)
8306 break;
8307 }
8308 else
8309 {
8310 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8311 if (c1 == PTR2CHAR(p))
8312 break;
8313 if (*p == NUL)
8314 break;
8315 }
8316 MB_PTR_ADV(head);
8317 }
8318
8319 for (tail = head + STRLEN(head); tail > head; tail = prev)
8320 {
8321 prev = tail;
8322 MB_PTR_BACK(head, prev);
8323 c1 = PTR2CHAR(prev);
8324 if (mask == NULL)
8325 {
8326 if (c1 > ' ' && c1 != 0xa0)
8327 break;
8328 }
8329 else
8330 {
8331 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8332 if (c1 == PTR2CHAR(p))
8333 break;
8334 if (*p == NUL)
8335 break;
8336 }
8337 }
8338 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8339}
8340
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008341#ifdef FEAT_FLOAT
8342/*
8343 * "trunc({float})" function
8344 */
8345 static void
8346f_trunc(typval_T *argvars, typval_T *rettv)
8347{
8348 float_T f = 0.0;
8349
8350 rettv->v_type = VAR_FLOAT;
8351 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008352 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008353 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8354 else
8355 rettv->vval.v_float = 0.0;
8356}
8357#endif
8358
8359/*
8360 * "type(expr)" function
8361 */
8362 static void
8363f_type(typval_T *argvars, typval_T *rettv)
8364{
8365 int n = -1;
8366
8367 switch (argvars[0].v_type)
8368 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008369 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8370 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008371 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008372 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8373 case VAR_LIST: n = VAR_TYPE_LIST; break;
8374 case VAR_DICT: n = VAR_TYPE_DICT; break;
8375 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8376 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8377 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008378 case VAR_JOB: n = VAR_TYPE_JOB; break;
8379 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008380 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008381 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008382 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008383 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008384 n = -1;
8385 break;
8386 }
8387 rettv->vval.v_number = n;
8388}
8389
8390/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008391 * "virtcol(string)" function
8392 */
8393 static void
8394f_virtcol(typval_T *argvars, typval_T *rettv)
8395{
8396 colnr_T vcol = 0;
8397 pos_T *fp;
8398 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008399 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008400
8401 fp = var2fpos(&argvars[0], FALSE, &fnum);
8402 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8403 && fnum == curbuf->b_fnum)
8404 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008405 // Limit the column to a valid value, getvvcol() doesn't check.
8406 if (fp->col < 0)
8407 fp->col = 0;
8408 else
8409 {
8410 len = (int)STRLEN(ml_get(fp->lnum));
8411 if (fp->col > len)
8412 fp->col = len;
8413 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008414 getvvcol(curwin, fp, NULL, NULL, &vcol);
8415 ++vcol;
8416 }
8417
8418 rettv->vval.v_number = vcol;
8419}
8420
8421/*
8422 * "visualmode()" function
8423 */
8424 static void
8425f_visualmode(typval_T *argvars, typval_T *rettv)
8426{
8427 char_u str[2];
8428
8429 rettv->v_type = VAR_STRING;
8430 str[0] = curbuf->b_visual_mode_eval;
8431 str[1] = NUL;
8432 rettv->vval.v_string = vim_strsave(str);
8433
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008434 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008435 if (non_zero_arg(&argvars[0]))
8436 curbuf->b_visual_mode_eval = NUL;
8437}
8438
8439/*
8440 * "wildmenumode()" function
8441 */
8442 static void
8443f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8444{
8445#ifdef FEAT_WILDMENU
8446 if (wild_menu_showing)
8447 rettv->vval.v_number = 1;
8448#endif
8449}
8450
8451/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008452 * "windowsversion()" function
8453 */
8454 static void
8455f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8456{
8457 rettv->v_type = VAR_STRING;
8458 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8459}
8460
8461/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008462 * "wordcount()" function
8463 */
8464 static void
8465f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8466{
8467 if (rettv_dict_alloc(rettv) == FAIL)
8468 return;
8469 cursor_pos_info(rettv->vval.v_dict);
8470}
8471
8472/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008473 * "xor(expr, expr)" function
8474 */
8475 static void
8476f_xor(typval_T *argvars, typval_T *rettv)
8477{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008478 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8479 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480}
8481
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008482#endif // FEAT_EVAL