blob: 5db6718fb6e64ab11f770f20c9119775d84ad573 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020023#ifdef FEAT_FLOAT
24static void f_abs(typval_T *argvars, typval_T *rettv);
25static void f_acos(typval_T *argvars, typval_T *rettv);
26#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028#ifdef FEAT_FLOAT
29static void f_asin(typval_T *argvars, typval_T *rettv);
30static void f_atan(typval_T *argvars, typval_T *rettv);
31static void f_atan2(typval_T *argvars, typval_T *rettv);
32#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010033#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020034static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010035static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010036# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010037static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010038# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020040static void f_byte2line(typval_T *argvars, typval_T *rettv);
41static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
42static void f_byteidx(typval_T *argvars, typval_T *rettv);
43static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
44static void f_call(typval_T *argvars, typval_T *rettv);
45#ifdef FEAT_FLOAT
46static void f_ceil(typval_T *argvars, typval_T *rettv);
47#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020048static void f_changenr(typval_T *argvars, typval_T *rettv);
49static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_confirm(typval_T *argvars, typval_T *rettv);
52static void f_copy(typval_T *argvars, typval_T *rettv);
53#ifdef FEAT_FLOAT
54static void f_cos(typval_T *argvars, typval_T *rettv);
55static void f_cosh(typval_T *argvars, typval_T *rettv);
56#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020057static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010058#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020059static void f_debugbreak(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4132eb52020-02-14 16:53:00 +010063static void f_echoraw(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020064static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020065static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_escape(typval_T *argvars, typval_T *rettv);
67static void f_eval(typval_T *argvars, typval_T *rettv);
68static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_exists(typval_T *argvars, typval_T *rettv);
71#ifdef FEAT_FLOAT
72static void f_exp(typval_T *argvars, typval_T *rettv);
73#endif
74static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020075static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020076static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020077#ifdef FEAT_FLOAT
78static void f_float2nr(typval_T *argvars, typval_T *rettv);
79static void f_floor(typval_T *argvars, typval_T *rettv);
80static void f_fmod(typval_T *argvars, typval_T *rettv);
81#endif
82static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020083static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020084static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_function(typval_T *argvars, typval_T *rettv);
86static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
87static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010088static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020090static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020091static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010092static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getpid(typval_T *argvars, typval_T *rettv);
94static void f_getcurpos(typval_T *argvars, typval_T *rettv);
95static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getreg(typval_T *argvars, typval_T *rettv);
97static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010098static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020099static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
100static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_hlID(typval_T *argvars, typval_T *rettv);
102static void f_hlexists(typval_T *argvars, typval_T *rettv);
103static void f_hostname(typval_T *argvars, typval_T *rettv);
104static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_index(typval_T *argvars, typval_T *rettv);
106static void f_input(typval_T *argvars, typval_T *rettv);
107static void f_inputdialog(typval_T *argvars, typval_T *rettv);
108static void f_inputlist(typval_T *argvars, typval_T *rettv);
109static void f_inputrestore(typval_T *argvars, typval_T *rettv);
110static void f_inputsave(typval_T *argvars, typval_T *rettv);
111static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100112static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200113static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200114static void f_islocked(typval_T *argvars, typval_T *rettv);
115#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200116static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_isnan(typval_T *argvars, typval_T *rettv);
118#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
120static void f_len(typval_T *argvars, typval_T *rettv);
121static void f_libcall(typval_T *argvars, typval_T *rettv);
122static void f_libcallnr(typval_T *argvars, typval_T *rettv);
123static void f_line(typval_T *argvars, typval_T *rettv);
124static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125#ifdef FEAT_FLOAT
126static void f_log(typval_T *argvars, typval_T *rettv);
127static void f_log10(typval_T *argvars, typval_T *rettv);
128#endif
129#ifdef FEAT_LUA
130static void f_luaeval(typval_T *argvars, typval_T *rettv);
131#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_maparg(typval_T *argvars, typval_T *rettv);
133static void f_mapcheck(typval_T *argvars, typval_T *rettv);
134static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_matchend(typval_T *argvars, typval_T *rettv);
136static void f_matchlist(typval_T *argvars, typval_T *rettv);
137static void f_matchstr(typval_T *argvars, typval_T *rettv);
138static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
139static void f_max(typval_T *argvars, typval_T *rettv);
140static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141#ifdef FEAT_MZSCHEME
142static void f_mzeval(typval_T *argvars, typval_T *rettv);
143#endif
144static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
145static void f_nr2char(typval_T *argvars, typval_T *rettv);
146static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_PERL
148static void f_perleval(typval_T *argvars, typval_T *rettv);
149#endif
150#ifdef FEAT_FLOAT
151static void f_pow(typval_T *argvars, typval_T *rettv);
152#endif
153static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
154static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200155static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156static void f_pumvisible(typval_T *argvars, typval_T *rettv);
157#ifdef FEAT_PYTHON3
158static void f_py3eval(typval_T *argvars, typval_T *rettv);
159#endif
160#ifdef FEAT_PYTHON
161static void f_pyeval(typval_T *argvars, typval_T *rettv);
162#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100163#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
164static void f_pyxeval(typval_T *argvars, typval_T *rettv);
165#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100166static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100167static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200169static void f_reg_executing(typval_T *argvars, typval_T *rettv);
170static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_remote_expr(typval_T *argvars, typval_T *rettv);
172static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
173static void f_remote_peek(typval_T *argvars, typval_T *rettv);
174static void f_remote_read(typval_T *argvars, typval_T *rettv);
175static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100176static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_rename(typval_T *argvars, typval_T *rettv);
178static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179#ifdef FEAT_FLOAT
180static void f_round(typval_T *argvars, typval_T *rettv);
181#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100182#ifdef FEAT_RUBY
183static void f_rubyeval(typval_T *argvars, typval_T *rettv);
184#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_screenattr(typval_T *argvars, typval_T *rettv);
186static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100187static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_screencol(typval_T *argvars, typval_T *rettv);
189static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100190static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_search(typval_T *argvars, typval_T *rettv);
192static void f_searchdecl(typval_T *argvars, typval_T *rettv);
193static void f_searchpair(typval_T *argvars, typval_T *rettv);
194static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
195static void f_searchpos(typval_T *argvars, typval_T *rettv);
196static void f_server2client(typval_T *argvars, typval_T *rettv);
197static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200199static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100203static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204#ifdef FEAT_CRYPT
205static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200206#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_shellescape(typval_T *argvars, typval_T *rettv);
208static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209#ifdef FEAT_FLOAT
210static void f_sin(typval_T *argvars, typval_T *rettv);
211static void f_sinh(typval_T *argvars, typval_T *rettv);
212#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_soundfold(typval_T *argvars, typval_T *rettv);
214static void f_spellbadword(typval_T *argvars, typval_T *rettv);
215static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
216static void f_split(typval_T *argvars, typval_T *rettv);
217#ifdef FEAT_FLOAT
218static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100219#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100220static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100221#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_str2float(typval_T *argvars, typval_T *rettv);
223#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200224static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_str2nr(typval_T *argvars, typval_T *rettv);
226static void f_strchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200227static void f_strgetchar(typval_T *argvars, typval_T *rettv);
228static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200229static void f_strlen(typval_T *argvars, typval_T *rettv);
230static void f_strcharpart(typval_T *argvars, typval_T *rettv);
231static void f_strpart(typval_T *argvars, typval_T *rettv);
232static void f_strridx(typval_T *argvars, typval_T *rettv);
233static void f_strtrans(typval_T *argvars, typval_T *rettv);
234static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
235static void f_strwidth(typval_T *argvars, typval_T *rettv);
236static void f_submatch(typval_T *argvars, typval_T *rettv);
237static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200238static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200239static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_synID(typval_T *argvars, typval_T *rettv);
241static void f_synIDattr(typval_T *argvars, typval_T *rettv);
242static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
243static void f_synstack(typval_T *argvars, typval_T *rettv);
244static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_taglist(typval_T *argvars, typval_T *rettv);
247static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248#ifdef FEAT_FLOAT
249static void f_tan(typval_T *argvars, typval_T *rettv);
250static void f_tanh(typval_T *argvars, typval_T *rettv);
251#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200252static void f_tolower(typval_T *argvars, typval_T *rettv);
253static void f_toupper(typval_T *argvars, typval_T *rettv);
254static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100255static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256#ifdef FEAT_FLOAT
257static void f_trunc(typval_T *argvars, typval_T *rettv);
258#endif
259static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_virtcol(typval_T *argvars, typval_T *rettv);
261static void f_visualmode(typval_T *argvars, typval_T *rettv);
262static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100263static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264static void f_wordcount(typval_T *argvars, typval_T *rettv);
265static void f_xor(typval_T *argvars, typval_T *rettv);
266
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100267
268 static type_T *
269ret_void(int argcount UNUSED, type_T **argtypes UNUSED)
270{
271 return &t_void;
272}
273 static type_T *
274ret_any(int argcount UNUSED, type_T **argtypes UNUSED)
275{
276 return &t_any;
277}
278 static type_T *
279ret_number(int argcount UNUSED, type_T **argtypes UNUSED)
280{
281 return &t_number;
282}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100283#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100284 static type_T *
285ret_float(int argcount UNUSED, type_T **argtypes UNUSED)
286{
287 return &t_float;
288}
Bram Moolenaar815eb832020-03-01 20:34:26 +0100289#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100290 static type_T *
291ret_string(int argcount UNUSED, type_T **argtypes UNUSED)
292{
293 return &t_string;
294}
295 static type_T * ret_list_any(int argcount UNUSED, type_T **argtypes UNUSED)
296{
297 return &t_list_any;
298}
299 static type_T *
300ret_list_number(int argcount UNUSED, type_T **argtypes UNUSED)
301{
302 return &t_list_number;
303}
304 static type_T *
305ret_list_string(int argcount UNUSED, type_T **argtypes UNUSED)
306{
307 return &t_list_string;
308}
309 static type_T *
310ret_list_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
311{
312 return &t_list_dict_any;
313}
314 static type_T *
315ret_dict_any(int argcount UNUSED, type_T **argtypes UNUSED)
316{
317 return &t_dict_any;
318}
319 static type_T *
320ret_dict_number(int argcount UNUSED, type_T **argtypes UNUSED)
321{
322 return &t_dict_number;
323}
324 static type_T *
325ret_dict_string(int argcount UNUSED, type_T **argtypes UNUSED)
326{
327 return &t_dict_string;
328}
329 static type_T *
330ret_blob(int argcount UNUSED, type_T **argtypes UNUSED)
331{
332 return &t_blob;
333}
334 static type_T *
335ret_partial_void(int argcount UNUSED, type_T **argtypes UNUSED)
336{
337 return &t_partial_void;
338}
339#ifdef FEAT_JOB_CHANNEL
340 static type_T *
341ret_channel(int argcount UNUSED, type_T **argtypes UNUSED)
342{
343 return &t_channel;
344}
345 static type_T *
346ret_job(int argcount UNUSED, type_T **argtypes UNUSED)
347{
348 return &t_job;
349}
350#endif
351
352static type_T *ret_f_function(int argcount, type_T **argtypes);
353
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200354/*
355 * Array with names and number of arguments of all internal functions
356 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
357 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200358typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200360 char *f_name; // function name
361 char f_min_argc; // minimal number of arguments
362 char f_max_argc; // maximal number of arguments
363 char f_argtype; // for method: FEARG_ values
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100364 type_T *(*f_retfunc)(int argcount, type_T **argtypes);
365 // return type function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200367 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200368} funcentry_T;
369
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200370// values for f_argtype; zero means it cannot be used as a method
371#define FEARG_1 1 // base is the first argument
372#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200373#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200374#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200375#define FEARG_LAST 9 // base is the last argument
376
Bram Moolenaarac92e252019-08-03 21:58:38 +0200377static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378{
379#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100380 {"abs", 1, 1, FEARG_1, ret_any, f_abs},
381 {"acos", 1, 1, FEARG_1, ret_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200382#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100383 {"add", 2, 2, FEARG_1, ret_any, f_add},
384 {"and", 2, 2, FEARG_1, ret_number, f_and},
385 {"append", 2, 2, FEARG_LAST, ret_number, f_append},
386 {"appendbufline", 3, 3, FEARG_LAST, ret_number, f_appendbufline},
387 {"argc", 0, 1, 0, ret_number, f_argc},
388 {"argidx", 0, 0, 0, ret_number, f_argidx},
389 {"arglistid", 0, 2, 0, ret_number, f_arglistid},
390 {"argv", 0, 2, 0, ret_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100392 {"asin", 1, 1, FEARG_1, ret_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200393#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100394 {"assert_beeps", 1, 2, FEARG_1, ret_number, f_assert_beeps},
395 {"assert_equal", 2, 3, FEARG_2, ret_number, f_assert_equal},
396 {"assert_equalfile", 2, 2, FEARG_1, ret_number, f_assert_equalfile},
397 {"assert_exception", 1, 2, 0, ret_number, f_assert_exception},
398 {"assert_fails", 1, 3, FEARG_1, ret_number, f_assert_fails},
399 {"assert_false", 1, 2, FEARG_1, ret_number, f_assert_false},
400 {"assert_inrange", 3, 4, FEARG_3, ret_number, f_assert_inrange},
401 {"assert_match", 2, 3, FEARG_2, ret_number, f_assert_match},
402 {"assert_notequal", 2, 3, FEARG_2, ret_number, f_assert_notequal},
403 {"assert_notmatch", 2, 3, FEARG_2, ret_number, f_assert_notmatch},
404 {"assert_report", 1, 1, FEARG_1, ret_number, f_assert_report},
405 {"assert_true", 1, 2, FEARG_1, ret_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200406#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100407 {"atan", 1, 1, FEARG_1, ret_float, f_atan},
408 {"atan2", 2, 2, FEARG_1, ret_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100410#ifdef FEAT_BEVAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100411 {"balloon_gettext", 0, 0, 0, ret_string, f_balloon_gettext},
412 {"balloon_show", 1, 1, FEARG_1, ret_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100413# if defined(FEAT_BEVAL_TERM)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100414 {"balloon_split", 1, 1, FEARG_1, ret_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100415# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100416#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100417 {"browse", 4, 4, 0, ret_string, f_browse},
418 {"browsedir", 2, 2, 0, ret_string, f_browsedir},
419 {"bufadd", 1, 1, FEARG_1, ret_number, f_bufadd},
420 {"bufexists", 1, 1, FEARG_1, ret_number, f_bufexists},
421 {"buffer_exists", 1, 1, FEARG_1, ret_number, f_bufexists}, // obsolete
422 {"buffer_name", 0, 1, FEARG_1, ret_string, f_bufname}, // obsolete
423 {"buffer_number", 0, 1, FEARG_1, ret_number, f_bufnr}, // obsolete
424 {"buflisted", 1, 1, FEARG_1, ret_number, f_buflisted},
425 {"bufload", 1, 1, FEARG_1, ret_void, f_bufload},
426 {"bufloaded", 1, 1, FEARG_1, ret_number, f_bufloaded},
427 {"bufname", 0, 1, FEARG_1, ret_string, f_bufname},
428 {"bufnr", 0, 2, FEARG_1, ret_number, f_bufnr},
429 {"bufwinid", 1, 1, FEARG_1, ret_number, f_bufwinid},
430 {"bufwinnr", 1, 1, FEARG_1, ret_number, f_bufwinnr},
431 {"byte2line", 1, 1, FEARG_1, ret_number, f_byte2line},
432 {"byteidx", 2, 2, FEARG_1, ret_number, f_byteidx},
433 {"byteidxcomp", 2, 2, FEARG_1, ret_number, f_byteidxcomp},
434 {"call", 2, 3, FEARG_1, ret_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100436 {"ceil", 1, 1, FEARG_1, ret_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200437#endif
438#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100439 {"ch_canread", 1, 1, FEARG_1, ret_number, f_ch_canread},
440 {"ch_close", 1, 1, FEARG_1, ret_void, f_ch_close},
441 {"ch_close_in", 1, 1, FEARG_1, ret_void, f_ch_close_in},
442 {"ch_evalexpr", 2, 3, FEARG_1, ret_any, f_ch_evalexpr},
443 {"ch_evalraw", 2, 3, FEARG_1, ret_any, f_ch_evalraw},
444 {"ch_getbufnr", 2, 2, FEARG_1, ret_number, f_ch_getbufnr},
445 {"ch_getjob", 1, 1, FEARG_1, ret_job, f_ch_getjob},
446 {"ch_info", 1, 1, FEARG_1, ret_dict_any, f_ch_info},
447 {"ch_log", 1, 2, FEARG_1, ret_void, f_ch_log},
448 {"ch_logfile", 1, 2, FEARG_1, ret_void, f_ch_logfile},
449 {"ch_open", 1, 2, FEARG_1, ret_channel, f_ch_open},
450 {"ch_read", 1, 2, FEARG_1, ret_string, f_ch_read},
451 {"ch_readblob", 1, 2, FEARG_1, ret_blob, f_ch_readblob},
452 {"ch_readraw", 1, 2, FEARG_1, ret_string, f_ch_readraw},
453 {"ch_sendexpr", 2, 3, FEARG_1, ret_void, f_ch_sendexpr},
454 {"ch_sendraw", 2, 3, FEARG_1, ret_void, f_ch_sendraw},
455 {"ch_setoptions", 2, 2, FEARG_1, ret_void, f_ch_setoptions},
456 {"ch_status", 1, 2, FEARG_1, ret_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200457#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100458 {"changenr", 0, 0, 0, ret_number, f_changenr},
459 {"char2nr", 1, 2, FEARG_1, ret_number, f_char2nr},
460 {"chdir", 1, 1, FEARG_1, ret_string, f_chdir},
461 {"cindent", 1, 1, FEARG_1, ret_number, f_cindent},
462 {"clearmatches", 0, 1, FEARG_1, ret_void, f_clearmatches},
463 {"col", 1, 1, FEARG_1, ret_number, f_col},
464 {"complete", 2, 2, FEARG_2, ret_void, f_complete},
465 {"complete_add", 1, 1, FEARG_1, ret_number, f_complete_add},
466 {"complete_check", 0, 0, 0, ret_number, f_complete_check},
467 {"complete_info", 0, 1, FEARG_1, ret_dict_any, f_complete_info},
468 {"confirm", 1, 4, FEARG_1, ret_number, f_confirm},
469 {"copy", 1, 1, FEARG_1, ret_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200470#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100471 {"cos", 1, 1, FEARG_1, ret_float, f_cos},
472 {"cosh", 1, 1, FEARG_1, ret_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100474 {"count", 2, 4, FEARG_1, ret_number, f_count},
475 {"cscope_connection",0,3, 0, ret_number, f_cscope_connection},
476 {"cursor", 1, 3, FEARG_1, ret_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100477#ifdef MSWIN
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100478 {"debugbreak", 1, 1, FEARG_1, ret_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200479#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100480 {"deepcopy", 1, 2, FEARG_1, ret_any, f_deepcopy},
481 {"delete", 1, 2, FEARG_1, ret_number, f_delete},
482 {"deletebufline", 2, 3, FEARG_1, ret_number, f_deletebufline},
483 {"did_filetype", 0, 0, 0, ret_number, f_did_filetype},
484 {"diff_filler", 1, 1, FEARG_1, ret_number, f_diff_filler},
485 {"diff_hlID", 2, 2, FEARG_1, ret_number, f_diff_hlID},
486 {"echoraw", 1, 1, FEARG_1, ret_number, f_echoraw},
487 {"empty", 1, 1, FEARG_1, ret_number, f_empty},
488 {"environ", 0, 0, 0, ret_dict_string, f_environ},
489 {"escape", 2, 2, FEARG_1, ret_string, f_escape},
490 {"eval", 1, 1, FEARG_1, ret_any, f_eval},
491 {"eventhandler", 0, 0, 0, ret_number, f_eventhandler},
492 {"executable", 1, 1, FEARG_1, ret_number, f_executable},
493 {"execute", 1, 2, FEARG_1, ret_string, f_execute},
494 {"exepath", 1, 1, FEARG_1, ret_string, f_exepath},
495 {"exists", 1, 1, FEARG_1, ret_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200496#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100497 {"exp", 1, 1, FEARG_1, ret_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200498#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100499 {"expand", 1, 3, FEARG_1, ret_any, f_expand},
500 {"expandcmd", 1, 1, FEARG_1, ret_string, f_expandcmd},
501 {"extend", 2, 3, FEARG_1, ret_any, f_extend},
502 {"feedkeys", 1, 2, FEARG_1, ret_void, f_feedkeys},
503 {"file_readable", 1, 1, FEARG_1, ret_number, f_filereadable}, // obsolete
504 {"filereadable", 1, 1, FEARG_1, ret_number, f_filereadable},
505 {"filewritable", 1, 1, FEARG_1, ret_number, f_filewritable},
506 {"filter", 2, 2, FEARG_1, ret_any, f_filter},
507 {"finddir", 1, 3, FEARG_1, ret_string, f_finddir},
508 {"findfile", 1, 3, FEARG_1, ret_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200509#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100510 {"float2nr", 1, 1, FEARG_1, ret_number, f_float2nr},
511 {"floor", 1, 1, FEARG_1, ret_float, f_floor},
512 {"fmod", 2, 2, FEARG_1, ret_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100514 {"fnameescape", 1, 1, FEARG_1, ret_string, f_fnameescape},
515 {"fnamemodify", 2, 2, FEARG_1, ret_string, f_fnamemodify},
516 {"foldclosed", 1, 1, FEARG_1, ret_number, f_foldclosed},
517 {"foldclosedend", 1, 1, FEARG_1, ret_number, f_foldclosedend},
518 {"foldlevel", 1, 1, FEARG_1, ret_number, f_foldlevel},
519 {"foldtext", 0, 0, 0, ret_string, f_foldtext},
520 {"foldtextresult", 1, 1, FEARG_1, ret_string, f_foldtextresult},
521 {"foreground", 0, 0, 0, ret_void, f_foreground},
522 {"funcref", 1, 3, FEARG_1, ret_partial_void, f_funcref},
523 {"function", 1, 3, FEARG_1, ret_f_function, f_function},
524 {"garbagecollect", 0, 1, 0, ret_void, f_garbagecollect},
525 {"get", 2, 3, FEARG_1, ret_any, f_get},
526 {"getbufinfo", 0, 1, 0, ret_list_dict_any, f_getbufinfo},
527 {"getbufline", 2, 3, FEARG_1, ret_list_string, f_getbufline},
528 {"getbufvar", 2, 3, FEARG_1, ret_any, f_getbufvar},
529 {"getchangelist", 0, 1, FEARG_1, ret_list_any, f_getchangelist},
530 {"getchar", 0, 1, 0, ret_number, f_getchar},
531 {"getcharmod", 0, 0, 0, ret_number, f_getcharmod},
532 {"getcharsearch", 0, 0, 0, ret_dict_any, f_getcharsearch},
533 {"getcmdline", 0, 0, 0, ret_string, f_getcmdline},
534 {"getcmdpos", 0, 0, 0, ret_number, f_getcmdpos},
535 {"getcmdtype", 0, 0, 0, ret_string, f_getcmdtype},
536 {"getcmdwintype", 0, 0, 0, ret_string, f_getcmdwintype},
537 {"getcompletion", 2, 3, FEARG_1, ret_list_string, f_getcompletion},
538 {"getcurpos", 0, 0, 0, ret_list_number, f_getcurpos},
539 {"getcwd", 0, 2, FEARG_1, ret_string, f_getcwd},
540 {"getenv", 1, 1, FEARG_1, ret_string, f_getenv},
541 {"getfontname", 0, 1, 0, ret_string, f_getfontname},
542 {"getfperm", 1, 1, FEARG_1, ret_string, f_getfperm},
543 {"getfsize", 1, 1, FEARG_1, ret_number, f_getfsize},
544 {"getftime", 1, 1, FEARG_1, ret_number, f_getftime},
545 {"getftype", 1, 1, FEARG_1, ret_string, f_getftype},
546 {"getimstatus", 0, 0, 0, ret_number, f_getimstatus},
547 {"getjumplist", 0, 2, FEARG_1, ret_list_any, f_getjumplist},
548 {"getline", 1, 2, FEARG_1, ret_f_getline, f_getline},
549 {"getloclist", 1, 2, 0, ret_list_dict_any, f_getloclist},
550 {"getmatches", 0, 1, 0, ret_list_dict_any, f_getmatches},
551 {"getmousepos", 0, 0, 0, ret_dict_number, f_getmousepos},
552 {"getpid", 0, 0, 0, ret_number, f_getpid},
553 {"getpos", 1, 1, FEARG_1, ret_list_number, f_getpos},
554 {"getqflist", 0, 1, 0, ret_list_dict_any, f_getqflist},
555 {"getreg", 0, 3, FEARG_1, ret_string, f_getreg},
556 {"getregtype", 0, 1, FEARG_1, ret_string, f_getregtype},
557 {"gettabinfo", 0, 1, FEARG_1, ret_list_dict_any, f_gettabinfo},
558 {"gettabvar", 2, 3, FEARG_1, ret_any, f_gettabvar},
559 {"gettabwinvar", 3, 4, FEARG_1, ret_any, f_gettabwinvar},
560 {"gettagstack", 0, 1, FEARG_1, ret_dict_any, f_gettagstack},
561 {"getwininfo", 0, 1, FEARG_1, ret_list_dict_any, f_getwininfo},
562 {"getwinpos", 0, 1, FEARG_1, ret_list_number, f_getwinpos},
563 {"getwinposx", 0, 0, 0, ret_number, f_getwinposx},
564 {"getwinposy", 0, 0, 0, ret_number, f_getwinposy},
565 {"getwinvar", 2, 3, FEARG_1, ret_any, f_getwinvar},
566 {"glob", 1, 4, FEARG_1, ret_any, f_glob},
567 {"glob2regpat", 1, 1, FEARG_1, ret_string, f_glob2regpat},
568 {"globpath", 2, 5, FEARG_2, ret_any, f_globpath},
569 {"has", 1, 1, 0, ret_number, f_has},
570 {"has_key", 2, 2, FEARG_1, ret_number, f_has_key},
571 {"haslocaldir", 0, 2, FEARG_1, ret_number, f_haslocaldir},
572 {"hasmapto", 1, 3, FEARG_1, ret_number, f_hasmapto},
573 {"highlightID", 1, 1, FEARG_1, ret_number, f_hlID}, // obsolete
574 {"highlight_exists",1, 1, FEARG_1, ret_number, f_hlexists}, // obsolete
575 {"histadd", 2, 2, FEARG_2, ret_number, f_histadd},
576 {"histdel", 1, 2, FEARG_1, ret_number, f_histdel},
577 {"histget", 1, 2, FEARG_1, ret_string, f_histget},
578 {"histnr", 1, 1, FEARG_1, ret_number, f_histnr},
579 {"hlID", 1, 1, FEARG_1, ret_number, f_hlID},
580 {"hlexists", 1, 1, FEARG_1, ret_number, f_hlexists},
581 {"hostname", 0, 0, 0, ret_string, f_hostname},
582 {"iconv", 3, 3, FEARG_1, ret_string, f_iconv},
583 {"indent", 1, 1, FEARG_1, ret_number, f_indent},
584 {"index", 2, 4, FEARG_1, ret_number, f_index},
585 {"input", 1, 3, FEARG_1, ret_string, f_input},
586 {"inputdialog", 1, 3, FEARG_1, ret_string, f_inputdialog},
587 {"inputlist", 1, 1, FEARG_1, ret_number, f_inputlist},
588 {"inputrestore", 0, 0, 0, ret_number, f_inputrestore},
589 {"inputsave", 0, 0, 0, ret_number, f_inputsave},
590 {"inputsecret", 1, 2, FEARG_1, ret_string, f_inputsecret},
591 {"insert", 2, 3, FEARG_1, ret_any, f_insert},
592 {"interrupt", 0, 0, 0, ret_void, f_interrupt},
593 {"invert", 1, 1, FEARG_1, ret_number, f_invert},
594 {"isdirectory", 1, 1, FEARG_1, ret_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200595#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100596 {"isinf", 1, 1, FEARG_1, ret_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200597#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100598 {"islocked", 1, 1, FEARG_1, ret_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200599#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100600 {"isnan", 1, 1, FEARG_1, ret_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100602 {"items", 1, 1, FEARG_1, ret_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100604 {"job_getchannel", 1, 1, FEARG_1, ret_channel, f_job_getchannel},
605 {"job_info", 0, 1, FEARG_1, ret_dict_any, f_job_info},
606 {"job_setoptions", 2, 2, FEARG_1, ret_void, f_job_setoptions},
607 {"job_start", 1, 2, FEARG_1, ret_job, f_job_start},
608 {"job_status", 1, 1, FEARG_1, ret_string, f_job_status},
609 {"job_stop", 1, 2, FEARG_1, ret_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200610#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100611 {"join", 1, 2, FEARG_1, ret_string, f_join},
612 {"js_decode", 1, 1, FEARG_1, ret_any, f_js_decode},
613 {"js_encode", 1, 1, FEARG_1, ret_string, f_js_encode},
614 {"json_decode", 1, 1, FEARG_1, ret_any, f_json_decode},
615 {"json_encode", 1, 1, FEARG_1, ret_string, f_json_encode},
616 {"keys", 1, 1, FEARG_1, ret_list_any, f_keys},
617 {"last_buffer_nr", 0, 0, 0, ret_number, f_last_buffer_nr}, // obsolete
618 {"len", 1, 1, FEARG_1, ret_number, f_len},
619 {"libcall", 3, 3, FEARG_3, ret_string, f_libcall},
620 {"libcallnr", 3, 3, FEARG_3, ret_number, f_libcallnr},
621 {"line", 1, 2, FEARG_1, ret_number, f_line},
622 {"line2byte", 1, 1, FEARG_1, ret_number, f_line2byte},
623 {"lispindent", 1, 1, FEARG_1, ret_number, f_lispindent},
624 {"list2str", 1, 2, FEARG_1, ret_string, f_list2str},
625 {"listener_add", 1, 2, FEARG_2, ret_number, f_listener_add},
626 {"listener_flush", 0, 1, FEARG_1, ret_void, f_listener_flush},
627 {"listener_remove", 1, 1, FEARG_1, ret_number, f_listener_remove},
628 {"localtime", 0, 0, 0, ret_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200629#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100630 {"log", 1, 1, FEARG_1, ret_float, f_log},
631 {"log10", 1, 1, FEARG_1, ret_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632#endif
633#ifdef FEAT_LUA
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100634 {"luaeval", 1, 2, FEARG_1, ret_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100636 {"map", 2, 2, FEARG_1, ret_any, f_map},
637 {"maparg", 1, 4, FEARG_1, ret_string, f_maparg},
638 {"mapcheck", 1, 3, FEARG_1, ret_string, f_mapcheck},
639 {"match", 2, 4, FEARG_1, ret_any, f_match},
640 {"matchadd", 2, 5, FEARG_1, ret_number, f_matchadd},
641 {"matchaddpos", 2, 5, FEARG_1, ret_number, f_matchaddpos},
642 {"matcharg", 1, 1, FEARG_1, ret_list_string, f_matcharg},
643 {"matchdelete", 1, 2, FEARG_1, ret_number, f_matchdelete},
644 {"matchend", 2, 4, FEARG_1, ret_number, f_matchend},
645 {"matchlist", 2, 4, FEARG_1, ret_list_string, f_matchlist},
646 {"matchstr", 2, 4, FEARG_1, ret_string, f_matchstr},
647 {"matchstrpos", 2, 4, FEARG_1, ret_list_any, f_matchstrpos},
648 {"max", 1, 1, FEARG_1, ret_any, f_max},
Bram Moolenaar0eabd4d2020-03-15 16:13:53 +0100649 {"menu_info", 1, 2, FEARG_1, ret_dict_any, f_menu_info},
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100650 {"min", 1, 1, FEARG_1, ret_any, f_min},
651 {"mkdir", 1, 3, FEARG_1, ret_number, f_mkdir},
652 {"mode", 0, 1, FEARG_1, ret_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653#ifdef FEAT_MZSCHEME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100654 {"mzeval", 1, 1, FEARG_1, ret_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100656 {"nextnonblank", 1, 1, FEARG_1, ret_number, f_nextnonblank},
657 {"nr2char", 1, 2, FEARG_1, ret_string, f_nr2char},
658 {"or", 2, 2, FEARG_1, ret_number, f_or},
659 {"pathshorten", 1, 1, FEARG_1, ret_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200660#ifdef FEAT_PERL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100661 {"perleval", 1, 1, FEARG_1, ret_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100663#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100664 {"popup_atcursor", 2, 2, FEARG_1, ret_number, f_popup_atcursor},
665 {"popup_beval", 2, 2, FEARG_1, ret_number, f_popup_beval},
666 {"popup_clear", 0, 0, 0, ret_void, f_popup_clear},
667 {"popup_close", 1, 2, FEARG_1, ret_void, f_popup_close},
668 {"popup_create", 2, 2, FEARG_1, ret_number, f_popup_create},
669 {"popup_dialog", 2, 2, FEARG_1, ret_number, f_popup_dialog},
670 {"popup_filter_menu", 2, 2, 0, ret_number, f_popup_filter_menu},
671 {"popup_filter_yesno", 2, 2, 0, ret_number, f_popup_filter_yesno},
672 {"popup_findinfo", 0, 0, 0, ret_number, f_popup_findinfo},
673 {"popup_findpreview", 0, 0, 0, ret_number, f_popup_findpreview},
674 {"popup_getoptions", 1, 1, FEARG_1, ret_dict_any, f_popup_getoptions},
675 {"popup_getpos", 1, 1, FEARG_1, ret_dict_any, f_popup_getpos},
676 {"popup_hide", 1, 1, FEARG_1, ret_void, f_popup_hide},
677 {"popup_locate", 2, 2, 0, ret_number, f_popup_locate},
678 {"popup_menu", 2, 2, FEARG_1, ret_number, f_popup_menu},
679 {"popup_move", 2, 2, FEARG_1, ret_void, f_popup_move},
680 {"popup_notification", 2, 2, FEARG_1, ret_number, f_popup_notification},
681 {"popup_setoptions", 2, 2, FEARG_1, ret_void, f_popup_setoptions},
682 {"popup_settext", 2, 2, FEARG_1, ret_void, f_popup_settext},
683 {"popup_show", 1, 1, FEARG_1, ret_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200684#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100686 {"pow", 2, 2, FEARG_1, ret_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200687#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100688 {"prevnonblank", 1, 1, FEARG_1, ret_number, f_prevnonblank},
689 {"printf", 1, 19, FEARG_2, ret_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200690#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100691 {"prompt_setcallback", 2, 2, FEARG_1, ret_void, f_prompt_setcallback},
692 {"prompt_setinterrupt", 2, 2, FEARG_1,ret_void, f_prompt_setinterrupt},
693 {"prompt_setprompt", 2, 2, FEARG_1, ret_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200694#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100695#ifdef FEAT_PROP_POPUP
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100696 {"prop_add", 3, 3, FEARG_1, ret_void, f_prop_add},
697 {"prop_clear", 1, 3, FEARG_1, ret_void, f_prop_clear},
698 {"prop_find", 1, 2, FEARG_1, ret_dict_any, f_prop_find},
699 {"prop_list", 1, 2, FEARG_1, ret_list_dict_any, f_prop_list},
700 {"prop_remove", 1, 3, FEARG_1, ret_number, f_prop_remove},
701 {"prop_type_add", 2, 2, FEARG_1, ret_void, f_prop_type_add},
702 {"prop_type_change", 2, 2, FEARG_1, ret_void, f_prop_type_change},
703 {"prop_type_delete", 1, 2, FEARG_1, ret_void, f_prop_type_delete},
704 {"prop_type_get", 1, 2, FEARG_1, ret_dict_any, f_prop_type_get},
705 {"prop_type_list", 0, 1, FEARG_1, ret_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100706#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100707 {"pum_getpos", 0, 0, 0, ret_dict_number, f_pum_getpos},
708 {"pumvisible", 0, 0, 0, ret_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200709#ifdef FEAT_PYTHON3
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100710 {"py3eval", 1, 1, FEARG_1, ret_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200711#endif
712#ifdef FEAT_PYTHON
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100713 {"pyeval", 1, 1, FEARG_1, ret_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200714#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100715#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100716 {"pyxeval", 1, 1, FEARG_1, ret_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100717#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100718 {"rand", 0, 1, FEARG_1, ret_number, f_rand},
719 {"range", 1, 3, FEARG_1, ret_list_number, f_range},
720 {"readdir", 1, 2, FEARG_1, ret_list_string, f_readdir},
721 {"readfile", 1, 3, FEARG_1, ret_any, f_readfile},
722 {"reg_executing", 0, 0, 0, ret_string, f_reg_executing},
723 {"reg_recording", 0, 0, 0, ret_string, f_reg_recording},
724 {"reltime", 0, 2, FEARG_1, ret_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200725#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100726 {"reltimefloat", 1, 1, FEARG_1, ret_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100728 {"reltimestr", 1, 1, FEARG_1, ret_string, f_reltimestr},
729 {"remote_expr", 2, 4, FEARG_1, ret_string, f_remote_expr},
730 {"remote_foreground", 1, 1, FEARG_1, ret_string, f_remote_foreground},
731 {"remote_peek", 1, 2, FEARG_1, ret_number, f_remote_peek},
732 {"remote_read", 1, 2, FEARG_1, ret_string, f_remote_read},
733 {"remote_send", 2, 3, FEARG_1, ret_string, f_remote_send},
734 {"remote_startserver", 1, 1, FEARG_1, ret_void, f_remote_startserver},
735 {"remove", 2, 3, FEARG_1, ret_any, f_remove},
736 {"rename", 2, 2, FEARG_1, ret_number, f_rename},
737 {"repeat", 2, 2, FEARG_1, ret_any, f_repeat},
738 {"resolve", 1, 1, FEARG_1, ret_string, f_resolve},
739 {"reverse", 1, 1, FEARG_1, ret_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200740#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100741 {"round", 1, 1, FEARG_1, ret_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200742#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100743#ifdef FEAT_RUBY
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100744 {"rubyeval", 1, 1, FEARG_1, ret_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100745#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100746 {"screenattr", 2, 2, FEARG_1, ret_number, f_screenattr},
747 {"screenchar", 2, 2, FEARG_1, ret_number, f_screenchar},
748 {"screenchars", 2, 2, FEARG_1, ret_list_number, f_screenchars},
749 {"screencol", 0, 0, 0, ret_number, f_screencol},
750 {"screenpos", 3, 3, FEARG_1, ret_dict_number, f_screenpos},
751 {"screenrow", 0, 0, 0, ret_number, f_screenrow},
752 {"screenstring", 2, 2, FEARG_1, ret_string, f_screenstring},
753 {"search", 1, 4, FEARG_1, ret_number, f_search},
754 {"searchdecl", 1, 3, FEARG_1, ret_number, f_searchdecl},
755 {"searchpair", 3, 7, 0, ret_number, f_searchpair},
756 {"searchpairpos", 3, 7, 0, ret_list_number, f_searchpairpos},
757 {"searchpos", 1, 4, FEARG_1, ret_list_number, f_searchpos},
758 {"server2client", 2, 2, FEARG_1, ret_number, f_server2client},
759 {"serverlist", 0, 0, 0, ret_string, f_serverlist},
760 {"setbufline", 3, 3, FEARG_3, ret_number, f_setbufline},
761 {"setbufvar", 3, 3, FEARG_3, ret_void, f_setbufvar},
762 {"setcharsearch", 1, 1, FEARG_1, ret_void, f_setcharsearch},
763 {"setcmdpos", 1, 1, FEARG_1, ret_number, f_setcmdpos},
764 {"setenv", 2, 2, FEARG_2, ret_void, f_setenv},
765 {"setfperm", 2, 2, FEARG_1, ret_number, f_setfperm},
766 {"setline", 2, 2, FEARG_2, ret_number, f_setline},
767 {"setloclist", 2, 4, FEARG_2, ret_number, f_setloclist},
768 {"setmatches", 1, 2, FEARG_1, ret_number, f_setmatches},
769 {"setpos", 2, 2, FEARG_2, ret_number, f_setpos},
770 {"setqflist", 1, 3, FEARG_1, ret_number, f_setqflist},
771 {"setreg", 2, 3, FEARG_2, ret_number, f_setreg},
772 {"settabvar", 3, 3, FEARG_3, ret_void, f_settabvar},
773 {"settabwinvar", 4, 4, FEARG_4, ret_void, f_settabwinvar},
774 {"settagstack", 2, 3, FEARG_2, ret_number, f_settagstack},
775 {"setwinvar", 3, 3, FEARG_3, ret_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200776#ifdef FEAT_CRYPT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100777 {"sha256", 1, 1, FEARG_1, ret_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100779 {"shellescape", 1, 2, FEARG_1, ret_string, f_shellescape},
780 {"shiftwidth", 0, 1, FEARG_1, ret_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100781#ifdef FEAT_SIGNS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100782 {"sign_define", 1, 2, FEARG_1, ret_any, f_sign_define},
783 {"sign_getdefined", 0, 1, FEARG_1, ret_list_dict_any, f_sign_getdefined},
784 {"sign_getplaced", 0, 2, FEARG_1, ret_list_dict_any, f_sign_getplaced},
785 {"sign_jump", 3, 3, FEARG_1, ret_number, f_sign_jump},
786 {"sign_place", 4, 5, FEARG_1, ret_number, f_sign_place},
787 {"sign_placelist", 1, 1, FEARG_1, ret_list_number, f_sign_placelist},
788 {"sign_undefine", 0, 1, FEARG_1, ret_number, f_sign_undefine},
789 {"sign_unplace", 1, 2, FEARG_1, ret_number, f_sign_unplace},
790 {"sign_unplacelist", 1, 2, FEARG_1, ret_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100791#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100792 {"simplify", 1, 1, 0, ret_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200793#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100794 {"sin", 1, 1, FEARG_1, ret_float, f_sin},
795 {"sinh", 1, 1, FEARG_1, ret_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200796#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100797 {"sort", 1, 3, FEARG_1, ret_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200798#ifdef FEAT_SOUND
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100799 {"sound_clear", 0, 0, 0, ret_void, f_sound_clear},
800 {"sound_playevent", 1, 2, FEARG_1, ret_number, f_sound_playevent},
801 {"sound_playfile", 1, 2, FEARG_1, ret_number, f_sound_playfile},
802 {"sound_stop", 1, 1, FEARG_1, ret_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200803#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100804 {"soundfold", 1, 1, FEARG_1, ret_string, f_soundfold},
805 {"spellbadword", 0, 1, FEARG_1, ret_list_string, f_spellbadword},
806 {"spellsuggest", 1, 3, FEARG_1, ret_list_string, f_spellsuggest},
807 {"split", 1, 3, FEARG_1, ret_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100809 {"sqrt", 1, 1, FEARG_1, ret_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200810#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100811 {"srand", 0, 1, FEARG_1, ret_list_number, f_srand},
812 {"state", 0, 1, FEARG_1, ret_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200813#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100814 {"str2float", 1, 1, FEARG_1, ret_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200815#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100816 {"str2list", 1, 2, FEARG_1, ret_list_number, f_str2list},
817 {"str2nr", 1, 3, FEARG_1, ret_number, f_str2nr},
818 {"strcharpart", 2, 3, FEARG_1, ret_string, f_strcharpart},
819 {"strchars", 1, 2, FEARG_1, ret_number, f_strchars},
820 {"strdisplaywidth", 1, 2, FEARG_1, ret_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821#ifdef HAVE_STRFTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100822 {"strftime", 1, 2, FEARG_1, ret_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100824 {"strgetchar", 2, 2, FEARG_1, ret_number, f_strgetchar},
825 {"stridx", 2, 3, FEARG_1, ret_number, f_stridx},
826 {"string", 1, 1, FEARG_1, ret_string, f_string},
827 {"strlen", 1, 1, FEARG_1, ret_number, f_strlen},
828 {"strpart", 2, 3, FEARG_1, ret_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100829#ifdef HAVE_STRPTIME
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100830 {"strptime", 2, 2, FEARG_1, ret_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100831#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100832 {"strridx", 2, 3, FEARG_1, ret_number, f_strridx},
833 {"strtrans", 1, 1, FEARG_1, ret_string, f_strtrans},
834 {"strwidth", 1, 1, FEARG_1, ret_number, f_strwidth},
835 {"submatch", 1, 2, FEARG_1, ret_string, f_submatch},
836 {"substitute", 4, 4, FEARG_1, ret_string, f_substitute},
837 {"swapinfo", 1, 1, FEARG_1, ret_dict_any, f_swapinfo},
838 {"swapname", 1, 1, FEARG_1, ret_string, f_swapname},
839 {"synID", 3, 3, 0, ret_number, f_synID},
840 {"synIDattr", 2, 3, FEARG_1, ret_string, f_synIDattr},
841 {"synIDtrans", 1, 1, FEARG_1, ret_number, f_synIDtrans},
842 {"synconcealed", 2, 2, 0, ret_list_any, f_synconcealed},
843 {"synstack", 2, 2, 0, ret_list_number, f_synstack},
844 {"system", 1, 2, FEARG_1, ret_string, f_system},
845 {"systemlist", 1, 2, FEARG_1, ret_list_string, f_systemlist},
846 {"tabpagebuflist", 0, 1, FEARG_1, ret_list_number, f_tabpagebuflist},
847 {"tabpagenr", 0, 1, 0, ret_number, f_tabpagenr},
848 {"tabpagewinnr", 1, 2, FEARG_1, ret_number, f_tabpagewinnr},
849 {"tagfiles", 0, 0, 0, ret_list_string, f_tagfiles},
850 {"taglist", 1, 2, FEARG_1, ret_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100852 {"tan", 1, 1, FEARG_1, ret_float, f_tan},
853 {"tanh", 1, 1, FEARG_1, ret_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200854#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100855 {"tempname", 0, 0, 0, ret_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200856#ifdef FEAT_TERMINAL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100857 {"term_dumpdiff", 2, 3, FEARG_1, ret_number, f_term_dumpdiff},
858 {"term_dumpload", 1, 2, FEARG_1, ret_number, f_term_dumpload},
859 {"term_dumpwrite", 2, 3, FEARG_2, ret_void, f_term_dumpwrite},
860 {"term_getaltscreen", 1, 1, FEARG_1, ret_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200861# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100862 {"term_getansicolors", 1, 1, FEARG_1, ret_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200863# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100864 {"term_getattr", 2, 2, FEARG_1, ret_number, f_term_getattr},
865 {"term_getcursor", 1, 1, FEARG_1, ret_list_any, f_term_getcursor},
866 {"term_getjob", 1, 1, FEARG_1, ret_job, f_term_getjob},
867 {"term_getline", 2, 2, FEARG_1, ret_string, f_term_getline},
868 {"term_getscrolled", 1, 1, FEARG_1, ret_number, f_term_getscrolled},
869 {"term_getsize", 1, 1, FEARG_1, ret_list_number, f_term_getsize},
870 {"term_getstatus", 1, 1, FEARG_1, ret_string, f_term_getstatus},
871 {"term_gettitle", 1, 1, FEARG_1, ret_string, f_term_gettitle},
872 {"term_gettty", 1, 2, FEARG_1, ret_string, f_term_gettty},
873 {"term_list", 0, 0, 0, ret_list_number, f_term_list},
874 {"term_scrape", 2, 2, FEARG_1, ret_list_dict_any, f_term_scrape},
875 {"term_sendkeys", 2, 2, FEARG_1, ret_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200876# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100877 {"term_setansicolors", 2, 2, FEARG_1, ret_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200878# endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100879 {"term_setapi", 2, 2, FEARG_1, ret_void, f_term_setapi},
880 {"term_setkill", 2, 2, FEARG_1, ret_void, f_term_setkill},
881 {"term_setrestore", 2, 2, FEARG_1, ret_void, f_term_setrestore},
882 {"term_setsize", 3, 3, FEARG_1, ret_void, f_term_setsize},
883 {"term_start", 1, 2, FEARG_1, ret_number, f_term_start},
884 {"term_wait", 1, 2, FEARG_1, ret_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200885#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100886 {"test_alloc_fail", 3, 3, FEARG_1, ret_void, f_test_alloc_fail},
887 {"test_autochdir", 0, 0, 0, ret_void, f_test_autochdir},
888 {"test_feedinput", 1, 1, FEARG_1, ret_void, f_test_feedinput},
889 {"test_garbagecollect_now", 0, 0, 0, ret_void, f_test_garbagecollect_now},
890 {"test_garbagecollect_soon", 0, 0, 0, ret_void, f_test_garbagecollect_soon},
891 {"test_getvalue", 1, 1, FEARG_1, ret_number, f_test_getvalue},
892 {"test_ignore_error", 1, 1, FEARG_1, ret_void, f_test_ignore_error},
893 {"test_null_blob", 0, 0, 0, ret_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200894#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100895 {"test_null_channel", 0, 0, 0, ret_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200896#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100897 {"test_null_dict", 0, 0, 0, ret_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200898#ifdef FEAT_JOB_CHANNEL
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100899 {"test_null_job", 0, 0, 0, ret_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200900#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100901 {"test_null_list", 0, 0, 0, ret_list_any, f_test_null_list},
902 {"test_null_partial", 0, 0, 0, ret_partial_void, f_test_null_partial},
903 {"test_null_string", 0, 0, 0, ret_string, f_test_null_string},
904 {"test_option_not_set", 1, 1, FEARG_1,ret_void, f_test_option_not_set},
905 {"test_override", 2, 2, FEARG_2, ret_void, f_test_override},
906 {"test_refcount", 1, 1, FEARG_1, ret_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200907#ifdef FEAT_GUI
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100908 {"test_scrollbar", 3, 3, FEARG_2, ret_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200909#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100910 {"test_setmouse", 2, 2, 0, ret_void, f_test_setmouse},
911 {"test_settime", 1, 1, FEARG_1, ret_void, f_test_settime},
912 {"test_srand_seed", 0, 1, FEARG_1, ret_void, f_test_srand_seed},
913 {"test_unknown", 0, 0, 0, ret_any, f_test_unknown},
914 {"test_void", 0, 0, 0, ret_any, f_test_void},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200915#ifdef FEAT_TIMERS
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100916 {"timer_info", 0, 1, FEARG_1, ret_list_dict_any, f_timer_info},
917 {"timer_pause", 2, 2, FEARG_1, ret_void, f_timer_pause},
918 {"timer_start", 2, 3, FEARG_1, ret_number, f_timer_start},
919 {"timer_stop", 1, 1, FEARG_1, ret_void, f_timer_stop},
920 {"timer_stopall", 0, 0, 0, ret_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200921#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100922 {"tolower", 1, 1, FEARG_1, ret_string, f_tolower},
923 {"toupper", 1, 1, FEARG_1, ret_string, f_toupper},
924 {"tr", 3, 3, FEARG_1, ret_string, f_tr},
925 {"trim", 1, 2, FEARG_1, ret_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926#ifdef FEAT_FLOAT
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100927 {"trunc", 1, 1, FEARG_1, ret_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928#endif
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +0100929 {"type", 1, 1, FEARG_1, ret_number, f_type},
930 {"undofile", 1, 1, FEARG_1, ret_string, f_undofile},
931 {"undotree", 0, 0, 0, ret_dict_any, f_undotree},
932 {"uniq", 1, 3, FEARG_1, ret_list_any, f_uniq},
933 {"values", 1, 1, FEARG_1, ret_list_any, f_values},
934 {"virtcol", 1, 1, FEARG_1, ret_number, f_virtcol},
935 {"visualmode", 0, 1, 0, ret_string, f_visualmode},
936 {"wildmenumode", 0, 0, 0, ret_number, f_wildmenumode},
937 {"win_execute", 2, 3, FEARG_2, ret_string, f_win_execute},
938 {"win_findbuf", 1, 1, FEARG_1, ret_list_number, f_win_findbuf},
939 {"win_getid", 0, 2, FEARG_1, ret_number, f_win_getid},
940 {"win_gettype", 0, 1, FEARG_1, ret_string, f_win_gettype},
941 {"win_gotoid", 1, 1, FEARG_1, ret_number, f_win_gotoid},
942 {"win_id2tabwin", 1, 1, FEARG_1, ret_list_number, f_win_id2tabwin},
943 {"win_id2win", 1, 1, FEARG_1, ret_number, f_win_id2win},
944 {"win_screenpos", 1, 1, FEARG_1, ret_list_number, f_win_screenpos},
945 {"win_splitmove", 2, 3, FEARG_1, ret_number, f_win_splitmove},
946 {"winbufnr", 1, 1, FEARG_1, ret_number, f_winbufnr},
947 {"wincol", 0, 0, 0, ret_number, f_wincol},
948 {"windowsversion", 0, 0, 0, ret_string, f_windowsversion},
949 {"winheight", 1, 1, FEARG_1, ret_number, f_winheight},
950 {"winlayout", 0, 1, FEARG_1, ret_list_any, f_winlayout},
951 {"winline", 0, 0, 0, ret_number, f_winline},
952 {"winnr", 0, 1, FEARG_1, ret_number, f_winnr},
953 {"winrestcmd", 0, 0, 0, ret_string, f_winrestcmd},
954 {"winrestview", 1, 1, FEARG_1, ret_void, f_winrestview},
955 {"winsaveview", 0, 0, 0, ret_dict_any, f_winsaveview},
956 {"winwidth", 1, 1, FEARG_1, ret_number, f_winwidth},
957 {"wordcount", 0, 0, 0, ret_dict_number, f_wordcount},
958 {"writefile", 2, 3, FEARG_1, ret_number, f_writefile},
959 {"xor", 2, 2, FEARG_1, ret_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200960};
961
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200962/*
963 * Function given to ExpandGeneric() to obtain the list of internal
964 * or user defined function names.
965 */
966 char_u *
967get_function_name(expand_T *xp, int idx)
968{
969 static int intidx = -1;
970 char_u *name;
971
972 if (idx == 0)
973 intidx = -1;
974 if (intidx < 0)
975 {
976 name = get_user_func_name(xp, idx);
977 if (name != NULL)
978 return name;
979 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200980 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200981 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200982 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200983 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200984 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200985 STRCAT(IObuff, ")");
986 return IObuff;
987 }
988
989 return NULL;
990}
991
992/*
993 * Function given to ExpandGeneric() to obtain the list of internal or
994 * user defined variable or function names.
995 */
996 char_u *
997get_expr_name(expand_T *xp, int idx)
998{
999 static int intidx = -1;
1000 char_u *name;
1001
1002 if (idx == 0)
1003 intidx = -1;
1004 if (intidx < 0)
1005 {
1006 name = get_function_name(xp, idx);
1007 if (name != NULL)
1008 return name;
1009 }
1010 return get_user_var_name(xp, ++intidx);
1011}
1012
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001013/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001014 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001015 * Return index, or -1 if not found
1016 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001017 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001018find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019{
1020 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001021 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001022 int cmp;
1023 int x;
1024
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001025 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001026
1027 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001028 while (first <= last)
1029 {
1030 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001031 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001032 if (cmp < 0)
1033 last = x - 1;
1034 else if (cmp > 0)
1035 first = x + 1;
1036 else
1037 return x;
1038 }
1039 return -1;
1040}
1041
1042 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001043has_internal_func(char_u *name)
1044{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001045 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001046}
1047
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001048 char *
1049internal_func_name(int idx)
1050{
1051 return global_functions[idx].f_name;
1052}
1053
1054 type_T *
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001055internal_func_ret_type(int idx, int argcount, type_T **argtypes)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001056{
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01001057 return global_functions[idx].f_retfunc(argcount, argtypes);
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001058}
1059
1060/*
1061 * Check the argument count to use for internal function "idx".
1062 * Returns OK or FAIL;
1063 */
1064 int
1065check_internal_func(int idx, int argcount)
1066{
1067 int res;
1068 char *name;
1069
1070 if (argcount < global_functions[idx].f_min_argc)
1071 res = FCERR_TOOFEW;
1072 else if (argcount > global_functions[idx].f_max_argc)
1073 res = FCERR_TOOMANY;
1074 else
1075 return OK;
1076
1077 name = internal_func_name(idx);
1078 if (res == FCERR_TOOMANY)
1079 semsg(_(e_toomanyarg), name);
1080 else
1081 semsg(_(e_toofewarg), name);
1082 return FAIL;
1083}
1084
Bram Moolenaarac92e252019-08-03 21:58:38 +02001085 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001086call_internal_func(
1087 char_u *name,
1088 int argcount,
1089 typval_T *argvars,
1090 typval_T *rettv)
1091{
1092 int i;
1093
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001094 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001095 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001096 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001097 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001098 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001099 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001100 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001101 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001102 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001103 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001104}
1105
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001106 void
1107call_internal_func_by_idx(
1108 int idx,
1109 typval_T *argvars,
1110 typval_T *rettv)
1111{
1112 global_functions[idx].f_func(argvars, rettv);
1113}
1114
Bram Moolenaarac92e252019-08-03 21:58:38 +02001115/*
1116 * Invoke a method for base->method().
1117 */
1118 int
1119call_internal_method(
1120 char_u *name,
1121 int argcount,
1122 typval_T *argvars,
1123 typval_T *rettv,
1124 typval_T *basetv)
1125{
1126 int i;
1127 int fi;
1128 typval_T argv[MAX_FUNC_ARGS + 1];
1129
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001130 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001131 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001132 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001133 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001134 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001135 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001136 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001137 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001138 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001139
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001140 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001141 {
1142 // base value goes last
1143 for (i = 0; i < argcount; ++i)
1144 argv[i] = argvars[i];
1145 argv[argcount] = *basetv;
1146 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001147 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001148 {
1149 // base value goes second
1150 argv[0] = argvars[0];
1151 argv[1] = *basetv;
1152 for (i = 1; i < argcount; ++i)
1153 argv[i + 1] = argvars[i];
1154 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001155 else if (global_functions[fi].f_argtype == FEARG_3)
1156 {
1157 // base value goes third
1158 argv[0] = argvars[0];
1159 argv[1] = argvars[1];
1160 argv[2] = *basetv;
1161 for (i = 2; i < argcount; ++i)
1162 argv[i + 1] = argvars[i];
1163 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001164 else if (global_functions[fi].f_argtype == FEARG_4)
1165 {
1166 // base value goes fourth
1167 argv[0] = argvars[0];
1168 argv[1] = argvars[1];
1169 argv[2] = argvars[2];
1170 argv[3] = *basetv;
1171 for (i = 3; i < argcount; ++i)
1172 argv[i + 1] = argvars[i];
1173 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001174 else
1175 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001176 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001177 argv[0] = *basetv;
1178 for (i = 0; i < argcount; ++i)
1179 argv[i + 1] = argvars[i];
1180 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001181 argv[argcount + 1].v_type = VAR_UNKNOWN;
1182
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001183 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001184 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001185}
1186
1187/*
1188 * Return TRUE for a non-zero Number and a non-empty String.
1189 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001190 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001191non_zero_arg(typval_T *argvars)
1192{
1193 return ((argvars[0].v_type == VAR_NUMBER
1194 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001195 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001196 && argvars[0].vval.v_number == VVAL_TRUE)
1197 || (argvars[0].v_type == VAR_STRING
1198 && argvars[0].vval.v_string != NULL
1199 && *argvars[0].vval.v_string != NUL));
1200}
1201
1202/*
1203 * Get the lnum from the first argument.
1204 * Also accepts ".", "$", etc., but that only works for the current buffer.
1205 * Returns -1 on error.
1206 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001207 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001208tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001209{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001210 linenr_T lnum;
1211
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001212 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001213 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001214 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001215 int fnum;
1216 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1217
1218 if (fp != NULL)
1219 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001220 }
1221 return lnum;
1222}
1223
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001224/*
1225 * Get the lnum from the first argument.
1226 * Also accepts "$", then "buf" is used.
1227 * Returns 0 on error.
1228 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001229 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001230tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1231{
1232 if (argvars[0].v_type == VAR_STRING
1233 && argvars[0].vval.v_string != NULL
1234 && argvars[0].vval.v_string[0] == '$'
1235 && buf != NULL)
1236 return buf->b_ml.ml_line_count;
1237 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1238}
1239
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001240#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001241/*
1242 * Get the float value of "argvars[0]" into "f".
1243 * Returns FAIL when the argument is not a Number or Float.
1244 */
1245 static int
1246get_float_arg(typval_T *argvars, float_T *f)
1247{
1248 if (argvars[0].v_type == VAR_FLOAT)
1249 {
1250 *f = argvars[0].vval.v_float;
1251 return OK;
1252 }
1253 if (argvars[0].v_type == VAR_NUMBER)
1254 {
1255 *f = (float_T)argvars[0].vval.v_number;
1256 return OK;
1257 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001258 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001259 return FAIL;
1260}
1261
1262/*
1263 * "abs(expr)" function
1264 */
1265 static void
1266f_abs(typval_T *argvars, typval_T *rettv)
1267{
1268 if (argvars[0].v_type == VAR_FLOAT)
1269 {
1270 rettv->v_type = VAR_FLOAT;
1271 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1272 }
1273 else
1274 {
1275 varnumber_T n;
1276 int error = FALSE;
1277
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001278 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001279 if (error)
1280 rettv->vval.v_number = -1;
1281 else if (n > 0)
1282 rettv->vval.v_number = n;
1283 else
1284 rettv->vval.v_number = -n;
1285 }
1286}
1287
1288/*
1289 * "acos()" function
1290 */
1291 static void
1292f_acos(typval_T *argvars, typval_T *rettv)
1293{
1294 float_T f = 0.0;
1295
1296 rettv->v_type = VAR_FLOAT;
1297 if (get_float_arg(argvars, &f) == OK)
1298 rettv->vval.v_float = acos(f);
1299 else
1300 rettv->vval.v_float = 0.0;
1301}
1302#endif
1303
1304/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001305 * "and(expr, expr)" function
1306 */
1307 static void
1308f_and(typval_T *argvars, typval_T *rettv)
1309{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001310 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1311 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001312}
1313
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001314#ifdef FEAT_FLOAT
1315/*
1316 * "asin()" function
1317 */
1318 static void
1319f_asin(typval_T *argvars, typval_T *rettv)
1320{
1321 float_T f = 0.0;
1322
1323 rettv->v_type = VAR_FLOAT;
1324 if (get_float_arg(argvars, &f) == OK)
1325 rettv->vval.v_float = asin(f);
1326 else
1327 rettv->vval.v_float = 0.0;
1328}
1329
1330/*
1331 * "atan()" function
1332 */
1333 static void
1334f_atan(typval_T *argvars, typval_T *rettv)
1335{
1336 float_T f = 0.0;
1337
1338 rettv->v_type = VAR_FLOAT;
1339 if (get_float_arg(argvars, &f) == OK)
1340 rettv->vval.v_float = atan(f);
1341 else
1342 rettv->vval.v_float = 0.0;
1343}
1344
1345/*
1346 * "atan2()" function
1347 */
1348 static void
1349f_atan2(typval_T *argvars, typval_T *rettv)
1350{
1351 float_T fx = 0.0, fy = 0.0;
1352
1353 rettv->v_type = VAR_FLOAT;
1354 if (get_float_arg(argvars, &fx) == OK
1355 && get_float_arg(&argvars[1], &fy) == OK)
1356 rettv->vval.v_float = atan2(fx, fy);
1357 else
1358 rettv->vval.v_float = 0.0;
1359}
1360#endif
1361
1362/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001363 * "balloon_show()" function
1364 */
1365#ifdef FEAT_BEVAL
1366 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001367f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1368{
1369 rettv->v_type = VAR_STRING;
1370 if (balloonEval != NULL)
1371 {
1372 if (balloonEval->msg == NULL)
1373 rettv->vval.v_string = NULL;
1374 else
1375 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1376 }
1377}
1378
1379 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001380f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1381{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001382 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001383 {
1384 if (argvars[0].v_type == VAR_LIST
1385# ifdef FEAT_GUI
1386 && !gui.in_use
1387# endif
1388 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001389 {
1390 list_T *l = argvars[0].vval.v_list;
1391
1392 // empty list removes the balloon
1393 post_balloon(balloonEval, NULL,
1394 l == NULL || l->lv_len == 0 ? NULL : l);
1395 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001396 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001397 {
1398 char_u *mesg = tv_get_string_chk(&argvars[0]);
1399
1400 if (mesg != NULL)
1401 // empty string removes the balloon
1402 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1403 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001404 }
1405}
1406
Bram Moolenaar669a8282017-11-19 20:13:05 +01001407# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001408 static void
1409f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1410{
1411 if (rettv_list_alloc(rettv) == OK)
1412 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001413 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001414
1415 if (msg != NULL)
1416 {
1417 pumitem_T *array;
1418 int size = split_message(msg, &array);
1419 int i;
1420
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001421 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001422 for (i = 1; i < size - 1; ++i)
1423 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001424 while (size > 0)
1425 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001426 vim_free(array);
1427 }
1428 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001429}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001430# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001431#endif
1432
1433/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434 * Get buffer by number or pattern.
1435 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001436 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001437tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001438{
1439 char_u *name = tv->vval.v_string;
1440 buf_T *buf;
1441
1442 if (tv->v_type == VAR_NUMBER)
1443 return buflist_findnr((int)tv->vval.v_number);
1444 if (tv->v_type != VAR_STRING)
1445 return NULL;
1446 if (name == NULL || *name == NUL)
1447 return curbuf;
1448 if (name[0] == '$' && name[1] == NUL)
1449 return lastbuf;
1450
1451 buf = buflist_find_by_name(name, curtab_only);
1452
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001453 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001454 if (buf == NULL)
1455 buf = find_buffer(tv);
1456
1457 return buf;
1458}
1459
1460/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001461 * Get the buffer from "arg" and give an error and return NULL if it is not
1462 * valid.
1463 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001464 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001465get_buf_arg(typval_T *arg)
1466{
1467 buf_T *buf;
1468
1469 ++emsg_off;
1470 buf = tv_get_buf(arg, FALSE);
1471 --emsg_off;
1472 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001473 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001474 return buf;
1475}
1476
1477/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001478 * "byte2line(byte)" function
1479 */
1480 static void
1481f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1482{
1483#ifndef FEAT_BYTEOFF
1484 rettv->vval.v_number = -1;
1485#else
1486 long boff = 0;
1487
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001488 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001489 if (boff < 0)
1490 rettv->vval.v_number = -1;
1491 else
1492 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1493 (linenr_T)0, &boff);
1494#endif
1495}
1496
1497 static void
1498byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1499{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001500 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 char_u *str;
1502 varnumber_T idx;
1503
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001504 str = tv_get_string_chk(&argvars[0]);
1505 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506 rettv->vval.v_number = -1;
1507 if (str == NULL || idx < 0)
1508 return;
1509
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001510 t = str;
1511 for ( ; idx > 0; idx--)
1512 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001513 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001514 return;
1515 if (enc_utf8 && comp)
1516 t += utf_ptr2len(t);
1517 else
1518 t += (*mb_ptr2len)(t);
1519 }
1520 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001521}
1522
1523/*
1524 * "byteidx()" function
1525 */
1526 static void
1527f_byteidx(typval_T *argvars, typval_T *rettv)
1528{
1529 byteidx(argvars, rettv, FALSE);
1530}
1531
1532/*
1533 * "byteidxcomp()" function
1534 */
1535 static void
1536f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1537{
1538 byteidx(argvars, rettv, TRUE);
1539}
1540
1541/*
1542 * "call(func, arglist [, dict])" function
1543 */
1544 static void
1545f_call(typval_T *argvars, typval_T *rettv)
1546{
1547 char_u *func;
1548 partial_T *partial = NULL;
1549 dict_T *selfdict = NULL;
1550
1551 if (argvars[1].v_type != VAR_LIST)
1552 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001553 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001554 return;
1555 }
1556 if (argvars[1].vval.v_list == NULL)
1557 return;
1558
1559 if (argvars[0].v_type == VAR_FUNC)
1560 func = argvars[0].vval.v_string;
1561 else if (argvars[0].v_type == VAR_PARTIAL)
1562 {
1563 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001564 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001565 }
1566 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001567 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001568 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001569 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570
1571 if (argvars[2].v_type != VAR_UNKNOWN)
1572 {
1573 if (argvars[2].v_type != VAR_DICT)
1574 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001575 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 return;
1577 }
1578 selfdict = argvars[2].vval.v_dict;
1579 }
1580
1581 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1582}
1583
1584#ifdef FEAT_FLOAT
1585/*
1586 * "ceil({float})" function
1587 */
1588 static void
1589f_ceil(typval_T *argvars, typval_T *rettv)
1590{
1591 float_T f = 0.0;
1592
1593 rettv->v_type = VAR_FLOAT;
1594 if (get_float_arg(argvars, &f) == OK)
1595 rettv->vval.v_float = ceil(f);
1596 else
1597 rettv->vval.v_float = 0.0;
1598}
1599#endif
1600
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001601/*
1602 * "changenr()" function
1603 */
1604 static void
1605f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1606{
1607 rettv->vval.v_number = curbuf->b_u_seq_cur;
1608}
1609
1610/*
1611 * "char2nr(string)" function
1612 */
1613 static void
1614f_char2nr(typval_T *argvars, typval_T *rettv)
1615{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616 if (has_mbyte)
1617 {
1618 int utf8 = 0;
1619
1620 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001621 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622
1623 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001624 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001626 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001627 }
1628 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001629 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001630}
1631
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001632 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001633get_optional_window(typval_T *argvars, int idx)
1634{
1635 win_T *win = curwin;
1636
1637 if (argvars[idx].v_type != VAR_UNKNOWN)
1638 {
1639 win = find_win_by_nr_or_id(&argvars[idx]);
1640 if (win == NULL)
1641 {
1642 emsg(_(e_invalwindow));
1643 return NULL;
1644 }
1645 }
1646 return win;
1647}
1648
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001650 * "col(string)" function
1651 */
1652 static void
1653f_col(typval_T *argvars, typval_T *rettv)
1654{
1655 colnr_T col = 0;
1656 pos_T *fp;
1657 int fnum = curbuf->b_fnum;
1658
1659 fp = var2fpos(&argvars[0], FALSE, &fnum);
1660 if (fp != NULL && fnum == curbuf->b_fnum)
1661 {
1662 if (fp->col == MAXCOL)
1663 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001664 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001665 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1666 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1667 else
1668 col = MAXCOL;
1669 }
1670 else
1671 {
1672 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001673 // col(".") when the cursor is on the NUL at the end of the line
1674 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 if (virtual_active() && fp == &curwin->w_cursor)
1676 {
1677 char_u *p = ml_get_cursor();
1678
1679 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1680 curwin->w_virtcol - curwin->w_cursor.coladd))
1681 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001682 int l;
1683
1684 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1685 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686 }
1687 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 }
1689 }
1690 rettv->vval.v_number = col;
1691}
1692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001693/*
1694 * "confirm(message, buttons[, default [, type]])" function
1695 */
1696 static void
1697f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1698{
1699#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1700 char_u *message;
1701 char_u *buttons = NULL;
1702 char_u buf[NUMBUFLEN];
1703 char_u buf2[NUMBUFLEN];
1704 int def = 1;
1705 int type = VIM_GENERIC;
1706 char_u *typestr;
1707 int error = FALSE;
1708
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001709 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001710 if (message == NULL)
1711 error = TRUE;
1712 if (argvars[1].v_type != VAR_UNKNOWN)
1713 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001714 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001715 if (buttons == NULL)
1716 error = TRUE;
1717 if (argvars[2].v_type != VAR_UNKNOWN)
1718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001719 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720 if (argvars[3].v_type != VAR_UNKNOWN)
1721 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001722 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001723 if (typestr == NULL)
1724 error = TRUE;
1725 else
1726 {
1727 switch (TOUPPER_ASC(*typestr))
1728 {
1729 case 'E': type = VIM_ERROR; break;
1730 case 'Q': type = VIM_QUESTION; break;
1731 case 'I': type = VIM_INFO; break;
1732 case 'W': type = VIM_WARNING; break;
1733 case 'G': type = VIM_GENERIC; break;
1734 }
1735 }
1736 }
1737 }
1738 }
1739
1740 if (buttons == NULL || *buttons == NUL)
1741 buttons = (char_u *)_("&Ok");
1742
1743 if (!error)
1744 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1745 def, NULL, FALSE);
1746#endif
1747}
1748
1749/*
1750 * "copy()" function
1751 */
1752 static void
1753f_copy(typval_T *argvars, typval_T *rettv)
1754{
1755 item_copy(&argvars[0], rettv, FALSE, 0);
1756}
1757
1758#ifdef FEAT_FLOAT
1759/*
1760 * "cos()" function
1761 */
1762 static void
1763f_cos(typval_T *argvars, typval_T *rettv)
1764{
1765 float_T f = 0.0;
1766
1767 rettv->v_type = VAR_FLOAT;
1768 if (get_float_arg(argvars, &f) == OK)
1769 rettv->vval.v_float = cos(f);
1770 else
1771 rettv->vval.v_float = 0.0;
1772}
1773
1774/*
1775 * "cosh()" function
1776 */
1777 static void
1778f_cosh(typval_T *argvars, typval_T *rettv)
1779{
1780 float_T f = 0.0;
1781
1782 rettv->v_type = VAR_FLOAT;
1783 if (get_float_arg(argvars, &f) == OK)
1784 rettv->vval.v_float = cosh(f);
1785 else
1786 rettv->vval.v_float = 0.0;
1787}
1788#endif
1789
1790/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001791 * "cursor(lnum, col)" function, or
1792 * "cursor(list)"
1793 *
1794 * Moves the cursor to the specified line and column.
1795 * Returns 0 when the position could be set, -1 otherwise.
1796 */
1797 static void
1798f_cursor(typval_T *argvars, typval_T *rettv)
1799{
1800 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001801 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001802 int set_curswant = TRUE;
1803
1804 rettv->vval.v_number = -1;
1805 if (argvars[1].v_type == VAR_UNKNOWN)
1806 {
1807 pos_T pos;
1808 colnr_T curswant = -1;
1809
1810 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1811 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001812 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813 return;
1814 }
1815 line = pos.lnum;
1816 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001817 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001818 if (curswant >= 0)
1819 {
1820 curwin->w_curswant = curswant - 1;
1821 set_curswant = FALSE;
1822 }
1823 }
1824 else
1825 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001826 line = tv_get_lnum(argvars);
1827 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001828 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001829 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001831 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001832 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001833 if (line > 0)
1834 curwin->w_cursor.lnum = line;
1835 if (col > 0)
1836 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001837 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001838
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001839 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001840 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001841 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001842 if (has_mbyte)
1843 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844
1845 curwin->w_set_curswant = set_curswant;
1846 rettv->vval.v_number = 0;
1847}
1848
Bram Moolenaar4f974752019-02-17 17:44:42 +01001849#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001850/*
1851 * "debugbreak()" function
1852 */
1853 static void
1854f_debugbreak(typval_T *argvars, typval_T *rettv)
1855{
1856 int pid;
1857
1858 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001859 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001860 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001861 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001862 else
1863 {
1864 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1865
1866 if (hProcess != NULL)
1867 {
1868 DebugBreakProcess(hProcess);
1869 CloseHandle(hProcess);
1870 rettv->vval.v_number = OK;
1871 }
1872 }
1873}
1874#endif
1875
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001876/*
1877 * "deepcopy()" function
1878 */
1879 static void
1880f_deepcopy(typval_T *argvars, typval_T *rettv)
1881{
1882 int noref = 0;
1883 int copyID;
1884
1885 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001886 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001887 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001888 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001889 else
1890 {
1891 copyID = get_copyID();
1892 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1893 }
1894}
1895
1896/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001897 * "did_filetype()" function
1898 */
1899 static void
1900f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1901{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001902 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001903}
1904
1905/*
Bram Moolenaar4132eb52020-02-14 16:53:00 +01001906 * "echoraw({expr})" function
1907 */
1908 static void
1909f_echoraw(typval_T *argvars, typval_T *rettv UNUSED)
1910{
1911 char_u *str = tv_get_string_chk(&argvars[0]);
1912
1913 if (str != NULL && *str != NUL)
1914 {
1915 out_str(str);
1916 out_flush();
1917 }
1918}
1919
1920/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001921 * "empty({expr})" function
1922 */
1923 static void
1924f_empty(typval_T *argvars, typval_T *rettv)
1925{
1926 int n = FALSE;
1927
1928 switch (argvars[0].v_type)
1929 {
1930 case VAR_STRING:
1931 case VAR_FUNC:
1932 n = argvars[0].vval.v_string == NULL
1933 || *argvars[0].vval.v_string == NUL;
1934 break;
1935 case VAR_PARTIAL:
1936 n = FALSE;
1937 break;
1938 case VAR_NUMBER:
1939 n = argvars[0].vval.v_number == 0;
1940 break;
1941 case VAR_FLOAT:
1942#ifdef FEAT_FLOAT
1943 n = argvars[0].vval.v_float == 0.0;
1944 break;
1945#endif
1946 case VAR_LIST:
1947 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001948 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001949 break;
1950 case VAR_DICT:
1951 n = argvars[0].vval.v_dict == NULL
1952 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1953 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001954 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001955 case VAR_SPECIAL:
1956 n = argvars[0].vval.v_number != VVAL_TRUE;
1957 break;
1958
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001959 case VAR_BLOB:
1960 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001961 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1962 break;
1963
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001964 case VAR_JOB:
1965#ifdef FEAT_JOB_CHANNEL
1966 n = argvars[0].vval.v_job == NULL
1967 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1968 break;
1969#endif
1970 case VAR_CHANNEL:
1971#ifdef FEAT_JOB_CHANNEL
1972 n = argvars[0].vval.v_channel == NULL
1973 || !channel_is_open(argvars[0].vval.v_channel);
1974 break;
1975#endif
1976 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001977 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01001978 internal_error_no_abort("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001979 n = TRUE;
1980 break;
1981 }
1982
1983 rettv->vval.v_number = n;
1984}
1985
1986/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001987 * "environ()" function
1988 */
1989 static void
1990f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1991{
1992#if !defined(AMIGA)
1993 int i = 0;
1994 char_u *entry, *value;
1995# ifdef MSWIN
1996 extern wchar_t **_wenviron;
1997# else
1998 extern char **environ;
1999# endif
2000
2001 if (rettv_dict_alloc(rettv) != OK)
2002 return;
2003
2004# ifdef MSWIN
2005 if (*_wenviron == NULL)
2006 return;
2007# else
2008 if (*environ == NULL)
2009 return;
2010# endif
2011
2012 for (i = 0; ; ++i)
2013 {
2014# ifdef MSWIN
2015 short_u *p;
2016
2017 if ((p = (short_u *)_wenviron[i]) == NULL)
2018 return;
2019 entry = utf16_to_enc(p, NULL);
2020# else
2021 if ((entry = (char_u *)environ[i]) == NULL)
2022 return;
2023 entry = vim_strsave(entry);
2024# endif
2025 if (entry == NULL) // out of memory
2026 return;
2027 if ((value = vim_strchr(entry, '=')) == NULL)
2028 {
2029 vim_free(entry);
2030 continue;
2031 }
2032 *value++ = NUL;
2033 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2034 vim_free(entry);
2035 }
2036#endif
2037}
2038
2039/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002040 * "escape({string}, {chars})" function
2041 */
2042 static void
2043f_escape(typval_T *argvars, typval_T *rettv)
2044{
2045 char_u buf[NUMBUFLEN];
2046
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002047 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2048 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049 rettv->v_type = VAR_STRING;
2050}
2051
2052/*
2053 * "eval()" function
2054 */
2055 static void
2056f_eval(typval_T *argvars, typval_T *rettv)
2057{
2058 char_u *s, *p;
2059
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002060 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061 if (s != NULL)
2062 s = skipwhite(s);
2063
2064 p = s;
2065 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2066 {
2067 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002068 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002069 need_clr_eos = FALSE;
2070 rettv->v_type = VAR_NUMBER;
2071 rettv->vval.v_number = 0;
2072 }
2073 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002074 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002075}
2076
2077/*
2078 * "eventhandler()" function
2079 */
2080 static void
2081f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2082{
2083 rettv->vval.v_number = vgetc_busy;
2084}
2085
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086static garray_T redir_execute_ga;
2087
2088/*
2089 * Append "value[value_len]" to the execute() output.
2090 */
2091 void
2092execute_redir_str(char_u *value, int value_len)
2093{
2094 int len;
2095
2096 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002097 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002099 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002100 if (ga_grow(&redir_execute_ga, len) == OK)
2101 {
2102 mch_memmove((char *)redir_execute_ga.ga_data
2103 + redir_execute_ga.ga_len, value, len);
2104 redir_execute_ga.ga_len += len;
2105 }
2106}
2107
2108/*
2109 * Get next line from a list.
2110 * Called by do_cmdline() to get the next line.
2111 * Returns allocated string, or NULL for end of function.
2112 */
2113
2114 static char_u *
2115get_list_line(
2116 int c UNUSED,
2117 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002118 int indent UNUSED,
2119 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120{
2121 listitem_T **p = (listitem_T **)cookie;
2122 listitem_T *item = *p;
2123 char_u buf[NUMBUFLEN];
2124 char_u *s;
2125
2126 if (item == NULL)
2127 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002128 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002129 *p = item->li_next;
2130 return s == NULL ? NULL : vim_strsave(s);
2131}
2132
2133/*
2134 * "execute()" function
2135 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002136 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002137execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138{
2139 char_u *cmd = NULL;
2140 list_T *list = NULL;
2141 int save_msg_silent = msg_silent;
2142 int save_emsg_silent = emsg_silent;
2143 int save_emsg_noredir = emsg_noredir;
2144 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002145 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002146 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002147 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002148 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002149
2150 rettv->vval.v_string = NULL;
2151 rettv->v_type = VAR_STRING;
2152
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002153 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002155 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002156 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002157 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 return;
2159 ++list->lv_refcount;
2160 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002161 else if (argvars[arg_off].v_type == VAR_JOB
2162 || argvars[arg_off].v_type == VAR_CHANNEL)
2163 {
2164 emsg(_(e_inval_string));
2165 return;
2166 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002167 else
2168 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002169 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002170 if (cmd == NULL)
2171 return;
2172 }
2173
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002174 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 {
2176 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002177 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178
2179 if (s == NULL)
2180 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002181 if (*s == NUL)
2182 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002183 if (STRNCMP(s, "silent", 6) == 0)
2184 ++msg_silent;
2185 if (STRCMP(s, "silent!") == 0)
2186 {
2187 emsg_silent = TRUE;
2188 emsg_noredir = TRUE;
2189 }
2190 }
2191 else
2192 ++msg_silent;
2193
2194 if (redir_execute)
2195 save_ga = redir_execute_ga;
2196 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2197 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002198 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002199 if (!echo_output)
2200 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002201
2202 if (cmd != NULL)
2203 do_cmdline_cmd(cmd);
2204 else
2205 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002206 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002208 range_list_materialize(list);
2209 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002210 do_cmdline(NULL, get_list_line, (void *)&item,
2211 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2212 --list->lv_refcount;
2213 }
2214
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002215 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002216 if (ga_grow(&redir_execute_ga, 1) == OK)
2217 {
2218 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2219 rettv->vval.v_string = redir_execute_ga.ga_data;
2220 }
2221 else
2222 {
2223 ga_clear(&redir_execute_ga);
2224 rettv->vval.v_string = NULL;
2225 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002226 msg_silent = save_msg_silent;
2227 emsg_silent = save_emsg_silent;
2228 emsg_noredir = save_emsg_noredir;
2229
2230 redir_execute = save_redir_execute;
2231 if (redir_execute)
2232 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002233 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002234
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002235 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002236 if (echo_output)
2237 // When not working silently: put it in column zero. A following
2238 // "echon" will overwrite the message, unavoidably.
2239 msg_col = 0;
2240 else
2241 // When working silently: Put it back where it was, since nothing
2242 // should have been written.
2243 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002244}
2245
2246/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002247 * "execute()" function
2248 */
2249 static void
2250f_execute(typval_T *argvars, typval_T *rettv)
2251{
2252 execute_common(argvars, rettv, 0);
2253}
2254
2255/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256 * "exists()" function
2257 */
2258 static void
2259f_exists(typval_T *argvars, typval_T *rettv)
2260{
2261 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002262 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002263
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002264 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002265 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002267 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 if (mch_getenv(p + 1) != NULL)
2269 n = TRUE;
2270 else
2271 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002272 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002273 p = expand_env_save(p);
2274 if (p != NULL && *p != '$')
2275 n = TRUE;
2276 vim_free(p);
2277 }
2278 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002279 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 {
2281 n = (get_option_tv(&p, NULL, TRUE) == OK);
2282 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002283 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002284 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002285 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002286 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002287 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002288 }
2289 else if (*p == ':')
2290 {
2291 n = cmd_exists(p + 1);
2292 }
2293 else if (*p == '#')
2294 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295 if (p[1] == '#')
2296 n = autocmd_supported(p + 2);
2297 else
2298 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002299 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002300 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002302 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303 }
2304
2305 rettv->vval.v_number = n;
2306}
2307
2308#ifdef FEAT_FLOAT
2309/*
2310 * "exp()" function
2311 */
2312 static void
2313f_exp(typval_T *argvars, typval_T *rettv)
2314{
2315 float_T f = 0.0;
2316
2317 rettv->v_type = VAR_FLOAT;
2318 if (get_float_arg(argvars, &f) == OK)
2319 rettv->vval.v_float = exp(f);
2320 else
2321 rettv->vval.v_float = 0.0;
2322}
2323#endif
2324
2325/*
2326 * "expand()" function
2327 */
2328 static void
2329f_expand(typval_T *argvars, typval_T *rettv)
2330{
2331 char_u *s;
2332 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002333 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002334 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2335 expand_T xpc;
2336 int error = FALSE;
2337 char_u *result;
2338
2339 rettv->v_type = VAR_STRING;
2340 if (argvars[1].v_type != VAR_UNKNOWN
2341 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002342 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002343 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002344 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002346 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347 if (*s == '%' || *s == '#' || *s == '<')
2348 {
2349 ++emsg_off;
2350 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2351 --emsg_off;
2352 if (rettv->v_type == VAR_LIST)
2353 {
2354 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2355 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002356 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002357 }
2358 else
2359 rettv->vval.v_string = result;
2360 }
2361 else
2362 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002363 // When the optional second argument is non-zero, don't remove matches
2364 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002366 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002367 options |= WILD_KEEP_ALL;
2368 if (!error)
2369 {
2370 ExpandInit(&xpc);
2371 xpc.xp_context = EXPAND_FILES;
2372 if (p_wic)
2373 options += WILD_ICASE;
2374 if (rettv->v_type == VAR_STRING)
2375 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2376 options, WILD_ALL);
2377 else if (rettv_list_alloc(rettv) != FAIL)
2378 {
2379 int i;
2380
2381 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2382 for (i = 0; i < xpc.xp_numfiles; i++)
2383 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2384 ExpandCleanup(&xpc);
2385 }
2386 }
2387 else
2388 rettv->vval.v_string = NULL;
2389 }
2390}
2391
2392/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002393 * "expandcmd()" function
2394 * Expand all the special characters in a command string.
2395 */
2396 static void
2397f_expandcmd(typval_T *argvars, typval_T *rettv)
2398{
2399 exarg_T eap;
2400 char_u *cmdstr;
2401 char *errormsg = NULL;
2402
2403 rettv->v_type = VAR_STRING;
2404 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2405
2406 memset(&eap, 0, sizeof(eap));
2407 eap.cmd = cmdstr;
2408 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002409 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002410 eap.usefilter = FALSE;
2411 eap.nextcmd = NULL;
2412 eap.cmdidx = CMD_USER;
2413
2414 expand_filename(&eap, &cmdstr, &errormsg);
2415 if (errormsg != NULL && *errormsg != NUL)
2416 emsg(errormsg);
2417
2418 rettv->vval.v_string = cmdstr;
2419}
2420
2421/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002422 * "feedkeys()" function
2423 */
2424 static void
2425f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2426{
2427 int remap = TRUE;
2428 int insert = FALSE;
2429 char_u *keys, *flags;
2430 char_u nbuf[NUMBUFLEN];
2431 int typed = FALSE;
2432 int execute = FALSE;
2433 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002434 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002435 char_u *keys_esc;
2436
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002437 // This is not allowed in the sandbox. If the commands would still be
2438 // executed in the sandbox it would be OK, but it probably happens later,
2439 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440 if (check_secure())
2441 return;
2442
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002443 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002444
2445 if (argvars[1].v_type != VAR_UNKNOWN)
2446 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002447 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 for ( ; *flags != NUL; ++flags)
2449 {
2450 switch (*flags)
2451 {
2452 case 'n': remap = FALSE; break;
2453 case 'm': remap = TRUE; break;
2454 case 't': typed = TRUE; break;
2455 case 'i': insert = TRUE; break;
2456 case 'x': execute = TRUE; break;
2457 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002458 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459 }
2460 }
2461 }
2462
2463 if (*keys != NUL || execute)
2464 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002465 // Need to escape K_SPECIAL and CSI before putting the string in the
2466 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467 keys_esc = vim_strsave_escape_csi(keys);
2468 if (keys_esc != NULL)
2469 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002470 if (lowlevel)
2471 {
2472#ifdef USE_INPUT_BUF
Bram Moolenaar0eabd4d2020-03-15 16:13:53 +01002473 int idx;
2474 int len = (int)STRLEN(keys);
2475
2476 for (idx = 0; idx < len; ++idx)
2477 {
2478 // if a CTRL-C was typed, set got_int
2479 if (keys[idx] == 3 && ctrl_c_interrupts)
2480 got_int = TRUE;
2481 else
2482 add_to_input_buf(keys + idx, 1);
2483 }
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002484#else
2485 emsg(_("E980: lowlevel input not supported"));
2486#endif
2487 }
2488 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002489 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002490 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002491 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002492 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002493#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002494 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002495#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002496 )
2497 typebuf_was_filled = TRUE;
2498 }
2499 vim_free(keys_esc);
2500
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002501 if (execute)
2502 {
2503 int save_msg_scroll = msg_scroll;
2504
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002505 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002506 msg_scroll = FALSE;
2507
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002508 if (!dangerous)
2509 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002510 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002511 if (!dangerous)
2512 --ex_normal_busy;
2513
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002514 msg_scroll |= save_msg_scroll;
2515 }
2516 }
2517 }
2518}
2519
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002520#ifdef FEAT_FLOAT
2521/*
2522 * "float2nr({float})" function
2523 */
2524 static void
2525f_float2nr(typval_T *argvars, typval_T *rettv)
2526{
2527 float_T f = 0.0;
2528
2529 if (get_float_arg(argvars, &f) == OK)
2530 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002531 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002532 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002533 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002534 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002535 else
2536 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 }
2538}
2539
2540/*
2541 * "floor({float})" function
2542 */
2543 static void
2544f_floor(typval_T *argvars, typval_T *rettv)
2545{
2546 float_T f = 0.0;
2547
2548 rettv->v_type = VAR_FLOAT;
2549 if (get_float_arg(argvars, &f) == OK)
2550 rettv->vval.v_float = floor(f);
2551 else
2552 rettv->vval.v_float = 0.0;
2553}
2554
2555/*
2556 * "fmod()" function
2557 */
2558 static void
2559f_fmod(typval_T *argvars, typval_T *rettv)
2560{
2561 float_T fx = 0.0, fy = 0.0;
2562
2563 rettv->v_type = VAR_FLOAT;
2564 if (get_float_arg(argvars, &fx) == OK
2565 && get_float_arg(&argvars[1], &fy) == OK)
2566 rettv->vval.v_float = fmod(fx, fy);
2567 else
2568 rettv->vval.v_float = 0.0;
2569}
2570#endif
2571
2572/*
2573 * "fnameescape({string})" function
2574 */
2575 static void
2576f_fnameescape(typval_T *argvars, typval_T *rettv)
2577{
2578 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002579 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002580 rettv->v_type = VAR_STRING;
2581}
2582
2583/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002584 * "foreground()" function
2585 */
2586 static void
2587f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2588{
2589#ifdef FEAT_GUI
2590 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002591 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002592 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002593 return;
2594 }
2595#endif
2596#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002597 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002598#endif
2599}
2600
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002601 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002602common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002603{
2604 char_u *s;
2605 char_u *name;
2606 int use_string = FALSE;
2607 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002608 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609
2610 if (argvars[0].v_type == VAR_FUNC)
2611 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002612 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002613 s = argvars[0].vval.v_string;
2614 }
2615 else if (argvars[0].v_type == VAR_PARTIAL
2616 && argvars[0].vval.v_partial != NULL)
2617 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002618 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002619 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002620 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621 }
2622 else
2623 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002624 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002625 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002626 use_string = TRUE;
2627 }
2628
Bram Moolenaar843b8842016-08-21 14:36:15 +02002629 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002630 {
2631 name = s;
2632 trans_name = trans_function_name(&name, FALSE,
2633 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2634 if (*name != NUL)
2635 s = NULL;
2636 }
2637
Bram Moolenaar843b8842016-08-21 14:36:15 +02002638 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2639 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002640 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002641 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002642 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002643 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002645 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002646 else
2647 {
2648 int dict_idx = 0;
2649 int arg_idx = 0;
2650 list_T *list = NULL;
2651
2652 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2653 {
2654 char sid_buf[25];
2655 int off = *s == 's' ? 2 : 5;
2656
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002657 // Expand s: and <SID> into <SNR>nr_, so that the function can
2658 // also be called from another script. Using trans_function_name()
2659 // would also work, but some plugins depend on the name being
2660 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002661 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002662 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002663 if (name != NULL)
2664 {
2665 STRCPY(name, sid_buf);
2666 STRCAT(name, s + off);
2667 }
2668 }
2669 else
2670 name = vim_strsave(s);
2671
2672 if (argvars[1].v_type != VAR_UNKNOWN)
2673 {
2674 if (argvars[2].v_type != VAR_UNKNOWN)
2675 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002676 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 arg_idx = 1;
2678 dict_idx = 2;
2679 }
2680 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002681 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 dict_idx = 1;
2683 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002684 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002685 arg_idx = 1;
2686 if (dict_idx > 0)
2687 {
2688 if (argvars[dict_idx].v_type != VAR_DICT)
2689 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002690 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002692 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 }
2694 if (argvars[dict_idx].vval.v_dict == NULL)
2695 dict_idx = 0;
2696 }
2697 if (arg_idx > 0)
2698 {
2699 if (argvars[arg_idx].v_type != VAR_LIST)
2700 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002701 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002702 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002703 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 }
2705 list = argvars[arg_idx].vval.v_list;
2706 if (list == NULL || list->lv_len == 0)
2707 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002708 else if (list->lv_len > MAX_FUNC_ARGS)
2709 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002710 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002711 vim_free(name);
2712 goto theend;
2713 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002714 }
2715 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002716 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002717 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002718 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002720 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002721 if (pt == NULL)
2722 vim_free(name);
2723 else
2724 {
2725 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2726 {
2727 listitem_T *li;
2728 int i = 0;
2729 int arg_len = 0;
2730 int lv_len = 0;
2731
2732 if (arg_pt != NULL)
2733 arg_len = arg_pt->pt_argc;
2734 if (list != NULL)
2735 lv_len = list->lv_len;
2736 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002737 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002738 if (pt->pt_argv == NULL)
2739 {
2740 vim_free(pt);
2741 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002742 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002743 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002744 for (i = 0; i < arg_len; i++)
2745 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2746 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002747 {
2748 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002749 for (li = list->lv_first; li != NULL;
2750 li = li->li_next)
2751 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002752 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002753 }
2754
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002755 // For "function(dict.func, [], dict)" and "func" is a partial
2756 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002757 if (dict_idx > 0)
2758 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002759 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002760 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2761 ++pt->pt_dict->dv_refcount;
2762 }
2763 else if (arg_pt != NULL)
2764 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002765 // If the dict was bound automatically the result is also
2766 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002767 pt->pt_dict = arg_pt->pt_dict;
2768 pt->pt_auto = arg_pt->pt_auto;
2769 if (pt->pt_dict != NULL)
2770 ++pt->pt_dict->dv_refcount;
2771 }
2772
2773 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002774 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2775 {
2776 pt->pt_func = arg_pt->pt_func;
2777 func_ptr_ref(pt->pt_func);
2778 vim_free(name);
2779 }
2780 else if (is_funcref)
2781 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002782 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002783 func_ptr_ref(pt->pt_func);
2784 vim_free(name);
2785 }
2786 else
2787 {
2788 pt->pt_name = name;
2789 func_ref(name);
2790 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002791 }
2792 rettv->v_type = VAR_PARTIAL;
2793 rettv->vval.v_partial = pt;
2794 }
2795 else
2796 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002797 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002798 rettv->v_type = VAR_FUNC;
2799 rettv->vval.v_string = name;
2800 func_ref(name);
2801 }
2802 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002803theend:
2804 vim_free(trans_name);
2805}
2806
2807/*
2808 * "funcref()" function
2809 */
2810 static void
2811f_funcref(typval_T *argvars, typval_T *rettv)
2812{
2813 common_function(argvars, rettv, TRUE);
2814}
2815
Bram Moolenaarfbdd08e2020-03-01 14:04:46 +01002816 static type_T *
2817ret_f_function(int argcount, type_T **argtypes UNUSED)
2818{
2819 if (argcount == 1 && argtypes[0]->tt_type == VAR_STRING)
2820 return &t_func_any;
2821 return &t_partial_void;
2822}
2823
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002824/*
2825 * "function()" function
2826 */
2827 static void
2828f_function(typval_T *argvars, typval_T *rettv)
2829{
2830 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002831}
2832
2833/*
2834 * "garbagecollect()" function
2835 */
2836 static void
2837f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2838{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002839 // This is postponed until we are back at the toplevel, because we may be
2840 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002841 want_garbage_collect = TRUE;
2842
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002843 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002844 garbage_collect_at_exit = TRUE;
2845}
2846
2847/*
2848 * "get()" function
2849 */
2850 static void
2851f_get(typval_T *argvars, typval_T *rettv)
2852{
2853 listitem_T *li;
2854 list_T *l;
2855 dictitem_T *di;
2856 dict_T *d;
2857 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002858 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002859
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002860 if (argvars[0].v_type == VAR_BLOB)
2861 {
2862 int error = FALSE;
2863 int idx = tv_get_number_chk(&argvars[1], &error);
2864
2865 if (!error)
2866 {
2867 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002868 if (idx < 0)
2869 idx = blob_len(argvars[0].vval.v_blob) + idx;
2870 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2871 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002872 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002873 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002874 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002875 tv = rettv;
2876 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002877 }
2878 }
2879 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002880 {
2881 if ((l = argvars[0].vval.v_list) != NULL)
2882 {
2883 int error = FALSE;
2884
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002885 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002886 if (!error && li != NULL)
2887 tv = &li->li_tv;
2888 }
2889 }
2890 else if (argvars[0].v_type == VAR_DICT)
2891 {
2892 if ((d = argvars[0].vval.v_dict) != NULL)
2893 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002894 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002895 if (di != NULL)
2896 tv = &di->di_tv;
2897 }
2898 }
2899 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2900 {
2901 partial_T *pt;
2902 partial_T fref_pt;
2903
2904 if (argvars[0].v_type == VAR_PARTIAL)
2905 pt = argvars[0].vval.v_partial;
2906 else
2907 {
2908 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2909 fref_pt.pt_name = argvars[0].vval.v_string;
2910 pt = &fref_pt;
2911 }
2912
2913 if (pt != NULL)
2914 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002915 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002916 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002917
2918 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2919 {
2920 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002921 n = partial_name(pt);
2922 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002923 rettv->vval.v_string = NULL;
2924 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002925 {
2926 rettv->vval.v_string = vim_strsave(n);
2927 if (rettv->v_type == VAR_FUNC)
2928 func_ref(rettv->vval.v_string);
2929 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002930 }
2931 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002932 {
2933 what_is_dict = TRUE;
2934 if (pt->pt_dict != NULL)
2935 rettv_dict_set(rettv, pt->pt_dict);
2936 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002937 else if (STRCMP(what, "args") == 0)
2938 {
2939 rettv->v_type = VAR_LIST;
2940 if (rettv_list_alloc(rettv) == OK)
2941 {
2942 int i;
2943
2944 for (i = 0; i < pt->pt_argc; ++i)
2945 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2946 }
2947 }
2948 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002949 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002950
2951 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2952 // third argument
2953 if (!what_is_dict)
2954 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002955 }
2956 }
2957 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002958 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002959
2960 if (tv == NULL)
2961 {
2962 if (argvars[2].v_type != VAR_UNKNOWN)
2963 copy_tv(&argvars[2], rettv);
2964 }
2965 else
2966 copy_tv(tv, rettv);
2967}
2968
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002969/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002970 * "getchangelist()" function
2971 */
2972 static void
2973f_getchangelist(typval_T *argvars, typval_T *rettv)
2974{
2975#ifdef FEAT_JUMPLIST
2976 buf_T *buf;
2977 int i;
2978 list_T *l;
2979 dict_T *d;
2980#endif
2981
2982 if (rettv_list_alloc(rettv) != OK)
2983 return;
2984
2985#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002986 if (argvars[0].v_type == VAR_UNKNOWN)
2987 buf = curbuf;
2988 else
2989 {
2990 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2991 ++emsg_off;
2992 buf = tv_get_buf(&argvars[0], FALSE);
2993 --emsg_off;
2994 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002995 if (buf == NULL)
2996 return;
2997
2998 l = list_alloc();
2999 if (l == NULL)
3000 return;
3001
3002 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3003 return;
3004 /*
3005 * The current window change list index tracks only the position in the
3006 * current buffer change list. For other buffers, use the change list
3007 * length as the current index.
3008 */
3009 list_append_number(rettv->vval.v_list,
3010 (varnumber_T)((buf == curwin->w_buffer)
3011 ? curwin->w_changelistidx : buf->b_changelistlen));
3012
3013 for (i = 0; i < buf->b_changelistlen; ++i)
3014 {
3015 if (buf->b_changelist[i].lnum == 0)
3016 continue;
3017 if ((d = dict_alloc()) == NULL)
3018 return;
3019 if (list_append_dict(l, d) == FAIL)
3020 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003021 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3022 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003023 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003024 }
3025#endif
3026}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003027
3028/*
3029 * "getcharsearch()" function
3030 */
3031 static void
3032f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3033{
3034 if (rettv_dict_alloc(rettv) != FAIL)
3035 {
3036 dict_T *dict = rettv->vval.v_dict;
3037
Bram Moolenaare0be1672018-07-08 16:50:37 +02003038 dict_add_string(dict, "char", last_csearch());
3039 dict_add_number(dict, "forward", last_csearch_forward());
3040 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003041 }
3042}
3043
3044/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003045 * "getenv()" function
3046 */
3047 static void
3048f_getenv(typval_T *argvars, typval_T *rettv)
3049{
3050 int mustfree = FALSE;
3051 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3052
3053 if (p == NULL)
3054 {
3055 rettv->v_type = VAR_SPECIAL;
3056 rettv->vval.v_number = VVAL_NULL;
3057 return;
3058 }
3059 if (!mustfree)
3060 p = vim_strsave(p);
3061 rettv->vval.v_string = p;
3062 rettv->v_type = VAR_STRING;
3063}
3064
3065/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003066 * "getfontname()" function
3067 */
3068 static void
3069f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3070{
3071 rettv->v_type = VAR_STRING;
3072 rettv->vval.v_string = NULL;
3073#ifdef FEAT_GUI
3074 if (gui.in_use)
3075 {
3076 GuiFont font;
3077 char_u *name = NULL;
3078
3079 if (argvars[0].v_type == VAR_UNKNOWN)
3080 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003081 // Get the "Normal" font. Either the name saved by
3082 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003083 font = gui.norm_font;
3084 name = hl_get_font_name();
3085 }
3086 else
3087 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003088 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003089 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003090 return;
3091 font = gui_mch_get_font(name, FALSE);
3092 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003093 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003094 }
3095 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3096 if (argvars[0].v_type != VAR_UNKNOWN)
3097 gui_mch_free_font(font);
3098 }
3099#endif
3100}
3101
3102/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003103 * "getjumplist()" function
3104 */
3105 static void
3106f_getjumplist(typval_T *argvars, typval_T *rettv)
3107{
3108#ifdef FEAT_JUMPLIST
3109 win_T *wp;
3110 int i;
3111 list_T *l;
3112 dict_T *d;
3113#endif
3114
3115 if (rettv_list_alloc(rettv) != OK)
3116 return;
3117
3118#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003119 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003120 if (wp == NULL)
3121 return;
3122
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003123 cleanup_jumplist(wp, TRUE);
3124
Bram Moolenaar4f505882018-02-10 21:06:32 +01003125 l = list_alloc();
3126 if (l == NULL)
3127 return;
3128
3129 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3130 return;
3131 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3132
3133 for (i = 0; i < wp->w_jumplistlen; ++i)
3134 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003135 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3136 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003137 if ((d = dict_alloc()) == NULL)
3138 return;
3139 if (list_append_dict(l, d) == FAIL)
3140 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003141 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3142 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003143 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003144 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003145 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003146 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003147 }
3148#endif
3149}
3150
3151/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003152 * "getpid()" function
3153 */
3154 static void
3155f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3156{
3157 rettv->vval.v_number = mch_get_pid();
3158}
3159
3160 static void
3161getpos_both(
3162 typval_T *argvars,
3163 typval_T *rettv,
3164 int getcurpos)
3165{
3166 pos_T *fp;
3167 list_T *l;
3168 int fnum = -1;
3169
3170 if (rettv_list_alloc(rettv) == OK)
3171 {
3172 l = rettv->vval.v_list;
3173 if (getcurpos)
3174 fp = &curwin->w_cursor;
3175 else
3176 fp = var2fpos(&argvars[0], TRUE, &fnum);
3177 if (fnum != -1)
3178 list_append_number(l, (varnumber_T)fnum);
3179 else
3180 list_append_number(l, (varnumber_T)0);
3181 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3182 : (varnumber_T)0);
3183 list_append_number(l, (fp != NULL)
3184 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3185 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003186 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003187 (varnumber_T)0);
3188 if (getcurpos)
3189 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003190 int save_set_curswant = curwin->w_set_curswant;
3191 colnr_T save_curswant = curwin->w_curswant;
3192 colnr_T save_virtcol = curwin->w_virtcol;
3193
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003194 update_curswant();
3195 list_append_number(l, curwin->w_curswant == MAXCOL ?
3196 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003197
3198 // Do not change "curswant", as it is unexpected that a get
3199 // function has a side effect.
3200 if (save_set_curswant)
3201 {
3202 curwin->w_set_curswant = save_set_curswant;
3203 curwin->w_curswant = save_curswant;
3204 curwin->w_virtcol = save_virtcol;
3205 curwin->w_valid &= ~VALID_VIRTCOL;
3206 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003207 }
3208 }
3209 else
3210 rettv->vval.v_number = FALSE;
3211}
3212
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003213/*
3214 * "getcurpos()" function
3215 */
3216 static void
3217f_getcurpos(typval_T *argvars, typval_T *rettv)
3218{
3219 getpos_both(argvars, rettv, TRUE);
3220}
3221
3222/*
3223 * "getpos(string)" function
3224 */
3225 static void
3226f_getpos(typval_T *argvars, typval_T *rettv)
3227{
3228 getpos_both(argvars, rettv, FALSE);
3229}
3230
3231/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003232 * "getreg()" function
3233 */
3234 static void
3235f_getreg(typval_T *argvars, typval_T *rettv)
3236{
3237 char_u *strregname;
3238 int regname;
3239 int arg2 = FALSE;
3240 int return_list = FALSE;
3241 int error = FALSE;
3242
3243 if (argvars[0].v_type != VAR_UNKNOWN)
3244 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003245 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003246 error = strregname == NULL;
3247 if (argvars[1].v_type != VAR_UNKNOWN)
3248 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003249 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003250 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003251 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003252 }
3253 }
3254 else
3255 strregname = get_vim_var_str(VV_REG);
3256
3257 if (error)
3258 return;
3259
3260 regname = (strregname == NULL ? '"' : *strregname);
3261 if (regname == 0)
3262 regname = '"';
3263
3264 if (return_list)
3265 {
3266 rettv->v_type = VAR_LIST;
3267 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3268 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3269 if (rettv->vval.v_list == NULL)
3270 (void)rettv_list_alloc(rettv);
3271 else
3272 ++rettv->vval.v_list->lv_refcount;
3273 }
3274 else
3275 {
3276 rettv->v_type = VAR_STRING;
3277 rettv->vval.v_string = get_reg_contents(regname,
3278 arg2 ? GREG_EXPR_SRC : 0);
3279 }
3280}
3281
3282/*
3283 * "getregtype()" function
3284 */
3285 static void
3286f_getregtype(typval_T *argvars, typval_T *rettv)
3287{
3288 char_u *strregname;
3289 int regname;
3290 char_u buf[NUMBUFLEN + 2];
3291 long reglen = 0;
3292
3293 if (argvars[0].v_type != VAR_UNKNOWN)
3294 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003295 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003296 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 {
3298 rettv->v_type = VAR_STRING;
3299 rettv->vval.v_string = NULL;
3300 return;
3301 }
3302 }
3303 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003304 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003305 strregname = get_vim_var_str(VV_REG);
3306
3307 regname = (strregname == NULL ? '"' : *strregname);
3308 if (regname == 0)
3309 regname = '"';
3310
3311 buf[0] = NUL;
3312 buf[1] = NUL;
3313 switch (get_reg_type(regname, &reglen))
3314 {
3315 case MLINE: buf[0] = 'V'; break;
3316 case MCHAR: buf[0] = 'v'; break;
3317 case MBLOCK:
3318 buf[0] = Ctrl_V;
3319 sprintf((char *)buf + 1, "%ld", reglen + 1);
3320 break;
3321 }
3322 rettv->v_type = VAR_STRING;
3323 rettv->vval.v_string = vim_strsave(buf);
3324}
3325
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003326/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003327 * "gettagstack()" function
3328 */
3329 static void
3330f_gettagstack(typval_T *argvars, typval_T *rettv)
3331{
3332 win_T *wp = curwin; // default is current window
3333
3334 if (rettv_dict_alloc(rettv) != OK)
3335 return;
3336
3337 if (argvars[0].v_type != VAR_UNKNOWN)
3338 {
3339 wp = find_win_by_nr_or_id(&argvars[0]);
3340 if (wp == NULL)
3341 return;
3342 }
3343
3344 get_tagstack(wp, rettv->vval.v_dict);
3345}
3346
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003347// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003348#include "version.h"
3349
3350/*
3351 * "has()" function
3352 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003353 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003354f_has(typval_T *argvars, typval_T *rettv)
3355{
3356 int i;
3357 char_u *name;
3358 int n = FALSE;
3359 static char *(has_list[]) =
3360 {
3361#ifdef AMIGA
3362 "amiga",
3363# ifdef FEAT_ARP
3364 "arp",
3365# endif
3366#endif
3367#ifdef __BEOS__
3368 "beos",
3369#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003370#ifdef __HAIKU__
3371 "haiku",
3372#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003373#if defined(BSD) && !defined(MACOS_X)
3374 "bsd",
3375#endif
3376#ifdef hpux
3377 "hpux",
3378#endif
3379#ifdef __linux__
3380 "linux",
3381#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003382#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003383 "mac", // Mac OS X (and, once, Mac OS Classic)
3384 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003385# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003386 "macunix", // Mac OS X, with the darwin feature
3387 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003388# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003389#endif
3390#ifdef __QNX__
3391 "qnx",
3392#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003393#ifdef SUN_SYSTEM
3394 "sun",
3395#else
3396 "moon",
3397#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003398#ifdef UNIX
3399 "unix",
3400#endif
3401#ifdef VMS
3402 "vms",
3403#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003404#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003405 "win32",
3406#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003407#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003408 "win32unix",
3409#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003410#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003411 "win64",
3412#endif
3413#ifdef EBCDIC
3414 "ebcdic",
3415#endif
3416#ifndef CASE_INSENSITIVE_FILENAME
3417 "fname_case",
3418#endif
3419#ifdef HAVE_ACL
3420 "acl",
3421#endif
3422#ifdef FEAT_ARABIC
3423 "arabic",
3424#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003425 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003426#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003427 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003428#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003429#ifdef FEAT_AUTOSERVERNAME
3430 "autoservername",
3431#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003432#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003433 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003434# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003435 "balloon_multiline",
3436# endif
3437#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003438#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003439 "balloon_eval_term",
3440#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003441#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3442 "builtin_terms",
3443# ifdef ALL_BUILTIN_TCAPS
3444 "all_builtin_terms",
3445# endif
3446#endif
3447#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003448 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003449 || defined(FEAT_GUI_MOTIF))
3450 "browsefilter",
3451#endif
3452#ifdef FEAT_BYTEOFF
3453 "byte_offset",
3454#endif
3455#ifdef FEAT_JOB_CHANNEL
3456 "channel",
3457#endif
3458#ifdef FEAT_CINDENT
3459 "cindent",
3460#endif
3461#ifdef FEAT_CLIENTSERVER
3462 "clientserver",
3463#endif
3464#ifdef FEAT_CLIPBOARD
3465 "clipboard",
3466#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003467 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003468 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003469 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470#ifdef FEAT_CONCEAL
3471 "conceal",
3472#endif
3473#ifdef FEAT_CRYPT
3474 "cryptv",
3475 "crypt-blowfish",
3476 "crypt-blowfish2",
3477#endif
3478#ifdef FEAT_CSCOPE
3479 "cscope",
3480#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003481 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003482#ifdef CURSOR_SHAPE
3483 "cursorshape",
3484#endif
3485#ifdef DEBUG
3486 "debug",
3487#endif
3488#ifdef FEAT_CON_DIALOG
3489 "dialog_con",
3490#endif
3491#ifdef FEAT_GUI_DIALOG
3492 "dialog_gui",
3493#endif
3494#ifdef FEAT_DIFF
3495 "diff",
3496#endif
3497#ifdef FEAT_DIGRAPHS
3498 "digraphs",
3499#endif
3500#ifdef FEAT_DIRECTX
3501 "directx",
3502#endif
3503#ifdef FEAT_DND
3504 "dnd",
3505#endif
3506#ifdef FEAT_EMACS_TAGS
3507 "emacs_tags",
3508#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003509 "eval", // always present, of course!
3510 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003511#ifdef FEAT_SEARCH_EXTRA
3512 "extra_search",
3513#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003514#ifdef FEAT_SEARCHPATH
3515 "file_in_path",
3516#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003517#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003518 "filterpipe",
3519#endif
3520#ifdef FEAT_FIND_ID
3521 "find_in_path",
3522#endif
3523#ifdef FEAT_FLOAT
3524 "float",
3525#endif
3526#ifdef FEAT_FOLDING
3527 "folding",
3528#endif
3529#ifdef FEAT_FOOTER
3530 "footer",
3531#endif
3532#if !defined(USE_SYSTEM) && defined(UNIX)
3533 "fork",
3534#endif
3535#ifdef FEAT_GETTEXT
3536 "gettext",
3537#endif
3538#ifdef FEAT_GUI
3539 "gui",
3540#endif
3541#ifdef FEAT_GUI_ATHENA
3542# ifdef FEAT_GUI_NEXTAW
3543 "gui_neXtaw",
3544# else
3545 "gui_athena",
3546# endif
3547#endif
3548#ifdef FEAT_GUI_GTK
3549 "gui_gtk",
3550# ifdef USE_GTK3
3551 "gui_gtk3",
3552# else
3553 "gui_gtk2",
3554# endif
3555#endif
3556#ifdef FEAT_GUI_GNOME
3557 "gui_gnome",
3558#endif
Bram Moolenaarb3f74062020-02-26 16:16:53 +01003559#ifdef FEAT_GUI_HAIKU
3560 "gui_haiku",
3561#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003562#ifdef FEAT_GUI_MAC
3563 "gui_mac",
3564#endif
3565#ifdef FEAT_GUI_MOTIF
3566 "gui_motif",
3567#endif
3568#ifdef FEAT_GUI_PHOTON
3569 "gui_photon",
3570#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003571#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572 "gui_win32",
3573#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003574#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3575 "iconv",
3576#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003577 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003578#ifdef FEAT_JOB_CHANNEL
3579 "job",
3580#endif
3581#ifdef FEAT_JUMPLIST
3582 "jumplist",
3583#endif
3584#ifdef FEAT_KEYMAP
3585 "keymap",
3586#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003587 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003588#ifdef FEAT_LANGMAP
3589 "langmap",
3590#endif
3591#ifdef FEAT_LIBCALL
3592 "libcall",
3593#endif
3594#ifdef FEAT_LINEBREAK
3595 "linebreak",
3596#endif
3597#ifdef FEAT_LISP
3598 "lispindent",
3599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003601 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602#ifdef FEAT_LUA
3603# ifndef DYNAMIC_LUA
3604 "lua",
3605# endif
3606#endif
3607#ifdef FEAT_MENU
3608 "menu",
3609#endif
3610#ifdef FEAT_SESSION
3611 "mksession",
3612#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003613 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003614 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003615#ifdef FEAT_MOUSESHAPE
3616 "mouseshape",
3617#endif
3618#if defined(UNIX) || defined(VMS)
3619# ifdef FEAT_MOUSE_DEC
3620 "mouse_dec",
3621# endif
3622# ifdef FEAT_MOUSE_GPM
3623 "mouse_gpm",
3624# endif
3625# ifdef FEAT_MOUSE_JSB
3626 "mouse_jsbterm",
3627# endif
3628# ifdef FEAT_MOUSE_NET
3629 "mouse_netterm",
3630# endif
3631# ifdef FEAT_MOUSE_PTERM
3632 "mouse_pterm",
3633# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003634# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635 "mouse_sgr",
3636# endif
3637# ifdef FEAT_SYSMOUSE
3638 "mouse_sysmouse",
3639# endif
3640# ifdef FEAT_MOUSE_URXVT
3641 "mouse_urxvt",
3642# endif
3643# ifdef FEAT_MOUSE_XTERM
3644 "mouse_xterm",
3645# endif
3646#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003648#ifdef FEAT_MBYTE_IME
3649 "multi_byte_ime",
3650#endif
3651#ifdef FEAT_MULTI_LANG
3652 "multi_lang",
3653#endif
3654#ifdef FEAT_MZSCHEME
3655#ifndef DYNAMIC_MZSCHEME
3656 "mzscheme",
3657#endif
3658#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003659 "num64",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003660#ifdef FEAT_OLE
3661 "ole",
3662#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003663#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003664 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003665#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003666#ifdef FEAT_PATH_EXTRA
3667 "path_extra",
3668#endif
3669#ifdef FEAT_PERL
3670#ifndef DYNAMIC_PERL
3671 "perl",
3672#endif
3673#endif
3674#ifdef FEAT_PERSISTENT_UNDO
3675 "persistent_undo",
3676#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003677#if defined(FEAT_PYTHON)
3678 "python_compiled",
3679# if defined(DYNAMIC_PYTHON)
3680 "python_dynamic",
3681# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003682 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003683 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003684# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003685#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003686#if defined(FEAT_PYTHON3)
3687 "python3_compiled",
3688# if defined(DYNAMIC_PYTHON3)
3689 "python3_dynamic",
3690# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003691 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003692 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003693# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003694#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003695#ifdef FEAT_PROP_POPUP
3696 "popupwin",
3697#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003698#ifdef FEAT_POSTSCRIPT
3699 "postscript",
3700#endif
3701#ifdef FEAT_PRINTER
3702 "printer",
3703#endif
3704#ifdef FEAT_PROFILE
3705 "profile",
3706#endif
3707#ifdef FEAT_RELTIME
3708 "reltime",
3709#endif
3710#ifdef FEAT_QUICKFIX
3711 "quickfix",
3712#endif
3713#ifdef FEAT_RIGHTLEFT
3714 "rightleft",
3715#endif
3716#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3717 "ruby",
3718#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003719 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720#ifdef FEAT_CMDL_INFO
3721 "showcmd",
3722 "cmdline_info",
3723#endif
3724#ifdef FEAT_SIGNS
3725 "signs",
3726#endif
3727#ifdef FEAT_SMARTINDENT
3728 "smartindent",
3729#endif
3730#ifdef STARTUPTIME
3731 "startuptime",
3732#endif
3733#ifdef FEAT_STL_OPT
3734 "statusline",
3735#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003736#ifdef FEAT_NETBEANS_INTG
3737 "netbeans_intg",
3738#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003739#ifdef FEAT_SOUND
3740 "sound",
3741#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003742#ifdef FEAT_SPELL
3743 "spell",
3744#endif
3745#ifdef FEAT_SYN_HL
3746 "syntax",
3747#endif
3748#if defined(USE_SYSTEM) || !defined(UNIX)
3749 "system",
3750#endif
3751#ifdef FEAT_TAG_BINS
3752 "tag_binary",
3753#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003754#ifdef FEAT_TCL
3755# ifndef DYNAMIC_TCL
3756 "tcl",
3757# endif
3758#endif
3759#ifdef FEAT_TERMGUICOLORS
3760 "termguicolors",
3761#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003762#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003763 "terminal",
3764#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003765#ifdef TERMINFO
3766 "terminfo",
3767#endif
3768#ifdef FEAT_TERMRESPONSE
3769 "termresponse",
3770#endif
3771#ifdef FEAT_TEXTOBJ
3772 "textobjects",
3773#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003774#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003775 "textprop",
3776#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777#ifdef HAVE_TGETENT
3778 "tgetent",
3779#endif
3780#ifdef FEAT_TIMERS
3781 "timers",
3782#endif
3783#ifdef FEAT_TITLE
3784 "title",
3785#endif
3786#ifdef FEAT_TOOLBAR
3787 "toolbar",
3788#endif
3789#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3790 "unnamedplus",
3791#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003792 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003793 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003794#ifdef FEAT_VARTABS
3795 "vartabs",
3796#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003797 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003798#ifdef FEAT_VIMINFO
3799 "viminfo",
3800#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003801 "vimscript-1",
3802 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003803 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003804 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003805 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003806 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003807 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003808 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003809#ifdef FEAT_VTP
3810 "vtp",
3811#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003812#ifdef FEAT_WILDIGN
3813 "wildignore",
3814#endif
3815#ifdef FEAT_WILDMENU
3816 "wildmenu",
3817#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003818 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003819#ifdef FEAT_WAK
3820 "winaltkeys",
3821#endif
3822#ifdef FEAT_WRITEBACKUP
3823 "writebackup",
3824#endif
3825#ifdef FEAT_XIM
3826 "xim",
3827#endif
3828#ifdef FEAT_XFONTSET
3829 "xfontset",
3830#endif
3831#ifdef FEAT_XPM_W32
3832 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003833 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003834#else
3835# if defined(HAVE_XPM)
3836 "xpm",
3837# endif
3838#endif
3839#ifdef USE_XSMP
3840 "xsmp",
3841#endif
3842#ifdef USE_XSMP_INTERACT
3843 "xsmp_interact",
3844#endif
3845#ifdef FEAT_XCLIPBOARD
3846 "xterm_clipboard",
3847#endif
3848#ifdef FEAT_XTERM_SAVE
3849 "xterm_save",
3850#endif
3851#if defined(UNIX) && defined(FEAT_X11)
3852 "X11",
3853#endif
3854 NULL
3855 };
3856
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003857 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003858 for (i = 0; has_list[i] != NULL; ++i)
3859 if (STRICMP(name, has_list[i]) == 0)
3860 {
3861 n = TRUE;
3862 break;
3863 }
3864
3865 if (n == FALSE)
3866 {
3867 if (STRNICMP(name, "patch", 5) == 0)
3868 {
3869 if (name[5] == '-'
3870 && STRLEN(name) >= 11
3871 && vim_isdigit(name[6])
3872 && vim_isdigit(name[8])
3873 && vim_isdigit(name[10]))
3874 {
3875 int major = atoi((char *)name + 6);
3876 int minor = atoi((char *)name + 8);
3877
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003878 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003879 n = (major < VIM_VERSION_MAJOR
3880 || (major == VIM_VERSION_MAJOR
3881 && (minor < VIM_VERSION_MINOR
3882 || (minor == VIM_VERSION_MINOR
3883 && has_patch(atoi((char *)name + 10))))));
3884 }
3885 else
3886 n = has_patch(atoi((char *)name + 5));
3887 }
3888 else if (STRICMP(name, "vim_starting") == 0)
3889 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003890 else if (STRICMP(name, "ttyin") == 0)
3891 n = mch_input_isatty();
3892 else if (STRICMP(name, "ttyout") == 0)
3893 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003894 else if (STRICMP(name, "multi_byte_encoding") == 0)
3895 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003896#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003897 else if (STRICMP(name, "balloon_multiline") == 0)
3898 n = multiline_balloon_available();
3899#endif
3900#ifdef DYNAMIC_TCL
3901 else if (STRICMP(name, "tcl") == 0)
3902 n = tcl_enabled(FALSE);
3903#endif
3904#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3905 else if (STRICMP(name, "iconv") == 0)
3906 n = iconv_enabled(FALSE);
3907#endif
3908#ifdef DYNAMIC_LUA
3909 else if (STRICMP(name, "lua") == 0)
3910 n = lua_enabled(FALSE);
3911#endif
3912#ifdef DYNAMIC_MZSCHEME
3913 else if (STRICMP(name, "mzscheme") == 0)
3914 n = mzscheme_enabled(FALSE);
3915#endif
3916#ifdef DYNAMIC_RUBY
3917 else if (STRICMP(name, "ruby") == 0)
3918 n = ruby_enabled(FALSE);
3919#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003920#ifdef DYNAMIC_PYTHON
3921 else if (STRICMP(name, "python") == 0)
3922 n = python_enabled(FALSE);
3923#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003924#ifdef DYNAMIC_PYTHON3
3925 else if (STRICMP(name, "python3") == 0)
3926 n = python3_enabled(FALSE);
3927#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003928#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3929 else if (STRICMP(name, "pythonx") == 0)
3930 {
3931# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3932 if (p_pyx == 0)
3933 n = python3_enabled(FALSE) || python_enabled(FALSE);
3934 else if (p_pyx == 3)
3935 n = python3_enabled(FALSE);
3936 else if (p_pyx == 2)
3937 n = python_enabled(FALSE);
3938# elif defined(DYNAMIC_PYTHON)
3939 n = python_enabled(FALSE);
3940# elif defined(DYNAMIC_PYTHON3)
3941 n = python3_enabled(FALSE);
3942# endif
3943 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003944#endif
3945#ifdef DYNAMIC_PERL
3946 else if (STRICMP(name, "perl") == 0)
3947 n = perl_enabled(FALSE);
3948#endif
3949#ifdef FEAT_GUI
3950 else if (STRICMP(name, "gui_running") == 0)
3951 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003952# ifdef FEAT_BROWSE
3953 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003954 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003955# endif
3956#endif
3957#ifdef FEAT_SYN_HL
3958 else if (STRICMP(name, "syntax_items") == 0)
3959 n = syntax_present(curwin);
3960#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003961#ifdef FEAT_VTP
3962 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003963 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003964#endif
3965#ifdef FEAT_NETBEANS_INTG
3966 else if (STRICMP(name, "netbeans_enabled") == 0)
3967 n = netbeans_active();
3968#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003969#ifdef FEAT_MOUSE_GPM
3970 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3971 n = gpm_enabled();
3972#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003973#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003974 else if (STRICMP(name, "terminal") == 0)
3975 n = terminal_enabled();
3976#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003977#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003978 else if (STRICMP(name, "conpty") == 0)
3979 n = use_conpty();
3980#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003981#ifdef FEAT_CLIPBOARD
3982 else if (STRICMP(name, "clipboard_working") == 0)
3983 n = clip_star.available;
3984#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003985#ifdef VIMDLL
3986 else if (STRICMP(name, "filterpipe") == 0)
3987 n = gui.in_use || gui.starting;
3988#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003989 }
3990
3991 rettv->vval.v_number = n;
3992}
3993
3994/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003995 * "haslocaldir()" function
3996 */
3997 static void
3998f_haslocaldir(typval_T *argvars, typval_T *rettv)
3999{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004000 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004001 win_T *wp = NULL;
4002
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004003 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
4004
4005 // Check for window-local and tab-local directories
4006 if (wp != NULL && wp->w_localdir != NULL)
4007 rettv->vval.v_number = 1;
4008 else if (tp != NULL && tp->tp_localdir != NULL)
4009 rettv->vval.v_number = 2;
4010 else
4011 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004012}
4013
4014/*
4015 * "hasmapto()" function
4016 */
4017 static void
4018f_hasmapto(typval_T *argvars, typval_T *rettv)
4019{
4020 char_u *name;
4021 char_u *mode;
4022 char_u buf[NUMBUFLEN];
4023 int abbr = FALSE;
4024
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004025 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004026 if (argvars[1].v_type == VAR_UNKNOWN)
4027 mode = (char_u *)"nvo";
4028 else
4029 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004030 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004031 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004032 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004033 }
4034
4035 if (map_to_exists(name, mode, abbr))
4036 rettv->vval.v_number = TRUE;
4037 else
4038 rettv->vval.v_number = FALSE;
4039}
4040
4041/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004042 * "highlightID(name)" function
4043 */
4044 static void
4045f_hlID(typval_T *argvars, typval_T *rettv)
4046{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004047 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004048}
4049
4050/*
4051 * "highlight_exists()" function
4052 */
4053 static void
4054f_hlexists(typval_T *argvars, typval_T *rettv)
4055{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004056 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004057}
4058
4059/*
4060 * "hostname()" function
4061 */
4062 static void
4063f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
4064{
4065 char_u hostname[256];
4066
4067 mch_get_host_name(hostname, 256);
4068 rettv->v_type = VAR_STRING;
4069 rettv->vval.v_string = vim_strsave(hostname);
4070}
4071
4072/*
4073 * iconv() function
4074 */
4075 static void
4076f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
4077{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004078 char_u buf1[NUMBUFLEN];
4079 char_u buf2[NUMBUFLEN];
4080 char_u *from, *to, *str;
4081 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004082
4083 rettv->v_type = VAR_STRING;
4084 rettv->vval.v_string = NULL;
4085
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004086 str = tv_get_string(&argvars[0]);
4087 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
4088 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004089 vimconv.vc_type = CONV_NONE;
4090 convert_setup(&vimconv, from, to);
4091
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004092 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004093 if (vimconv.vc_type == CONV_NONE)
4094 rettv->vval.v_string = vim_strsave(str);
4095 else
4096 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4097
4098 convert_setup(&vimconv, NULL, NULL);
4099 vim_free(from);
4100 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004101}
4102
4103/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004104 * "index()" function
4105 */
4106 static void
4107f_index(typval_T *argvars, typval_T *rettv)
4108{
4109 list_T *l;
4110 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004111 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004112 long idx = 0;
4113 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004114 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004115
4116 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004117 if (argvars[0].v_type == VAR_BLOB)
4118 {
4119 typval_T tv;
4120 int start = 0;
4121
4122 if (argvars[2].v_type != VAR_UNKNOWN)
4123 {
4124 start = tv_get_number_chk(&argvars[2], &error);
4125 if (error)
4126 return;
4127 }
4128 b = argvars[0].vval.v_blob;
4129 if (b == NULL)
4130 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004131 if (start < 0)
4132 {
4133 start = blob_len(b) + start;
4134 if (start < 0)
4135 start = 0;
4136 }
4137
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004138 for (idx = start; idx < blob_len(b); ++idx)
4139 {
4140 tv.v_type = VAR_NUMBER;
4141 tv.vval.v_number = blob_get(b, idx);
4142 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4143 {
4144 rettv->vval.v_number = idx;
4145 return;
4146 }
4147 }
4148 return;
4149 }
4150 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004151 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004152 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004153 return;
4154 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004155
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156 l = argvars[0].vval.v_list;
4157 if (l != NULL)
4158 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004159 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004160 item = l->lv_first;
4161 if (argvars[2].v_type != VAR_UNKNOWN)
4162 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004163 // Start at specified item. Use the cached index that list_find()
4164 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004165 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004166 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004167 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004168 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004169 if (error)
4170 item = NULL;
4171 }
4172
4173 for ( ; item != NULL; item = item->li_next, ++idx)
4174 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4175 {
4176 rettv->vval.v_number = idx;
4177 break;
4178 }
4179 }
4180}
4181
4182static int inputsecret_flag = 0;
4183
4184/*
4185 * "input()" function
4186 * Also handles inputsecret() when inputsecret is set.
4187 */
4188 static void
4189f_input(typval_T *argvars, typval_T *rettv)
4190{
4191 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4192}
4193
4194/*
4195 * "inputdialog()" function
4196 */
4197 static void
4198f_inputdialog(typval_T *argvars, typval_T *rettv)
4199{
4200#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004201 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004202 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4203 {
4204 char_u *message;
4205 char_u buf[NUMBUFLEN];
4206 char_u *defstr = (char_u *)"";
4207
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004208 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004209 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004210 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004211 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4212 else
4213 IObuff[0] = NUL;
4214 if (message != NULL && defstr != NULL
4215 && do_dialog(VIM_QUESTION, NULL, message,
4216 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4217 rettv->vval.v_string = vim_strsave(IObuff);
4218 else
4219 {
4220 if (message != NULL && defstr != NULL
4221 && argvars[1].v_type != VAR_UNKNOWN
4222 && argvars[2].v_type != VAR_UNKNOWN)
4223 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004224 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004225 else
4226 rettv->vval.v_string = NULL;
4227 }
4228 rettv->v_type = VAR_STRING;
4229 }
4230 else
4231#endif
4232 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4233}
4234
4235/*
4236 * "inputlist()" function
4237 */
4238 static void
4239f_inputlist(typval_T *argvars, typval_T *rettv)
4240{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004241 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004242 listitem_T *li;
4243 int selected;
4244 int mouse_used;
4245
4246#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004247 // While starting up, there is no place to enter text. When running tests
4248 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004249 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004250 return;
4251#endif
4252 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4253 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004254 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255 return;
4256 }
4257
4258 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004259 msg_row = Rows - 1; // for when 'cmdheight' > 1
4260 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004261 msg_scroll = TRUE;
4262 msg_clr_eos();
4263
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004264 l = argvars[0].vval.v_list;
4265 range_list_materialize(l);
4266 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004267 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004268 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004269 msg_putchar('\n');
4270 }
4271
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004272 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004273 selected = prompt_for_number(&mouse_used);
4274 if (mouse_used)
4275 selected -= lines_left;
4276
4277 rettv->vval.v_number = selected;
4278}
4279
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004280static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4281
4282/*
4283 * "inputrestore()" function
4284 */
4285 static void
4286f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4287{
4288 if (ga_userinput.ga_len > 0)
4289 {
4290 --ga_userinput.ga_len;
4291 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4292 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004293 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004294 }
4295 else if (p_verbose > 1)
4296 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004297 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004298 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004299 }
4300}
4301
4302/*
4303 * "inputsave()" function
4304 */
4305 static void
4306f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4307{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004308 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004309 if (ga_grow(&ga_userinput, 1) == OK)
4310 {
4311 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4312 + ga_userinput.ga_len);
4313 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004314 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004315 }
4316 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004317 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004318}
4319
4320/*
4321 * "inputsecret()" function
4322 */
4323 static void
4324f_inputsecret(typval_T *argvars, typval_T *rettv)
4325{
4326 ++cmdline_star;
4327 ++inputsecret_flag;
4328 f_input(argvars, rettv);
4329 --cmdline_star;
4330 --inputsecret_flag;
4331}
4332
4333/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004334 * "interrupt()" function
4335 */
4336 static void
4337f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4338{
4339 got_int = TRUE;
4340}
4341
4342/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004343 * "invert(expr)" function
4344 */
4345 static void
4346f_invert(typval_T *argvars, typval_T *rettv)
4347{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004348 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004349}
4350
4351/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004352 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4353 * or it refers to a List or Dictionary that is locked.
4354 */
4355 static int
4356tv_islocked(typval_T *tv)
4357{
4358 return (tv->v_lock & VAR_LOCKED)
4359 || (tv->v_type == VAR_LIST
4360 && tv->vval.v_list != NULL
4361 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4362 || (tv->v_type == VAR_DICT
4363 && tv->vval.v_dict != NULL
4364 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4365}
4366
4367/*
4368 * "islocked()" function
4369 */
4370 static void
4371f_islocked(typval_T *argvars, typval_T *rettv)
4372{
4373 lval_T lv;
4374 char_u *end;
4375 dictitem_T *di;
4376
4377 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004378 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004379 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004380 if (end != NULL && lv.ll_name != NULL)
4381 {
4382 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004383 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004384 else
4385 {
4386 if (lv.ll_tv == NULL)
4387 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004388 di = find_var(lv.ll_name, NULL, TRUE);
4389 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004390 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004391 // Consider a variable locked when:
4392 // 1. the variable itself is locked
4393 // 2. the value of the variable is locked.
4394 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004395 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4396 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397 }
4398 }
4399 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004400 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004401 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004402 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004403 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004404 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004405 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4406 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004407 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004408 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4409 }
4410 }
4411
4412 clear_lval(&lv);
4413}
4414
4415#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4416/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004417 * "isinf()" function
4418 */
4419 static void
4420f_isinf(typval_T *argvars, typval_T *rettv)
4421{
4422 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4423 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4424}
4425
4426/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004427 * "isnan()" function
4428 */
4429 static void
4430f_isnan(typval_T *argvars, typval_T *rettv)
4431{
4432 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4433 && isnan(argvars[0].vval.v_float);
4434}
4435#endif
4436
4437/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004438 * "last_buffer_nr()" function.
4439 */
4440 static void
4441f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4442{
4443 int n = 0;
4444 buf_T *buf;
4445
Bram Moolenaar29323592016-07-24 22:04:11 +02004446 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004447 if (n < buf->b_fnum)
4448 n = buf->b_fnum;
4449
4450 rettv->vval.v_number = n;
4451}
4452
4453/*
4454 * "len()" function
4455 */
4456 static void
4457f_len(typval_T *argvars, typval_T *rettv)
4458{
4459 switch (argvars[0].v_type)
4460 {
4461 case VAR_STRING:
4462 case VAR_NUMBER:
4463 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004464 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004465 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004466 case VAR_BLOB:
4467 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4468 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004469 case VAR_LIST:
4470 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4471 break;
4472 case VAR_DICT:
4473 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4474 break;
4475 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004476 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004477 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004478 case VAR_SPECIAL:
4479 case VAR_FLOAT:
4480 case VAR_FUNC:
4481 case VAR_PARTIAL:
4482 case VAR_JOB:
4483 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004484 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004485 break;
4486 }
4487}
4488
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004489 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004490libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004491{
4492#ifdef FEAT_LIBCALL
4493 char_u *string_in;
4494 char_u **string_result;
4495 int nr_result;
4496#endif
4497
4498 rettv->v_type = type;
4499 if (type != VAR_NUMBER)
4500 rettv->vval.v_string = NULL;
4501
4502 if (check_restricted() || check_secure())
4503 return;
4504
4505#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004506 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004507 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4508 {
4509 string_in = NULL;
4510 if (argvars[2].v_type == VAR_STRING)
4511 string_in = argvars[2].vval.v_string;
4512 if (type == VAR_NUMBER)
4513 string_result = NULL;
4514 else
4515 string_result = &rettv->vval.v_string;
4516 if (mch_libcall(argvars[0].vval.v_string,
4517 argvars[1].vval.v_string,
4518 string_in,
4519 argvars[2].vval.v_number,
4520 string_result,
4521 &nr_result) == OK
4522 && type == VAR_NUMBER)
4523 rettv->vval.v_number = nr_result;
4524 }
4525#endif
4526}
4527
4528/*
4529 * "libcall()" function
4530 */
4531 static void
4532f_libcall(typval_T *argvars, typval_T *rettv)
4533{
4534 libcall_common(argvars, rettv, VAR_STRING);
4535}
4536
4537/*
4538 * "libcallnr()" function
4539 */
4540 static void
4541f_libcallnr(typval_T *argvars, typval_T *rettv)
4542{
4543 libcall_common(argvars, rettv, VAR_NUMBER);
4544}
4545
4546/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004547 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004548 */
4549 static void
4550f_line(typval_T *argvars, typval_T *rettv)
4551{
4552 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004553 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004554 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004555 int id;
4556 tabpage_T *tp;
4557 win_T *wp;
4558 win_T *save_curwin;
4559 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004561 if (argvars[1].v_type != VAR_UNKNOWN)
4562 {
4563 // use window specified in the second argument
4564 id = (int)tv_get_number(&argvars[1]);
4565 wp = win_id2wp_tp(id, &tp);
4566 if (wp != NULL && tp != NULL)
4567 {
4568 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4569 == OK)
4570 {
4571 check_cursor();
4572 fp = var2fpos(&argvars[0], TRUE, &fnum);
4573 }
4574 restore_win_noblock(save_curwin, save_curtab, TRUE);
4575 }
4576 }
4577 else
4578 // use current window
4579 fp = var2fpos(&argvars[0], TRUE, &fnum);
4580
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004581 if (fp != NULL)
4582 lnum = fp->lnum;
4583 rettv->vval.v_number = lnum;
4584}
4585
4586/*
4587 * "line2byte(lnum)" function
4588 */
4589 static void
4590f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4591{
4592#ifndef FEAT_BYTEOFF
4593 rettv->vval.v_number = -1;
4594#else
4595 linenr_T lnum;
4596
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004597 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004598 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4599 rettv->vval.v_number = -1;
4600 else
4601 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4602 if (rettv->vval.v_number >= 0)
4603 ++rettv->vval.v_number;
4604#endif
4605}
4606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004607#ifdef FEAT_FLOAT
4608/*
4609 * "log()" function
4610 */
4611 static void
4612f_log(typval_T *argvars, typval_T *rettv)
4613{
4614 float_T f = 0.0;
4615
4616 rettv->v_type = VAR_FLOAT;
4617 if (get_float_arg(argvars, &f) == OK)
4618 rettv->vval.v_float = log(f);
4619 else
4620 rettv->vval.v_float = 0.0;
4621}
4622
4623/*
4624 * "log10()" function
4625 */
4626 static void
4627f_log10(typval_T *argvars, typval_T *rettv)
4628{
4629 float_T f = 0.0;
4630
4631 rettv->v_type = VAR_FLOAT;
4632 if (get_float_arg(argvars, &f) == OK)
4633 rettv->vval.v_float = log10(f);
4634 else
4635 rettv->vval.v_float = 0.0;
4636}
4637#endif
4638
4639#ifdef FEAT_LUA
4640/*
4641 * "luaeval()" function
4642 */
4643 static void
4644f_luaeval(typval_T *argvars, typval_T *rettv)
4645{
4646 char_u *str;
4647 char_u buf[NUMBUFLEN];
4648
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004649 if (check_restricted() || check_secure())
4650 return;
4651
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004652 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004653 do_luaeval(str, argvars + 1, rettv);
4654}
4655#endif
4656
4657/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004658 * "maparg()" function
4659 */
4660 static void
4661f_maparg(typval_T *argvars, typval_T *rettv)
4662{
4663 get_maparg(argvars, rettv, TRUE);
4664}
4665
4666/*
4667 * "mapcheck()" function
4668 */
4669 static void
4670f_mapcheck(typval_T *argvars, typval_T *rettv)
4671{
4672 get_maparg(argvars, rettv, FALSE);
4673}
4674
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004675typedef enum
4676{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004677 MATCH_END, // matchend()
4678 MATCH_MATCH, // match()
4679 MATCH_STR, // matchstr()
4680 MATCH_LIST, // matchlist()
4681 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004682} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004683
4684 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004685find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004686{
4687 char_u *str = NULL;
4688 long len = 0;
4689 char_u *expr = NULL;
4690 char_u *pat;
4691 regmatch_T regmatch;
4692 char_u patbuf[NUMBUFLEN];
4693 char_u strbuf[NUMBUFLEN];
4694 char_u *save_cpo;
4695 long start = 0;
4696 long nth = 1;
4697 colnr_T startcol = 0;
4698 int match = 0;
4699 list_T *l = NULL;
4700 listitem_T *li = NULL;
4701 long idx = 0;
4702 char_u *tofree = NULL;
4703
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004704 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004705 save_cpo = p_cpo;
4706 p_cpo = (char_u *)"";
4707
4708 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004709 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004710 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004711 // type MATCH_LIST: return empty list when there are no matches.
4712 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004713 if (rettv_list_alloc(rettv) == FAIL)
4714 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004715 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004716 && (list_append_string(rettv->vval.v_list,
4717 (char_u *)"", 0) == FAIL
4718 || list_append_number(rettv->vval.v_list,
4719 (varnumber_T)-1) == 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 {
4725 list_free(rettv->vval.v_list);
4726 rettv->vval.v_list = NULL;
4727 goto theend;
4728 }
4729 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004730 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004731 {
4732 rettv->v_type = VAR_STRING;
4733 rettv->vval.v_string = NULL;
4734 }
4735
4736 if (argvars[0].v_type == VAR_LIST)
4737 {
4738 if ((l = argvars[0].vval.v_list) == NULL)
4739 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004740 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004741 li = l->lv_first;
4742 }
4743 else
4744 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004745 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746 len = (long)STRLEN(str);
4747 }
4748
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004749 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004750 if (pat == NULL)
4751 goto theend;
4752
4753 if (argvars[2].v_type != VAR_UNKNOWN)
4754 {
4755 int error = FALSE;
4756
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004757 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004758 if (error)
4759 goto theend;
4760 if (l != NULL)
4761 {
4762 li = list_find(l, start);
4763 if (li == NULL)
4764 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004765 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766 }
4767 else
4768 {
4769 if (start < 0)
4770 start = 0;
4771 if (start > len)
4772 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004773 // When "count" argument is there ignore matches before "start",
4774 // otherwise skip part of the string. Differs when pattern is "^"
4775 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004776 if (argvars[3].v_type != VAR_UNKNOWN)
4777 startcol = start;
4778 else
4779 {
4780 str += start;
4781 len -= start;
4782 }
4783 }
4784
4785 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004786 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004787 if (error)
4788 goto theend;
4789 }
4790
4791 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4792 if (regmatch.regprog != NULL)
4793 {
4794 regmatch.rm_ic = p_ic;
4795
4796 for (;;)
4797 {
4798 if (l != NULL)
4799 {
4800 if (li == NULL)
4801 {
4802 match = FALSE;
4803 break;
4804 }
4805 vim_free(tofree);
4806 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4807 if (str == NULL)
4808 break;
4809 }
4810
4811 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4812
4813 if (match && --nth <= 0)
4814 break;
4815 if (l == NULL && !match)
4816 break;
4817
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004818 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004819 if (l != NULL)
4820 {
4821 li = li->li_next;
4822 ++idx;
4823 }
4824 else
4825 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004826 startcol = (colnr_T)(regmatch.startp[0]
4827 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004828 if (startcol > (colnr_T)len
4829 || str + startcol <= regmatch.startp[0])
4830 {
4831 match = FALSE;
4832 break;
4833 }
4834 }
4835 }
4836
4837 if (match)
4838 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004839 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004840 {
4841 listitem_T *li1 = rettv->vval.v_list->lv_first;
4842 listitem_T *li2 = li1->li_next;
4843 listitem_T *li3 = li2->li_next;
4844 listitem_T *li4 = li3->li_next;
4845
4846 vim_free(li1->li_tv.vval.v_string);
4847 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4848 (int)(regmatch.endp[0] - regmatch.startp[0]));
4849 li3->li_tv.vval.v_number =
4850 (varnumber_T)(regmatch.startp[0] - expr);
4851 li4->li_tv.vval.v_number =
4852 (varnumber_T)(regmatch.endp[0] - expr);
4853 if (l != NULL)
4854 li2->li_tv.vval.v_number = (varnumber_T)idx;
4855 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004856 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004857 {
4858 int i;
4859
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004860 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861 for (i = 0; i < NSUBEXP; ++i)
4862 {
4863 if (regmatch.endp[i] == NULL)
4864 {
4865 if (list_append_string(rettv->vval.v_list,
4866 (char_u *)"", 0) == FAIL)
4867 break;
4868 }
4869 else if (list_append_string(rettv->vval.v_list,
4870 regmatch.startp[i],
4871 (int)(regmatch.endp[i] - regmatch.startp[i]))
4872 == FAIL)
4873 break;
4874 }
4875 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004876 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004877 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004878 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004879 if (l != NULL)
4880 copy_tv(&li->li_tv, rettv);
4881 else
4882 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4883 (int)(regmatch.endp[0] - regmatch.startp[0]));
4884 }
4885 else if (l != NULL)
4886 rettv->vval.v_number = idx;
4887 else
4888 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004889 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004890 rettv->vval.v_number =
4891 (varnumber_T)(regmatch.startp[0] - str);
4892 else
4893 rettv->vval.v_number =
4894 (varnumber_T)(regmatch.endp[0] - str);
4895 rettv->vval.v_number += (varnumber_T)(str - expr);
4896 }
4897 }
4898 vim_regfree(regmatch.regprog);
4899 }
4900
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004901theend:
4902 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004903 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004904 listitem_remove(rettv->vval.v_list,
4905 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004906 vim_free(tofree);
4907 p_cpo = save_cpo;
4908}
4909
4910/*
4911 * "match()" function
4912 */
4913 static void
4914f_match(typval_T *argvars, typval_T *rettv)
4915{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004916 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917}
4918
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004919/*
4920 * "matchend()" function
4921 */
4922 static void
4923f_matchend(typval_T *argvars, typval_T *rettv)
4924{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004925 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004926}
4927
4928/*
4929 * "matchlist()" function
4930 */
4931 static void
4932f_matchlist(typval_T *argvars, typval_T *rettv)
4933{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004934 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004935}
4936
4937/*
4938 * "matchstr()" function
4939 */
4940 static void
4941f_matchstr(typval_T *argvars, typval_T *rettv)
4942{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004943 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004944}
4945
4946/*
4947 * "matchstrpos()" function
4948 */
4949 static void
4950f_matchstrpos(typval_T *argvars, typval_T *rettv)
4951{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004952 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004953}
4954
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955 static void
4956max_min(typval_T *argvars, typval_T *rettv, int domax)
4957{
4958 varnumber_T n = 0;
4959 varnumber_T i;
4960 int error = FALSE;
4961
4962 if (argvars[0].v_type == VAR_LIST)
4963 {
4964 list_T *l;
4965 listitem_T *li;
4966
4967 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004968 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004969 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004970 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004971 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004972 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4973 n = l->lv_u.nonmat.lv_start;
4974 else
4975 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4976 * l->lv_u.nonmat.lv_stride;
4977 }
4978 else
4979 {
4980 li = l->lv_first;
4981 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004982 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004983 n = tv_get_number_chk(&li->li_tv, &error);
4984 for (;;)
4985 {
4986 li = li->li_next;
4987 if (li == NULL)
4988 break;
4989 i = tv_get_number_chk(&li->li_tv, &error);
4990 if (domax ? i > n : i < n)
4991 n = i;
4992 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004993 }
4994 }
4995 }
4996 }
4997 else if (argvars[0].v_type == VAR_DICT)
4998 {
4999 dict_T *d;
5000 int first = TRUE;
5001 hashitem_T *hi;
5002 int todo;
5003
5004 d = argvars[0].vval.v_dict;
5005 if (d != NULL)
5006 {
5007 todo = (int)d->dv_hashtab.ht_used;
5008 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
5009 {
5010 if (!HASHITEM_EMPTY(hi))
5011 {
5012 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005013 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005014 if (first)
5015 {
5016 n = i;
5017 first = FALSE;
5018 }
5019 else if (domax ? i > n : i < n)
5020 n = i;
5021 }
5022 }
5023 }
5024 }
5025 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005026 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005027 rettv->vval.v_number = error ? 0 : n;
5028}
5029
5030/*
5031 * "max()" function
5032 */
5033 static void
5034f_max(typval_T *argvars, typval_T *rettv)
5035{
5036 max_min(argvars, rettv, TRUE);
5037}
5038
5039/*
5040 * "min()" function
5041 */
5042 static void
5043f_min(typval_T *argvars, typval_T *rettv)
5044{
5045 max_min(argvars, rettv, FALSE);
5046}
5047
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005048#if defined(FEAT_MZSCHEME) || defined(PROTO)
5049/*
5050 * "mzeval()" function
5051 */
5052 static void
5053f_mzeval(typval_T *argvars, typval_T *rettv)
5054{
5055 char_u *str;
5056 char_u buf[NUMBUFLEN];
5057
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005058 if (check_restricted() || check_secure())
5059 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005060 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005061 do_mzeval(str, rettv);
5062}
5063
5064 void
5065mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5066{
5067 typval_T argvars[3];
5068
5069 argvars[0].v_type = VAR_STRING;
5070 argvars[0].vval.v_string = name;
5071 copy_tv(args, &argvars[1]);
5072 argvars[2].v_type = VAR_UNKNOWN;
5073 f_call(argvars, rettv);
5074 clear_tv(&argvars[1]);
5075}
5076#endif
5077
5078/*
5079 * "nextnonblank()" function
5080 */
5081 static void
5082f_nextnonblank(typval_T *argvars, typval_T *rettv)
5083{
5084 linenr_T lnum;
5085
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005086 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005087 {
5088 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5089 {
5090 lnum = 0;
5091 break;
5092 }
5093 if (*skipwhite(ml_get(lnum)) != NUL)
5094 break;
5095 }
5096 rettv->vval.v_number = lnum;
5097}
5098
5099/*
5100 * "nr2char()" function
5101 */
5102 static void
5103f_nr2char(typval_T *argvars, typval_T *rettv)
5104{
5105 char_u buf[NUMBUFLEN];
5106
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 if (has_mbyte)
5108 {
5109 int utf8 = 0;
5110
5111 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005112 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005113 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005114 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005116 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117 }
5118 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005119 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005120 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005121 buf[1] = NUL;
5122 }
5123 rettv->v_type = VAR_STRING;
5124 rettv->vval.v_string = vim_strsave(buf);
5125}
5126
5127/*
5128 * "or(expr, expr)" function
5129 */
5130 static void
5131f_or(typval_T *argvars, typval_T *rettv)
5132{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005133 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5134 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005135}
5136
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137#ifdef FEAT_PERL
5138/*
5139 * "perleval()" function
5140 */
5141 static void
5142f_perleval(typval_T *argvars, typval_T *rettv)
5143{
5144 char_u *str;
5145 char_u buf[NUMBUFLEN];
5146
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005147 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005148 do_perleval(str, rettv);
5149}
5150#endif
5151
5152#ifdef FEAT_FLOAT
5153/*
5154 * "pow()" function
5155 */
5156 static void
5157f_pow(typval_T *argvars, typval_T *rettv)
5158{
5159 float_T fx = 0.0, fy = 0.0;
5160
5161 rettv->v_type = VAR_FLOAT;
5162 if (get_float_arg(argvars, &fx) == OK
5163 && get_float_arg(&argvars[1], &fy) == OK)
5164 rettv->vval.v_float = pow(fx, fy);
5165 else
5166 rettv->vval.v_float = 0.0;
5167}
5168#endif
5169
5170/*
5171 * "prevnonblank()" function
5172 */
5173 static void
5174f_prevnonblank(typval_T *argvars, typval_T *rettv)
5175{
5176 linenr_T lnum;
5177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005178 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005179 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5180 lnum = 0;
5181 else
5182 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5183 --lnum;
5184 rettv->vval.v_number = lnum;
5185}
5186
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005187// This dummy va_list is here because:
5188// - passing a NULL pointer doesn't work when va_list isn't a pointer
5189// - locally in the function results in a "used before set" warning
5190// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005191static va_list ap;
5192
5193/*
5194 * "printf()" function
5195 */
5196 static void
5197f_printf(typval_T *argvars, typval_T *rettv)
5198{
5199 char_u buf[NUMBUFLEN];
5200 int len;
5201 char_u *s;
5202 int saved_did_emsg = did_emsg;
5203 char *fmt;
5204
5205 rettv->v_type = VAR_STRING;
5206 rettv->vval.v_string = NULL;
5207
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005208 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005210 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005211 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005212 if (!did_emsg)
5213 {
5214 s = alloc(len + 1);
5215 if (s != NULL)
5216 {
5217 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005218 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5219 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005220 }
5221 }
5222 did_emsg |= saved_did_emsg;
5223}
5224
5225/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005226 * "pum_getpos()" function
5227 */
5228 static void
5229f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5230{
5231 if (rettv_dict_alloc(rettv) != OK)
5232 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005233 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005234}
5235
5236/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005237 * "pumvisible()" function
5238 */
5239 static void
5240f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5241{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005242 if (pum_visible())
5243 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244}
5245
5246#ifdef FEAT_PYTHON3
5247/*
5248 * "py3eval()" function
5249 */
5250 static void
5251f_py3eval(typval_T *argvars, typval_T *rettv)
5252{
5253 char_u *str;
5254 char_u buf[NUMBUFLEN];
5255
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005256 if (check_restricted() || check_secure())
5257 return;
5258
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005259 if (p_pyx == 0)
5260 p_pyx = 3;
5261
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005262 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005263 do_py3eval(str, rettv);
5264}
5265#endif
5266
5267#ifdef FEAT_PYTHON
5268/*
5269 * "pyeval()" function
5270 */
5271 static void
5272f_pyeval(typval_T *argvars, typval_T *rettv)
5273{
5274 char_u *str;
5275 char_u buf[NUMBUFLEN];
5276
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005277 if (check_restricted() || check_secure())
5278 return;
5279
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005280 if (p_pyx == 0)
5281 p_pyx = 2;
5282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005283 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005284 do_pyeval(str, rettv);
5285}
5286#endif
5287
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005288#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5289/*
5290 * "pyxeval()" function
5291 */
5292 static void
5293f_pyxeval(typval_T *argvars, typval_T *rettv)
5294{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005295 if (check_restricted() || check_secure())
5296 return;
5297
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005298# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5299 init_pyxversion();
5300 if (p_pyx == 2)
5301 f_pyeval(argvars, rettv);
5302 else
5303 f_py3eval(argvars, rettv);
5304# elif defined(FEAT_PYTHON)
5305 f_pyeval(argvars, rettv);
5306# elif defined(FEAT_PYTHON3)
5307 f_py3eval(argvars, rettv);
5308# endif
5309}
5310#endif
5311
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005312static UINT32_T srand_seed_for_testing = 0;
5313static int srand_seed_for_testing_is_used = FALSE;
5314
5315 static void
5316f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5317{
5318 if (argvars[0].v_type == VAR_UNKNOWN)
5319 srand_seed_for_testing_is_used = FALSE;
5320 else
5321 {
5322 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5323 srand_seed_for_testing_is_used = TRUE;
5324 }
5325}
5326
5327 static void
5328init_srand(UINT32_T *x)
5329{
5330#ifndef MSWIN
5331 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
5332#endif
5333
5334 if (srand_seed_for_testing_is_used)
5335 {
5336 *x = srand_seed_for_testing;
5337 return;
5338 }
5339#ifndef MSWIN
5340 if (dev_urandom_state != FAIL)
5341 {
5342 int fd = open("/dev/urandom", O_RDONLY);
5343 struct {
5344 union {
5345 UINT32_T number;
5346 char bytes[sizeof(UINT32_T)];
5347 } contents;
5348 } buf;
5349
5350 // Attempt reading /dev/urandom.
5351 if (fd == -1)
5352 dev_urandom_state = FAIL;
5353 else
5354 {
5355 buf.contents.number = 0;
5356 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
5357 != sizeof(UINT32_T))
5358 dev_urandom_state = FAIL;
5359 else
5360 {
5361 dev_urandom_state = OK;
5362 *x = buf.contents.number;
5363 }
5364 close(fd);
5365 }
5366 }
5367 if (dev_urandom_state != OK)
5368 // Reading /dev/urandom doesn't work, fall back to time().
5369#endif
5370 *x = vim_time();
5371}
5372
5373#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5374#define SPLITMIX32(x, z) ( \
5375 z = (x += 0x9e3779b9), \
5376 z = (z ^ (z >> 16)) * 0x85ebca6b, \
5377 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
5378 z ^ (z >> 16) \
5379 )
5380#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
5381 result = ROTL(y * 5, 7) * 9; \
5382 t = y << 9; \
5383 z ^= x; \
5384 w ^= y; \
5385 y ^= z, x ^= w; \
5386 z ^= t; \
5387 w = ROTL(w, 11);
5388
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005389/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005390 * "rand()" function
5391 */
5392 static void
5393f_rand(typval_T *argvars, typval_T *rettv)
5394{
5395 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005396 static UINT32_T gx, gy, gz, gw;
5397 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005398 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005399 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005400
5401 if (argvars[0].v_type == VAR_UNKNOWN)
5402 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005403 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005404 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005405 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005406 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005407 init_srand(&x);
5408
5409 gx = SPLITMIX32(x, z);
5410 gy = SPLITMIX32(x, z);
5411 gz = SPLITMIX32(x, z);
5412 gw = SPLITMIX32(x, z);
5413 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005414 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005415
5416 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005417 }
5418 else if (argvars[0].v_type == VAR_LIST)
5419 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005420 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005421 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005422 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005423
5424 lx = list_find(l, 0L);
5425 ly = list_find(l, 1L);
5426 lz = list_find(l, 2L);
5427 lw = list_find(l, 3L);
5428 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5429 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5430 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5431 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5432 x = (UINT32_T)lx->li_tv.vval.v_number;
5433 y = (UINT32_T)ly->li_tv.vval.v_number;
5434 z = (UINT32_T)lz->li_tv.vval.v_number;
5435 w = (UINT32_T)lw->li_tv.vval.v_number;
5436
5437 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
5438
5439 lx->li_tv.vval.v_number = (varnumber_T)x;
5440 ly->li_tv.vval.v_number = (varnumber_T)y;
5441 lz->li_tv.vval.v_number = (varnumber_T)z;
5442 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005443 }
5444 else
5445 goto theend;
5446
5447 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005448 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005449 return;
5450
5451theend:
5452 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005453 rettv->v_type = VAR_NUMBER;
5454 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005455}
5456
5457/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005458 * "srand()" function
5459 */
5460 static void
5461f_srand(typval_T *argvars, typval_T *rettv)
5462{
5463 UINT32_T x = 0, z;
5464
5465 if (rettv_list_alloc(rettv) == FAIL)
5466 return;
5467 if (argvars[0].v_type == VAR_UNKNOWN)
5468 {
5469 init_srand(&x);
5470 }
5471 else
5472 {
5473 int error = FALSE;
5474
5475 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
5476 if (error)
5477 return;
5478 }
5479
5480 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5481 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
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}
5485
5486#undef ROTL
5487#undef SPLITMIX32
5488#undef SHUFFLE_XOSHIRO128STARSTAR
5489
5490/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005491 * "range()" function
5492 */
5493 static void
5494f_range(typval_T *argvars, typval_T *rettv)
5495{
5496 varnumber_T start;
5497 varnumber_T end;
5498 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005499 int error = FALSE;
5500
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005501 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005502 if (argvars[1].v_type == VAR_UNKNOWN)
5503 {
5504 end = start - 1;
5505 start = 0;
5506 }
5507 else
5508 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005509 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005510 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005511 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005512 }
5513
5514 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005515 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005516 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005517 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005518 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005519 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005520 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005521 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005522 list_T *list = rettv->vval.v_list;
5523
5524 // Create a non-materialized list. This is much more efficient and
5525 // works with ":for". If used otherwise range_list_materialize() must
5526 // be called.
5527 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005528 list->lv_u.nonmat.lv_start = start;
5529 list->lv_u.nonmat.lv_end = end;
5530 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005531 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005532 }
5533}
5534
5535/*
5536 * If "list" is a non-materialized list then materialize it now.
5537 */
5538 void
5539range_list_materialize(list_T *list)
5540{
5541 if (list->lv_first == &range_list_item)
5542 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005543 varnumber_T start = list->lv_u.nonmat.lv_start;
5544 varnumber_T end = list->lv_u.nonmat.lv_end;
5545 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005546 varnumber_T i;
5547
5548 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005549 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005550 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005551 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005552 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5553 if (list_append_number(list, (varnumber_T)i) == FAIL)
5554 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005555 }
5556}
5557
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005558 static void
5559return_register(int regname, typval_T *rettv)
5560{
5561 char_u buf[2] = {0, 0};
5562
5563 buf[0] = (char_u)regname;
5564 rettv->v_type = VAR_STRING;
5565 rettv->vval.v_string = vim_strsave(buf);
5566}
5567
5568/*
5569 * "reg_executing()" function
5570 */
5571 static void
5572f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5573{
5574 return_register(reg_executing, rettv);
5575}
5576
5577/*
5578 * "reg_recording()" function
5579 */
5580 static void
5581f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5582{
5583 return_register(reg_recording, rettv);
5584}
5585
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005586#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005587 static void
5588make_connection(void)
5589{
5590 if (X_DISPLAY == NULL
5591# ifdef FEAT_GUI
5592 && !gui.in_use
5593# endif
5594 )
5595 {
5596 x_force_connect = TRUE;
5597 setup_term_clip();
5598 x_force_connect = FALSE;
5599 }
5600}
5601
5602 static int
5603check_connection(void)
5604{
5605 make_connection();
5606 if (X_DISPLAY == NULL)
5607 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005608 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005609 return FAIL;
5610 }
5611 return OK;
5612}
5613#endif
5614
5615#ifdef FEAT_CLIENTSERVER
5616 static void
5617remote_common(typval_T *argvars, typval_T *rettv, int expr)
5618{
5619 char_u *server_name;
5620 char_u *keys;
5621 char_u *r = NULL;
5622 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005623 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005624# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005625 HWND w;
5626# else
5627 Window w;
5628# endif
5629
5630 if (check_restricted() || check_secure())
5631 return;
5632
5633# ifdef FEAT_X11
5634 if (check_connection() == FAIL)
5635 return;
5636# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005637 if (argvars[2].v_type != VAR_UNKNOWN
5638 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005639 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005640
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005641 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005642 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005643 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005644 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005645# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005646 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005647# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005648 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5649 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005650# endif
5651 {
5652 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005653 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005654 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005655 vim_free(r);
5656 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005657 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005658 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 return;
5660 }
5661
5662 rettv->vval.v_string = r;
5663
5664 if (argvars[2].v_type != VAR_UNKNOWN)
5665 {
5666 dictitem_T v;
5667 char_u str[30];
5668 char_u *idvar;
5669
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005670 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005671 if (idvar != NULL && *idvar != NUL)
5672 {
5673 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5674 v.di_tv.v_type = VAR_STRING;
5675 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005676 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005677 vim_free(v.di_tv.vval.v_string);
5678 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005679 }
5680}
5681#endif
5682
5683/*
5684 * "remote_expr()" function
5685 */
5686 static void
5687f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5688{
5689 rettv->v_type = VAR_STRING;
5690 rettv->vval.v_string = NULL;
5691#ifdef FEAT_CLIENTSERVER
5692 remote_common(argvars, rettv, TRUE);
5693#endif
5694}
5695
5696/*
5697 * "remote_foreground()" function
5698 */
5699 static void
5700f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5701{
5702#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005703# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005704 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005705 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005706 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005707
5708 if (server_name != NULL)
5709 serverForeground(server_name);
5710 }
5711# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005712 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005713 argvars[1].v_type = VAR_STRING;
5714 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5715 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005716 rettv->v_type = VAR_STRING;
5717 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005718 remote_common(argvars, rettv, TRUE);
5719 vim_free(argvars[1].vval.v_string);
5720# endif
5721#endif
5722}
5723
5724 static void
5725f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5726{
5727#ifdef FEAT_CLIENTSERVER
5728 dictitem_T v;
5729 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005730# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005731 long_u n = 0;
5732# endif
5733 char_u *serverid;
5734
5735 if (check_restricted() || check_secure())
5736 {
5737 rettv->vval.v_number = -1;
5738 return;
5739 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005740 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005741 if (serverid == NULL)
5742 {
5743 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005744 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005745 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005746# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005747 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5748 if (n == 0)
5749 rettv->vval.v_number = -1;
5750 else
5751 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005752 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005753 rettv->vval.v_number = (s != NULL);
5754 }
5755# else
5756 if (check_connection() == FAIL)
5757 return;
5758
5759 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5760 serverStrToWin(serverid), &s);
5761# endif
5762
5763 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5764 {
5765 char_u *retvar;
5766
5767 v.di_tv.v_type = VAR_STRING;
5768 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005769 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005770 if (retvar != NULL)
5771 set_var(retvar, &v.di_tv, FALSE);
5772 vim_free(v.di_tv.vval.v_string);
5773 }
5774#else
5775 rettv->vval.v_number = -1;
5776#endif
5777}
5778
5779 static void
5780f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5781{
5782 char_u *r = NULL;
5783
5784#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005785 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005786
5787 if (serverid != NULL && !check_restricted() && !check_secure())
5788 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005789 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005790# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005791 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005792 long_u n = 0;
5793# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005794
5795 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005796 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005797
Bram Moolenaar4f974752019-02-17 17:44:42 +01005798# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5800 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005801 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005802 if (r == NULL)
5803# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005804 if (check_connection() == FAIL
5805 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5806 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005807# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005808 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005809 }
5810#endif
5811 rettv->v_type = VAR_STRING;
5812 rettv->vval.v_string = r;
5813}
5814
5815/*
5816 * "remote_send()" function
5817 */
5818 static void
5819f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5820{
5821 rettv->v_type = VAR_STRING;
5822 rettv->vval.v_string = NULL;
5823#ifdef FEAT_CLIENTSERVER
5824 remote_common(argvars, rettv, FALSE);
5825#endif
5826}
5827
5828/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005829 * "remote_startserver()" function
5830 */
5831 static void
5832f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5833{
5834#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005835 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005836
5837 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005838 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005839 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005840 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005841 else
5842 {
5843# ifdef FEAT_X11
5844 if (check_connection() == OK)
5845 serverRegisterName(X_DISPLAY, server);
5846# else
5847 serverSetName(server);
5848# endif
5849 }
5850#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005851 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005852#endif
5853}
5854
5855/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005856 * "rename({from}, {to})" function
5857 */
5858 static void
5859f_rename(typval_T *argvars, typval_T *rettv)
5860{
5861 char_u buf[NUMBUFLEN];
5862
5863 if (check_restricted() || check_secure())
5864 rettv->vval.v_number = -1;
5865 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005866 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5867 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868}
5869
5870/*
5871 * "repeat()" function
5872 */
5873 static void
5874f_repeat(typval_T *argvars, typval_T *rettv)
5875{
5876 char_u *p;
5877 int n;
5878 int slen;
5879 int len;
5880 char_u *r;
5881 int i;
5882
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005883 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005884 if (argvars[0].v_type == VAR_LIST)
5885 {
5886 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5887 while (n-- > 0)
5888 if (list_extend(rettv->vval.v_list,
5889 argvars[0].vval.v_list, NULL) == FAIL)
5890 break;
5891 }
5892 else
5893 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005894 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005895 rettv->v_type = VAR_STRING;
5896 rettv->vval.v_string = NULL;
5897
5898 slen = (int)STRLEN(p);
5899 len = slen * n;
5900 if (len <= 0)
5901 return;
5902
5903 r = alloc(len + 1);
5904 if (r != NULL)
5905 {
5906 for (i = 0; i < n; i++)
5907 mch_memmove(r + i * slen, p, (size_t)slen);
5908 r[len] = NUL;
5909 }
5910
5911 rettv->vval.v_string = r;
5912 }
5913}
5914
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005915#define SP_NOMOVE 0x01 // don't move cursor
5916#define SP_REPEAT 0x02 // repeat to find outer pair
5917#define SP_RETCOUNT 0x04 // return matchcount
5918#define SP_SETPCMARK 0x08 // set previous context mark
5919#define SP_START 0x10 // accept match at start position
5920#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5921#define SP_END 0x40 // leave cursor at end of match
5922#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005923
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005924/*
5925 * Get flags for a search function.
5926 * Possibly sets "p_ws".
5927 * Returns BACKWARD, FORWARD or zero (for an error).
5928 */
5929 static int
5930get_search_arg(typval_T *varp, int *flagsp)
5931{
5932 int dir = FORWARD;
5933 char_u *flags;
5934 char_u nbuf[NUMBUFLEN];
5935 int mask;
5936
5937 if (varp->v_type != VAR_UNKNOWN)
5938 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005939 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005940 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005941 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005942 while (*flags != NUL)
5943 {
5944 switch (*flags)
5945 {
5946 case 'b': dir = BACKWARD; break;
5947 case 'w': p_ws = TRUE; break;
5948 case 'W': p_ws = FALSE; break;
5949 default: mask = 0;
5950 if (flagsp != NULL)
5951 switch (*flags)
5952 {
5953 case 'c': mask = SP_START; break;
5954 case 'e': mask = SP_END; break;
5955 case 'm': mask = SP_RETCOUNT; break;
5956 case 'n': mask = SP_NOMOVE; break;
5957 case 'p': mask = SP_SUBPAT; break;
5958 case 'r': mask = SP_REPEAT; break;
5959 case 's': mask = SP_SETPCMARK; break;
5960 case 'z': mask = SP_COLUMN; break;
5961 }
5962 if (mask == 0)
5963 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005964 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005965 dir = 0;
5966 }
5967 else
5968 *flagsp |= mask;
5969 }
5970 if (dir == 0)
5971 break;
5972 ++flags;
5973 }
5974 }
5975 return dir;
5976}
5977
5978/*
5979 * Shared by search() and searchpos() functions.
5980 */
5981 static int
5982search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5983{
5984 int flags;
5985 char_u *pat;
5986 pos_T pos;
5987 pos_T save_cursor;
5988 int save_p_ws = p_ws;
5989 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005990 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005991 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005992#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005993 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005994 long time_limit = 0;
5995#endif
5996 int options = SEARCH_KEEP;
5997 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005998 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005999
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006000 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006001 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006002 if (dir == 0)
6003 goto theend;
6004 flags = *flagsp;
6005 if (flags & SP_START)
6006 options |= SEARCH_START;
6007 if (flags & SP_END)
6008 options |= SEARCH_END;
6009 if (flags & SP_COLUMN)
6010 options |= SEARCH_COL;
6011
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006012 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006013 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6014 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006015 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006016 if (lnum_stop < 0)
6017 goto theend;
6018#ifdef FEAT_RELTIME
6019 if (argvars[3].v_type != VAR_UNKNOWN)
6020 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006021 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006022 if (time_limit < 0)
6023 goto theend;
6024 }
6025#endif
6026 }
6027
6028#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006029 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006030 profile_setlimit(time_limit, &tm);
6031#endif
6032
6033 /*
6034 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6035 * Check to make sure only those flags are set.
6036 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6037 * flags cannot be set. Check for that condition also.
6038 */
6039 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6040 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6041 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006042 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006043 goto theend;
6044 }
6045
6046 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006047 vim_memset(&sia, 0, sizeof(sia));
6048 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6049#ifdef FEAT_RELTIME
6050 sia.sa_tm = &tm;
6051#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006052 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006053 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006054 if (subpatnum != FAIL)
6055 {
6056 if (flags & SP_SUBPAT)
6057 retval = subpatnum;
6058 else
6059 retval = pos.lnum;
6060 if (flags & SP_SETPCMARK)
6061 setpcmark();
6062 curwin->w_cursor = pos;
6063 if (match_pos != NULL)
6064 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006065 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006066 match_pos->lnum = pos.lnum;
6067 match_pos->col = pos.col + 1;
6068 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006069 // "/$" will put the cursor after the end of the line, may need to
6070 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006071 check_cursor();
6072 }
6073
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006074 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006075 if (flags & SP_NOMOVE)
6076 curwin->w_cursor = save_cursor;
6077 else
6078 curwin->w_set_curswant = TRUE;
6079theend:
6080 p_ws = save_p_ws;
6081
6082 return retval;
6083}
6084
6085#ifdef FEAT_FLOAT
6086
6087/*
6088 * round() is not in C90, use ceil() or floor() instead.
6089 */
6090 float_T
6091vim_round(float_T f)
6092{
6093 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6094}
6095
6096/*
6097 * "round({float})" function
6098 */
6099 static void
6100f_round(typval_T *argvars, typval_T *rettv)
6101{
6102 float_T f = 0.0;
6103
6104 rettv->v_type = VAR_FLOAT;
6105 if (get_float_arg(argvars, &f) == OK)
6106 rettv->vval.v_float = vim_round(f);
6107 else
6108 rettv->vval.v_float = 0.0;
6109}
6110#endif
6111
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006112#ifdef FEAT_RUBY
6113/*
6114 * "rubyeval()" function
6115 */
6116 static void
6117f_rubyeval(typval_T *argvars, typval_T *rettv)
6118{
6119 char_u *str;
6120 char_u buf[NUMBUFLEN];
6121
6122 str = tv_get_string_buf(&argvars[0], buf);
6123 do_rubyeval(str, rettv);
6124}
6125#endif
6126
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006127/*
6128 * "screenattr()" function
6129 */
6130 static void
6131f_screenattr(typval_T *argvars, typval_T *rettv)
6132{
6133 int row;
6134 int col;
6135 int c;
6136
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006137 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6138 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006139 if (row < 0 || row >= screen_Rows
6140 || col < 0 || col >= screen_Columns)
6141 c = -1;
6142 else
6143 c = ScreenAttrs[LineOffset[row] + col];
6144 rettv->vval.v_number = c;
6145}
6146
6147/*
6148 * "screenchar()" function
6149 */
6150 static void
6151f_screenchar(typval_T *argvars, typval_T *rettv)
6152{
6153 int row;
6154 int col;
6155 int off;
6156 int c;
6157
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006158 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6159 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006160 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006161 c = -1;
6162 else
6163 {
6164 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006165 if (enc_utf8 && ScreenLinesUC[off] != 0)
6166 c = ScreenLinesUC[off];
6167 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006168 c = ScreenLines[off];
6169 }
6170 rettv->vval.v_number = c;
6171}
6172
6173/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006174 * "screenchars()" function
6175 */
6176 static void
6177f_screenchars(typval_T *argvars, typval_T *rettv)
6178{
6179 int row;
6180 int col;
6181 int off;
6182 int c;
6183 int i;
6184
6185 if (rettv_list_alloc(rettv) == FAIL)
6186 return;
6187 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6188 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6189 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6190 return;
6191
6192 off = LineOffset[row] + col;
6193 if (enc_utf8 && ScreenLinesUC[off] != 0)
6194 c = ScreenLinesUC[off];
6195 else
6196 c = ScreenLines[off];
6197 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6198
6199 if (enc_utf8)
6200
6201 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6202 list_append_number(rettv->vval.v_list,
6203 (varnumber_T)ScreenLinesC[i][off]);
6204}
6205
6206/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006207 * "screencol()" function
6208 *
6209 * First column is 1 to be consistent with virtcol().
6210 */
6211 static void
6212f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6213{
6214 rettv->vval.v_number = screen_screencol() + 1;
6215}
6216
6217/*
6218 * "screenrow()" function
6219 */
6220 static void
6221f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6222{
6223 rettv->vval.v_number = screen_screenrow() + 1;
6224}
6225
6226/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006227 * "screenstring()" function
6228 */
6229 static void
6230f_screenstring(typval_T *argvars, typval_T *rettv)
6231{
6232 int row;
6233 int col;
6234 int off;
6235 int c;
6236 int i;
6237 char_u buf[MB_MAXBYTES + 1];
6238 int buflen = 0;
6239
6240 rettv->vval.v_string = NULL;
6241 rettv->v_type = VAR_STRING;
6242
6243 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6244 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6245 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6246 return;
6247
6248 off = LineOffset[row] + col;
6249 if (enc_utf8 && ScreenLinesUC[off] != 0)
6250 c = ScreenLinesUC[off];
6251 else
6252 c = ScreenLines[off];
6253 buflen += mb_char2bytes(c, buf);
6254
6255 if (enc_utf8)
6256 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6257 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6258
6259 buf[buflen] = NUL;
6260 rettv->vval.v_string = vim_strsave(buf);
6261}
6262
6263/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264 * "search()" function
6265 */
6266 static void
6267f_search(typval_T *argvars, typval_T *rettv)
6268{
6269 int flags = 0;
6270
6271 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6272}
6273
6274/*
6275 * "searchdecl()" function
6276 */
6277 static void
6278f_searchdecl(typval_T *argvars, typval_T *rettv)
6279{
6280 int locally = 1;
6281 int thisblock = 0;
6282 int error = FALSE;
6283 char_u *name;
6284
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006285 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006286
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006287 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006288 if (argvars[1].v_type != VAR_UNKNOWN)
6289 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006290 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006292 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006293 }
6294 if (!error && name != NULL)
6295 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6296 locally, thisblock, SEARCH_KEEP) == FAIL;
6297}
6298
6299/*
6300 * Used by searchpair() and searchpairpos()
6301 */
6302 static int
6303searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6304{
6305 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006306 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307 int save_p_ws = p_ws;
6308 int dir;
6309 int flags = 0;
6310 char_u nbuf1[NUMBUFLEN];
6311 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006312 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313 long lnum_stop = 0;
6314 long time_limit = 0;
6315
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006316 // Get the three pattern arguments: start, middle, end. Will result in an
6317 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006318 spat = tv_get_string_chk(&argvars[0]);
6319 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6320 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006321 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006322 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006324 // Handle the optional fourth argument: flags
6325 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006326 if (dir == 0)
6327 goto theend;
6328
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006329 // Don't accept SP_END or SP_SUBPAT.
6330 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006331 if ((flags & (SP_END | SP_SUBPAT)) != 0
6332 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6333 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006334 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006335 goto theend;
6336 }
6337
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006338 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006339 if (flags & SP_REPEAT)
6340 p_ws = FALSE;
6341
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006342 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343 if (argvars[3].v_type == VAR_UNKNOWN
6344 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006345 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006346 else
6347 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006348 skip = &argvars[4];
6349 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6350 && skip->v_type != VAR_STRING)
6351 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006352 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006353 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006354 goto theend;
6355 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006356 if (argvars[5].v_type != VAR_UNKNOWN)
6357 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006358 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006359 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006360 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006361 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006362 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006363 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006364#ifdef FEAT_RELTIME
6365 if (argvars[6].v_type != VAR_UNKNOWN)
6366 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006367 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006368 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006369 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006370 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006371 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006372 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373 }
6374#endif
6375 }
6376 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006377
6378 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6379 match_pos, lnum_stop, time_limit);
6380
6381theend:
6382 p_ws = save_p_ws;
6383
6384 return retval;
6385}
6386
6387/*
6388 * "searchpair()" function
6389 */
6390 static void
6391f_searchpair(typval_T *argvars, typval_T *rettv)
6392{
6393 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6394}
6395
6396/*
6397 * "searchpairpos()" function
6398 */
6399 static void
6400f_searchpairpos(typval_T *argvars, typval_T *rettv)
6401{
6402 pos_T match_pos;
6403 int lnum = 0;
6404 int col = 0;
6405
6406 if (rettv_list_alloc(rettv) == FAIL)
6407 return;
6408
6409 if (searchpair_cmn(argvars, &match_pos) > 0)
6410 {
6411 lnum = match_pos.lnum;
6412 col = match_pos.col;
6413 }
6414
6415 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6416 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6417}
6418
6419/*
6420 * Search for a start/middle/end thing.
6421 * Used by searchpair(), see its documentation for the details.
6422 * Returns 0 or -1 for no match,
6423 */
6424 long
6425do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006426 char_u *spat, // start pattern
6427 char_u *mpat, // middle pattern
6428 char_u *epat, // end pattern
6429 int dir, // BACKWARD or FORWARD
6430 typval_T *skip, // skip expression
6431 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006432 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006433 linenr_T lnum_stop, // stop at this line if not zero
6434 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006435{
6436 char_u *save_cpo;
6437 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6438 long retval = 0;
6439 pos_T pos;
6440 pos_T firstpos;
6441 pos_T foundpos;
6442 pos_T save_cursor;
6443 pos_T save_pos;
6444 int n;
6445 int r;
6446 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006447 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006448 int err;
6449 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006450#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006451 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006452#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006453
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006454 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006455 save_cpo = p_cpo;
6456 p_cpo = empty_option;
6457
6458#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006459 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006460 profile_setlimit(time_limit, &tm);
6461#endif
6462
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006463 // Make two search patterns: start/end (pat2, for in nested pairs) and
6464 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006465 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6466 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006467 if (pat2 == NULL || pat3 == NULL)
6468 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006469 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006470 if (*mpat == NUL)
6471 STRCPY(pat3, pat2);
6472 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006473 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 spat, epat, mpat);
6475 if (flags & SP_START)
6476 options |= SEARCH_START;
6477
Bram Moolenaar48570482017-10-30 21:48:41 +01006478 if (skip != NULL)
6479 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006480 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006481 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6482 use_skip = skip->vval.v_string != NULL
6483 && *skip->vval.v_string != NUL;
6484 }
6485
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486 save_cursor = curwin->w_cursor;
6487 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006488 CLEAR_POS(&firstpos);
6489 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006490 pat = pat3;
6491 for (;;)
6492 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006493 searchit_arg_T sia;
6494
6495 vim_memset(&sia, 0, sizeof(sia));
6496 sia.sa_stop_lnum = lnum_stop;
6497#ifdef FEAT_RELTIME
6498 sia.sa_tm = &tm;
6499#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006500 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006501 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006502 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006503 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504 break;
6505
6506 if (firstpos.lnum == 0)
6507 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006508 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006509 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006510 // Found the same position again. Can happen with a pattern that
6511 // has "\zs" at the end and searching backwards. Advance one
6512 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006513 if (dir == BACKWARD)
6514 decl(&pos);
6515 else
6516 incl(&pos);
6517 }
6518 foundpos = pos;
6519
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006520 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006521 options &= ~SEARCH_START;
6522
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006523 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006524 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006525 {
6526 save_pos = curwin->w_cursor;
6527 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006528 err = FALSE;
6529 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006530 curwin->w_cursor = save_pos;
6531 if (err)
6532 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006533 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006534 curwin->w_cursor = save_cursor;
6535 retval = -1;
6536 break;
6537 }
6538 if (r)
6539 continue;
6540 }
6541
6542 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6543 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006544 // Found end when searching backwards or start when searching
6545 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006546 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006547 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006548 }
6549 else
6550 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006551 // Found end when searching forward or start when searching
6552 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006553 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006554 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006555 }
6556
6557 if (nest == 0)
6558 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006559 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560 if (flags & SP_RETCOUNT)
6561 ++retval;
6562 else
6563 retval = pos.lnum;
6564 if (flags & SP_SETPCMARK)
6565 setpcmark();
6566 curwin->w_cursor = pos;
6567 if (!(flags & SP_REPEAT))
6568 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006569 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 }
6571 }
6572
6573 if (match_pos != NULL)
6574 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006575 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006576 match_pos->lnum = curwin->w_cursor.lnum;
6577 match_pos->col = curwin->w_cursor.col + 1;
6578 }
6579
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006580 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006581 if ((flags & SP_NOMOVE) || retval == 0)
6582 curwin->w_cursor = save_cursor;
6583
6584theend:
6585 vim_free(pat2);
6586 vim_free(pat3);
6587 if (p_cpo == empty_option)
6588 p_cpo = save_cpo;
6589 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006590 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006591 free_string_option(save_cpo);
6592
6593 return retval;
6594}
6595
6596/*
6597 * "searchpos()" function
6598 */
6599 static void
6600f_searchpos(typval_T *argvars, typval_T *rettv)
6601{
6602 pos_T match_pos;
6603 int lnum = 0;
6604 int col = 0;
6605 int n;
6606 int flags = 0;
6607
6608 if (rettv_list_alloc(rettv) == FAIL)
6609 return;
6610
6611 n = search_cmn(argvars, &match_pos, &flags);
6612 if (n > 0)
6613 {
6614 lnum = match_pos.lnum;
6615 col = match_pos.col;
6616 }
6617
6618 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6619 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6620 if (flags & SP_SUBPAT)
6621 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6622}
6623
6624 static void
6625f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6626{
6627#ifdef FEAT_CLIENTSERVER
6628 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006629 char_u *server = tv_get_string_chk(&argvars[0]);
6630 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006631
6632 rettv->vval.v_number = -1;
6633 if (server == NULL || reply == NULL)
6634 return;
6635 if (check_restricted() || check_secure())
6636 return;
6637# ifdef FEAT_X11
6638 if (check_connection() == FAIL)
6639 return;
6640# endif
6641
6642 if (serverSendReply(server, reply) < 0)
6643 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006644 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006645 return;
6646 }
6647 rettv->vval.v_number = 0;
6648#else
6649 rettv->vval.v_number = -1;
6650#endif
6651}
6652
6653 static void
6654f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6655{
6656 char_u *r = NULL;
6657
6658#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006659# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006660 r = serverGetVimNames();
6661# else
6662 make_connection();
6663 if (X_DISPLAY != NULL)
6664 r = serverGetVimNames(X_DISPLAY);
6665# endif
6666#endif
6667 rettv->v_type = VAR_STRING;
6668 rettv->vval.v_string = r;
6669}
6670
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006671 static void
6672f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6673{
6674 dict_T *d;
6675 dictitem_T *di;
6676 char_u *csearch;
6677
6678 if (argvars[0].v_type != VAR_DICT)
6679 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006680 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006681 return;
6682 }
6683
6684 if ((d = argvars[0].vval.v_dict) != NULL)
6685 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006686 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006687 if (csearch != NULL)
6688 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 if (enc_utf8)
6690 {
6691 int pcc[MAX_MCO];
6692 int c = utfc_ptr2char(csearch, pcc);
6693
6694 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6695 }
6696 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006697 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006698 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006699 }
6700
6701 di = dict_find(d, (char_u *)"forward", -1);
6702 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006703 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006704 ? FORWARD : BACKWARD);
6705
6706 di = dict_find(d, (char_u *)"until", -1);
6707 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006708 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006709 }
6710}
6711
6712/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006713 * "setenv()" function
6714 */
6715 static void
6716f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6717{
6718 char_u namebuf[NUMBUFLEN];
6719 char_u valbuf[NUMBUFLEN];
6720 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6721
6722 if (argvars[1].v_type == VAR_SPECIAL
6723 && argvars[1].vval.v_number == VVAL_NULL)
6724 vim_unsetenv(name);
6725 else
6726 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6727}
6728
6729/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006730 * "setfperm({fname}, {mode})" function
6731 */
6732 static void
6733f_setfperm(typval_T *argvars, typval_T *rettv)
6734{
6735 char_u *fname;
6736 char_u modebuf[NUMBUFLEN];
6737 char_u *mode_str;
6738 int i;
6739 int mask;
6740 int mode = 0;
6741
6742 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006743 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006744 if (fname == NULL)
6745 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006746 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006747 if (mode_str == NULL)
6748 return;
6749 if (STRLEN(mode_str) != 9)
6750 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006751 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006752 return;
6753 }
6754
6755 mask = 1;
6756 for (i = 8; i >= 0; --i)
6757 {
6758 if (mode_str[i] != '-')
6759 mode |= mask;
6760 mask = mask << 1;
6761 }
6762 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6763}
6764
6765/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006766 * "setpos()" function
6767 */
6768 static void
6769f_setpos(typval_T *argvars, typval_T *rettv)
6770{
6771 pos_T pos;
6772 int fnum;
6773 char_u *name;
6774 colnr_T curswant = -1;
6775
6776 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006777 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006778 if (name != NULL)
6779 {
6780 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6781 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006782 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006783 pos.col = 0;
6784 if (name[0] == '.' && name[1] == NUL)
6785 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006786 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006787 curwin->w_cursor = pos;
6788 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006789 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006790 curwin->w_curswant = curswant - 1;
6791 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006792 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006793 check_cursor();
6794 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006795 }
6796 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6797 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006798 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006799 if (setmark_pos(name[1], &pos, fnum) == OK)
6800 rettv->vval.v_number = 0;
6801 }
6802 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006803 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804 }
6805 }
6806}
6807
6808/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006809 * "setreg()" function
6810 */
6811 static void
6812f_setreg(typval_T *argvars, typval_T *rettv)
6813{
6814 int regname;
6815 char_u *strregname;
6816 char_u *stropt;
6817 char_u *strval;
6818 int append;
6819 char_u yank_type;
6820 long block_len;
6821
6822 block_len = -1;
6823 yank_type = MAUTO;
6824 append = FALSE;
6825
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006826 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006827 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006828
6829 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006830 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831 regname = *strregname;
6832 if (regname == 0 || regname == '@')
6833 regname = '"';
6834
6835 if (argvars[2].v_type != VAR_UNKNOWN)
6836 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006837 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006838 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006839 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006840 for (; *stropt != NUL; ++stropt)
6841 switch (*stropt)
6842 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006843 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006844 append = TRUE;
6845 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006846 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006847 yank_type = MCHAR;
6848 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006849 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006850 yank_type = MLINE;
6851 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006852 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006853 yank_type = MBLOCK;
6854 if (VIM_ISDIGIT(stropt[1]))
6855 {
6856 ++stropt;
6857 block_len = getdigits(&stropt) - 1;
6858 --stropt;
6859 }
6860 break;
6861 }
6862 }
6863
6864 if (argvars[1].v_type == VAR_LIST)
6865 {
6866 char_u **lstval;
6867 char_u **allocval;
6868 char_u buf[NUMBUFLEN];
6869 char_u **curval;
6870 char_u **curallocval;
6871 list_T *ll = argvars[1].vval.v_list;
6872 listitem_T *li;
6873 int len;
6874
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006875 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006876 len = ll == NULL ? 0 : ll->lv_len;
6877
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006878 // First half: use for pointers to result lines; second half: use for
6879 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006880 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006881 if (lstval == NULL)
6882 return;
6883 curval = lstval;
6884 allocval = lstval + len + 2;
6885 curallocval = allocval;
6886
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006887 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006888 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006889 range_list_materialize(ll);
6890 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006891 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006892 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893 if (strval == NULL)
6894 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006895 if (strval == buf)
6896 {
6897 // Need to make a copy, next tv_get_string_buf_chk() will
6898 // overwrite the string.
6899 strval = vim_strsave(buf);
6900 if (strval == NULL)
6901 goto free_lstval;
6902 *curallocval++ = strval;
6903 }
6904 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006905 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006906 }
6907 *curval++ = NULL;
6908
6909 write_reg_contents_lst(regname, lstval, -1,
6910 append, yank_type, block_len);
6911free_lstval:
6912 while (curallocval > allocval)
6913 vim_free(*--curallocval);
6914 vim_free(lstval);
6915 }
6916 else
6917 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006918 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006919 if (strval == NULL)
6920 return;
6921 write_reg_contents_ex(regname, strval, -1,
6922 append, yank_type, block_len);
6923 }
6924 rettv->vval.v_number = 0;
6925}
6926
6927/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006928 * "settagstack()" function
6929 */
6930 static void
6931f_settagstack(typval_T *argvars, typval_T *rettv)
6932{
6933 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6934 win_T *wp;
6935 dict_T *d;
6936 int action = 'r';
6937
6938 rettv->vval.v_number = -1;
6939
6940 // first argument: window number or id
6941 wp = find_win_by_nr_or_id(&argvars[0]);
6942 if (wp == NULL)
6943 return;
6944
6945 // second argument: dict with items to set in the tag stack
6946 if (argvars[1].v_type != VAR_DICT)
6947 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006948 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006949 return;
6950 }
6951 d = argvars[1].vval.v_dict;
6952 if (d == NULL)
6953 return;
6954
6955 // third argument: action - 'a' for append and 'r' for replace.
6956 // default is to replace the stack.
6957 if (argvars[2].v_type == VAR_UNKNOWN)
6958 action = 'r';
6959 else if (argvars[2].v_type == VAR_STRING)
6960 {
6961 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006962 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006963 if (actstr == NULL)
6964 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006965 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6966 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006967 action = *actstr;
6968 else
6969 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006970 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006971 return;
6972 }
6973 }
6974 else
6975 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006976 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006977 return;
6978 }
6979
6980 if (set_tagstack(wp, d, action) == OK)
6981 rettv->vval.v_number = 0;
6982}
6983
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006984#ifdef FEAT_CRYPT
6985/*
6986 * "sha256({string})" function
6987 */
6988 static void
6989f_sha256(typval_T *argvars, typval_T *rettv)
6990{
6991 char_u *p;
6992
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006993 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006994 rettv->vval.v_string = vim_strsave(
6995 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6996 rettv->v_type = VAR_STRING;
6997}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006998#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006999
7000/*
7001 * "shellescape({string})" function
7002 */
7003 static void
7004f_shellescape(typval_T *argvars, typval_T *rettv)
7005{
Bram Moolenaar20615522017-06-05 18:46:26 +02007006 int do_special = non_zero_arg(&argvars[1]);
7007
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007008 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007009 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 rettv->v_type = VAR_STRING;
7011}
7012
7013/*
7014 * shiftwidth() function
7015 */
7016 static void
7017f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7018{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007019 rettv->vval.v_number = 0;
7020
7021 if (argvars[0].v_type != VAR_UNKNOWN)
7022 {
7023 long col;
7024
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007025 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007026 if (col < 0)
7027 return; // type error; errmsg already given
7028#ifdef FEAT_VARTABS
7029 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7030 return;
7031#endif
7032 }
7033
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 rettv->vval.v_number = get_sw_value(curbuf);
7035}
7036
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007037#ifdef FEAT_FLOAT
7038/*
7039 * "sin()" function
7040 */
7041 static void
7042f_sin(typval_T *argvars, typval_T *rettv)
7043{
7044 float_T f = 0.0;
7045
7046 rettv->v_type = VAR_FLOAT;
7047 if (get_float_arg(argvars, &f) == OK)
7048 rettv->vval.v_float = sin(f);
7049 else
7050 rettv->vval.v_float = 0.0;
7051}
7052
7053/*
7054 * "sinh()" function
7055 */
7056 static void
7057f_sinh(typval_T *argvars, typval_T *rettv)
7058{
7059 float_T f = 0.0;
7060
7061 rettv->v_type = VAR_FLOAT;
7062 if (get_float_arg(argvars, &f) == OK)
7063 rettv->vval.v_float = sinh(f);
7064 else
7065 rettv->vval.v_float = 0.0;
7066}
7067#endif
7068
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069/*
7070 * "soundfold({word})" function
7071 */
7072 static void
7073f_soundfold(typval_T *argvars, typval_T *rettv)
7074{
7075 char_u *s;
7076
7077 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007078 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007079#ifdef FEAT_SPELL
7080 rettv->vval.v_string = eval_soundfold(s);
7081#else
7082 rettv->vval.v_string = vim_strsave(s);
7083#endif
7084}
7085
7086/*
7087 * "spellbadword()" function
7088 */
7089 static void
7090f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7091{
7092 char_u *word = (char_u *)"";
7093 hlf_T attr = HLF_COUNT;
7094 int len = 0;
7095
7096 if (rettv_list_alloc(rettv) == FAIL)
7097 return;
7098
7099#ifdef FEAT_SPELL
7100 if (argvars[0].v_type == VAR_UNKNOWN)
7101 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007102 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007103 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7104 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007105 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007106 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007107 curwin->w_set_curswant = TRUE;
7108 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007109 }
7110 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7111 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007112 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007113 int capcol = -1;
7114
7115 if (str != NULL)
7116 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007117 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 while (*str != NUL)
7119 {
7120 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7121 if (attr != HLF_COUNT)
7122 {
7123 word = str;
7124 break;
7125 }
7126 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007127 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007128 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007129 }
7130 }
7131 }
7132#endif
7133
7134 list_append_string(rettv->vval.v_list, word, len);
7135 list_append_string(rettv->vval.v_list, (char_u *)(
7136 attr == HLF_SPB ? "bad" :
7137 attr == HLF_SPR ? "rare" :
7138 attr == HLF_SPL ? "local" :
7139 attr == HLF_SPC ? "caps" :
7140 ""), -1);
7141}
7142
7143/*
7144 * "spellsuggest()" function
7145 */
7146 static void
7147f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7148{
7149#ifdef FEAT_SPELL
7150 char_u *str;
7151 int typeerr = FALSE;
7152 int maxcount;
7153 garray_T ga;
7154 int i;
7155 listitem_T *li;
7156 int need_capital = FALSE;
7157#endif
7158
7159 if (rettv_list_alloc(rettv) == FAIL)
7160 return;
7161
7162#ifdef FEAT_SPELL
7163 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7164 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007165 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007166 if (argvars[1].v_type != VAR_UNKNOWN)
7167 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007168 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007169 if (maxcount <= 0)
7170 return;
7171 if (argvars[2].v_type != VAR_UNKNOWN)
7172 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007173 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007174 if (typeerr)
7175 return;
7176 }
7177 }
7178 else
7179 maxcount = 25;
7180
7181 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7182
7183 for (i = 0; i < ga.ga_len; ++i)
7184 {
7185 str = ((char_u **)ga.ga_data)[i];
7186
7187 li = listitem_alloc();
7188 if (li == NULL)
7189 vim_free(str);
7190 else
7191 {
7192 li->li_tv.v_type = VAR_STRING;
7193 li->li_tv.v_lock = 0;
7194 li->li_tv.vval.v_string = str;
7195 list_append(rettv->vval.v_list, li);
7196 }
7197 }
7198 ga_clear(&ga);
7199 }
7200#endif
7201}
7202
7203 static void
7204f_split(typval_T *argvars, typval_T *rettv)
7205{
7206 char_u *str;
7207 char_u *end;
7208 char_u *pat = NULL;
7209 regmatch_T regmatch;
7210 char_u patbuf[NUMBUFLEN];
7211 char_u *save_cpo;
7212 int match;
7213 colnr_T col = 0;
7214 int keepempty = FALSE;
7215 int typeerr = FALSE;
7216
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007217 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218 save_cpo = p_cpo;
7219 p_cpo = (char_u *)"";
7220
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007221 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007222 if (argvars[1].v_type != VAR_UNKNOWN)
7223 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007224 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007225 if (pat == NULL)
7226 typeerr = TRUE;
7227 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007228 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229 }
7230 if (pat == NULL || *pat == NUL)
7231 pat = (char_u *)"[\\x01- ]\\+";
7232
7233 if (rettv_list_alloc(rettv) == FAIL)
7234 return;
7235 if (typeerr)
7236 return;
7237
7238 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7239 if (regmatch.regprog != NULL)
7240 {
7241 regmatch.rm_ic = FALSE;
7242 while (*str != NUL || keepempty)
7243 {
7244 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007245 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007246 else
7247 match = vim_regexec_nl(&regmatch, str, col);
7248 if (match)
7249 end = regmatch.startp[0];
7250 else
7251 end = str + STRLEN(str);
7252 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7253 && *str != NUL && match && end < regmatch.endp[0]))
7254 {
7255 if (list_append_string(rettv->vval.v_list, str,
7256 (int)(end - str)) == FAIL)
7257 break;
7258 }
7259 if (!match)
7260 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007261 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007262 if (regmatch.endp[0] > str)
7263 col = 0;
7264 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007265 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007266 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267 str = regmatch.endp[0];
7268 }
7269
7270 vim_regfree(regmatch.regprog);
7271 }
7272
7273 p_cpo = save_cpo;
7274}
7275
7276#ifdef FEAT_FLOAT
7277/*
7278 * "sqrt()" function
7279 */
7280 static void
7281f_sqrt(typval_T *argvars, typval_T *rettv)
7282{
7283 float_T f = 0.0;
7284
7285 rettv->v_type = VAR_FLOAT;
7286 if (get_float_arg(argvars, &f) == OK)
7287 rettv->vval.v_float = sqrt(f);
7288 else
7289 rettv->vval.v_float = 0.0;
7290}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007291#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007292
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007293#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007294/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007295 * "str2float()" function
7296 */
7297 static void
7298f_str2float(typval_T *argvars, typval_T *rettv)
7299{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007300 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007301 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007302
Bram Moolenaar08243d22017-01-10 16:12:29 +01007303 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007304 p = skipwhite(p + 1);
7305 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007306 if (isneg)
7307 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007308 rettv->v_type = VAR_FLOAT;
7309}
7310#endif
7311
7312/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007313 * "str2list()" function
7314 */
7315 static void
7316f_str2list(typval_T *argvars, typval_T *rettv)
7317{
7318 char_u *p;
7319 int utf8 = FALSE;
7320
7321 if (rettv_list_alloc(rettv) == FAIL)
7322 return;
7323
7324 if (argvars[1].v_type != VAR_UNKNOWN)
7325 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7326
7327 p = tv_get_string(&argvars[0]);
7328
7329 if (has_mbyte || utf8)
7330 {
7331 int (*ptr2len)(char_u *);
7332 int (*ptr2char)(char_u *);
7333
7334 if (utf8 || enc_utf8)
7335 {
7336 ptr2len = utf_ptr2len;
7337 ptr2char = utf_ptr2char;
7338 }
7339 else
7340 {
7341 ptr2len = mb_ptr2len;
7342 ptr2char = mb_ptr2char;
7343 }
7344
7345 for ( ; *p != NUL; p += (*ptr2len)(p))
7346 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7347 }
7348 else
7349 for ( ; *p != NUL; ++p)
7350 list_append_number(rettv->vval.v_list, *p);
7351}
7352
7353/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007354 * "str2nr()" function
7355 */
7356 static void
7357f_str2nr(typval_T *argvars, typval_T *rettv)
7358{
7359 int base = 10;
7360 char_u *p;
7361 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007362 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007363 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364
7365 if (argvars[1].v_type != VAR_UNKNOWN)
7366 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007367 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368 if (base != 2 && base != 8 && base != 10 && base != 16)
7369 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007370 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007371 return;
7372 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007373 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7374 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007375 }
7376
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007377 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007378 isneg = (*p == '-');
7379 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007380 p = skipwhite(p + 1);
7381 switch (base)
7382 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007383 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7384 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7385 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007387 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7388 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007389 if (isneg)
7390 rettv->vval.v_number = -n;
7391 else
7392 rettv->vval.v_number = n;
7393
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007394}
7395
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007396/*
7397 * "strgetchar()" function
7398 */
7399 static void
7400f_strgetchar(typval_T *argvars, typval_T *rettv)
7401{
7402 char_u *str;
7403 int len;
7404 int error = FALSE;
7405 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007406 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407
7408 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007409 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007410 if (str == NULL)
7411 return;
7412 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007413 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007414 if (error)
7415 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007416
Bram Moolenaar13505972019-01-24 15:04:48 +01007417 while (charidx >= 0 && byteidx < len)
7418 {
7419 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007420 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007421 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7422 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007424 --charidx;
7425 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007426 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427}
7428
7429/*
7430 * "stridx()" function
7431 */
7432 static void
7433f_stridx(typval_T *argvars, typval_T *rettv)
7434{
7435 char_u buf[NUMBUFLEN];
7436 char_u *needle;
7437 char_u *haystack;
7438 char_u *save_haystack;
7439 char_u *pos;
7440 int start_idx;
7441
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007442 needle = tv_get_string_chk(&argvars[1]);
7443 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007444 rettv->vval.v_number = -1;
7445 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007446 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007447
7448 if (argvars[2].v_type != VAR_UNKNOWN)
7449 {
7450 int error = FALSE;
7451
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007452 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007453 if (error || start_idx >= (int)STRLEN(haystack))
7454 return;
7455 if (start_idx >= 0)
7456 haystack += start_idx;
7457 }
7458
7459 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7460 if (pos != NULL)
7461 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7462}
7463
7464/*
7465 * "string()" function
7466 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007467 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007468f_string(typval_T *argvars, typval_T *rettv)
7469{
7470 char_u *tofree;
7471 char_u numbuf[NUMBUFLEN];
7472
7473 rettv->v_type = VAR_STRING;
7474 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7475 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007476 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007477 if (rettv->vval.v_string != NULL && tofree == NULL)
7478 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7479}
7480
7481/*
7482 * "strlen()" function
7483 */
7484 static void
7485f_strlen(typval_T *argvars, typval_T *rettv)
7486{
7487 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007488 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007489}
7490
7491/*
7492 * "strchars()" function
7493 */
7494 static void
7495f_strchars(typval_T *argvars, typval_T *rettv)
7496{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007497 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007498 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007499 varnumber_T len = 0;
7500 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501
7502 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007503 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007505 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007506 else
7507 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007508 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7509 while (*s != NUL)
7510 {
7511 func_mb_ptr2char_adv(&s);
7512 ++len;
7513 }
7514 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007515 }
7516}
7517
7518/*
7519 * "strdisplaywidth()" function
7520 */
7521 static void
7522f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7523{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007524 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007525 int col = 0;
7526
7527 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007528 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529
7530 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7531}
7532
7533/*
7534 * "strwidth()" function
7535 */
7536 static void
7537f_strwidth(typval_T *argvars, typval_T *rettv)
7538{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007539 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540
Bram Moolenaar13505972019-01-24 15:04:48 +01007541 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007542}
7543
7544/*
7545 * "strcharpart()" function
7546 */
7547 static void
7548f_strcharpart(typval_T *argvars, typval_T *rettv)
7549{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007550 char_u *p;
7551 int nchar;
7552 int nbyte = 0;
7553 int charlen;
7554 int len = 0;
7555 int slen;
7556 int error = FALSE;
7557
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007558 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007559 slen = (int)STRLEN(p);
7560
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007561 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007562 if (!error)
7563 {
7564 if (nchar > 0)
7565 while (nchar > 0 && nbyte < slen)
7566 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007567 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007568 --nchar;
7569 }
7570 else
7571 nbyte = nchar;
7572 if (argvars[2].v_type != VAR_UNKNOWN)
7573 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007574 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575 while (charlen > 0 && nbyte + len < slen)
7576 {
7577 int off = nbyte + len;
7578
7579 if (off < 0)
7580 len += 1;
7581 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007582 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007583 --charlen;
7584 }
7585 }
7586 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007587 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588 }
7589
7590 /*
7591 * Only return the overlap between the specified part and the actual
7592 * string.
7593 */
7594 if (nbyte < 0)
7595 {
7596 len += nbyte;
7597 nbyte = 0;
7598 }
7599 else if (nbyte > slen)
7600 nbyte = slen;
7601 if (len < 0)
7602 len = 0;
7603 else if (nbyte + len > slen)
7604 len = slen - nbyte;
7605
7606 rettv->v_type = VAR_STRING;
7607 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007608}
7609
7610/*
7611 * "strpart()" function
7612 */
7613 static void
7614f_strpart(typval_T *argvars, typval_T *rettv)
7615{
7616 char_u *p;
7617 int n;
7618 int len;
7619 int slen;
7620 int error = FALSE;
7621
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007622 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007623 slen = (int)STRLEN(p);
7624
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007625 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626 if (error)
7627 len = 0;
7628 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007629 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007630 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007631 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632
7633 /*
7634 * Only return the overlap between the specified part and the actual
7635 * string.
7636 */
7637 if (n < 0)
7638 {
7639 len += n;
7640 n = 0;
7641 }
7642 else if (n > slen)
7643 n = slen;
7644 if (len < 0)
7645 len = 0;
7646 else if (n + len > slen)
7647 len = slen - n;
7648
7649 rettv->v_type = VAR_STRING;
7650 rettv->vval.v_string = vim_strnsave(p + n, len);
7651}
7652
7653/*
7654 * "strridx()" function
7655 */
7656 static void
7657f_strridx(typval_T *argvars, typval_T *rettv)
7658{
7659 char_u buf[NUMBUFLEN];
7660 char_u *needle;
7661 char_u *haystack;
7662 char_u *rest;
7663 char_u *lastmatch = NULL;
7664 int haystack_len, end_idx;
7665
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007666 needle = tv_get_string_chk(&argvars[1]);
7667 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007668
7669 rettv->vval.v_number = -1;
7670 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007671 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672
7673 haystack_len = (int)STRLEN(haystack);
7674 if (argvars[2].v_type != VAR_UNKNOWN)
7675 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007676 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007677 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007679 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007680 }
7681 else
7682 end_idx = haystack_len;
7683
7684 if (*needle == NUL)
7685 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007686 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007687 lastmatch = haystack + end_idx;
7688 }
7689 else
7690 {
7691 for (rest = haystack; *rest != '\0'; ++rest)
7692 {
7693 rest = (char_u *)strstr((char *)rest, (char *)needle);
7694 if (rest == NULL || rest > haystack + end_idx)
7695 break;
7696 lastmatch = rest;
7697 }
7698 }
7699
7700 if (lastmatch == NULL)
7701 rettv->vval.v_number = -1;
7702 else
7703 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7704}
7705
7706/*
7707 * "strtrans()" function
7708 */
7709 static void
7710f_strtrans(typval_T *argvars, typval_T *rettv)
7711{
7712 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007713 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714}
7715
7716/*
7717 * "submatch()" function
7718 */
7719 static void
7720f_submatch(typval_T *argvars, typval_T *rettv)
7721{
7722 int error = FALSE;
7723 int no;
7724 int retList = 0;
7725
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007726 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007727 if (error)
7728 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007729 if (no < 0 || no >= NSUBEXP)
7730 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007731 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007732 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007733 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007734 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007735 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007736 if (error)
7737 return;
7738
7739 if (retList == 0)
7740 {
7741 rettv->v_type = VAR_STRING;
7742 rettv->vval.v_string = reg_submatch(no);
7743 }
7744 else
7745 {
7746 rettv->v_type = VAR_LIST;
7747 rettv->vval.v_list = reg_submatch_list(no);
7748 }
7749}
7750
7751/*
7752 * "substitute()" function
7753 */
7754 static void
7755f_substitute(typval_T *argvars, typval_T *rettv)
7756{
7757 char_u patbuf[NUMBUFLEN];
7758 char_u subbuf[NUMBUFLEN];
7759 char_u flagsbuf[NUMBUFLEN];
7760
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007761 char_u *str = tv_get_string_chk(&argvars[0]);
7762 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007763 char_u *sub = NULL;
7764 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007765 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007766
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007767 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7768 expr = &argvars[2];
7769 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007770 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007771
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007772 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007773 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7774 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007775 rettv->vval.v_string = NULL;
7776 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007777 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007778}
7779
7780/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007781 * "swapinfo(swap_filename)" function
7782 */
7783 static void
7784f_swapinfo(typval_T *argvars, typval_T *rettv)
7785{
7786 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007787 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007788}
7789
7790/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007791 * "swapname(expr)" function
7792 */
7793 static void
7794f_swapname(typval_T *argvars, typval_T *rettv)
7795{
7796 buf_T *buf;
7797
7798 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007799 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007800 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7801 || buf->b_ml.ml_mfp->mf_fname == NULL)
7802 rettv->vval.v_string = NULL;
7803 else
7804 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7805}
7806
7807/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007808 * "synID(lnum, col, trans)" function
7809 */
7810 static void
7811f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7812{
7813 int id = 0;
7814#ifdef FEAT_SYN_HL
7815 linenr_T lnum;
7816 colnr_T col;
7817 int trans;
7818 int transerr = FALSE;
7819
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007820 lnum = tv_get_lnum(argvars); // -1 on type error
7821 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007822 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007823
7824 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7825 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7826 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7827#endif
7828
7829 rettv->vval.v_number = id;
7830}
7831
7832/*
7833 * "synIDattr(id, what [, mode])" function
7834 */
7835 static void
7836f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7837{
7838 char_u *p = NULL;
7839#ifdef FEAT_SYN_HL
7840 int id;
7841 char_u *what;
7842 char_u *mode;
7843 char_u modebuf[NUMBUFLEN];
7844 int modec;
7845
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007846 id = (int)tv_get_number(&argvars[0]);
7847 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848 if (argvars[2].v_type != VAR_UNKNOWN)
7849 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007850 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007851 modec = TOLOWER_ASC(mode[0]);
7852 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007853 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854 }
7855 else
7856 {
7857#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7858 if (USE_24BIT)
7859 modec = 'g';
7860 else
7861#endif
7862 if (t_colors > 1)
7863 modec = 'c';
7864 else
7865 modec = 't';
7866 }
7867
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 switch (TOLOWER_ASC(what[0]))
7869 {
7870 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007871 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007872 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007873 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874 p = highlight_has_attr(id, HL_BOLD, modec);
7875 break;
7876
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007877 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007878 p = highlight_color(id, what, modec);
7879 break;
7880
7881 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007882 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007883 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007884 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885 p = highlight_has_attr(id, HL_ITALIC, modec);
7886 break;
7887
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007888 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007889 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 break;
7891
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007892 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 p = highlight_has_attr(id, HL_INVERSE, modec);
7894 break;
7895
7896 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007897 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007898 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007899 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007900 else if (TOLOWER_ASC(what[1]) == 't' &&
7901 TOLOWER_ASC(what[2]) == 'r')
7902 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007903 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 p = highlight_has_attr(id, HL_STANDOUT, modec);
7905 break;
7906
7907 case 'u':
7908 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007909 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7911 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007912 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007913 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7914 break;
7915 }
7916
7917 if (p != NULL)
7918 p = vim_strsave(p);
7919#endif
7920 rettv->v_type = VAR_STRING;
7921 rettv->vval.v_string = p;
7922}
7923
7924/*
7925 * "synIDtrans(id)" function
7926 */
7927 static void
7928f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7929{
7930 int id;
7931
7932#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007933 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007934
7935 if (id > 0)
7936 id = syn_get_final_id(id);
7937 else
7938#endif
7939 id = 0;
7940
7941 rettv->vval.v_number = id;
7942}
7943
7944/*
7945 * "synconcealed(lnum, col)" function
7946 */
7947 static void
7948f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7949{
7950#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7951 linenr_T lnum;
7952 colnr_T col;
7953 int syntax_flags = 0;
7954 int cchar;
7955 int matchid = 0;
7956 char_u str[NUMBUFLEN];
7957#endif
7958
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007959 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960
7961#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007962 lnum = tv_get_lnum(argvars); // -1 on type error
7963 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007964
7965 vim_memset(str, NUL, sizeof(str));
7966
7967 if (rettv_list_alloc(rettv) != FAIL)
7968 {
7969 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7970 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7971 && curwin->w_p_cole > 0)
7972 {
7973 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7974 syntax_flags = get_syntax_info(&matchid);
7975
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007976 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007977 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7978 {
7979 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007980 if (cchar == NUL && curwin->w_p_cole == 1)
7981 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007982 if (cchar != NUL)
7983 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984 if (has_mbyte)
7985 (*mb_char2bytes)(cchar, str);
7986 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987 str[0] = cchar;
7988 }
7989 }
7990 }
7991
7992 list_append_number(rettv->vval.v_list,
7993 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007994 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995 list_append_string(rettv->vval.v_list, str, -1);
7996 list_append_number(rettv->vval.v_list, matchid);
7997 }
7998#endif
7999}
8000
8001/*
8002 * "synstack(lnum, col)" function
8003 */
8004 static void
8005f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8006{
8007#ifdef FEAT_SYN_HL
8008 linenr_T lnum;
8009 colnr_T col;
8010 int i;
8011 int id;
8012#endif
8013
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008014 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008015
8016#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008017 lnum = tv_get_lnum(argvars); // -1 on type error
8018 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019
8020 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8021 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8022 && rettv_list_alloc(rettv) != FAIL)
8023 {
8024 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8025 for (i = 0; ; ++i)
8026 {
8027 id = syn_get_stack_item(i);
8028 if (id < 0)
8029 break;
8030 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8031 break;
8032 }
8033 }
8034#endif
8035}
8036
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008037/*
8038 * "tabpagebuflist()" function
8039 */
8040 static void
8041f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8042{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008043 tabpage_T *tp;
8044 win_T *wp = NULL;
8045
8046 if (argvars[0].v_type == VAR_UNKNOWN)
8047 wp = firstwin;
8048 else
8049 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008050 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008051 if (tp != NULL)
8052 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8053 }
8054 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8055 {
8056 for (; wp != NULL; wp = wp->w_next)
8057 if (list_append_number(rettv->vval.v_list,
8058 wp->w_buffer->b_fnum) == FAIL)
8059 break;
8060 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008061}
8062
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008063/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008064 * "tagfiles()" function
8065 */
8066 static void
8067f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8068{
8069 char_u *fname;
8070 tagname_T tn;
8071 int first;
8072
8073 if (rettv_list_alloc(rettv) == FAIL)
8074 return;
8075 fname = alloc(MAXPATHL);
8076 if (fname == NULL)
8077 return;
8078
8079 for (first = TRUE; ; first = FALSE)
8080 if (get_tagfname(&tn, first, fname) == FAIL
8081 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8082 break;
8083 tagname_free(&tn);
8084 vim_free(fname);
8085}
8086
8087/*
8088 * "taglist()" function
8089 */
8090 static void
8091f_taglist(typval_T *argvars, typval_T *rettv)
8092{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008093 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008094 char_u *tag_pattern;
8095
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008096 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008097
8098 rettv->vval.v_number = FALSE;
8099 if (*tag_pattern == NUL)
8100 return;
8101
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008102 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008103 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008104 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008105 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106}
8107
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008108#ifdef FEAT_FLOAT
8109/*
8110 * "tan()" function
8111 */
8112 static void
8113f_tan(typval_T *argvars, typval_T *rettv)
8114{
8115 float_T f = 0.0;
8116
8117 rettv->v_type = VAR_FLOAT;
8118 if (get_float_arg(argvars, &f) == OK)
8119 rettv->vval.v_float = tan(f);
8120 else
8121 rettv->vval.v_float = 0.0;
8122}
8123
8124/*
8125 * "tanh()" function
8126 */
8127 static void
8128f_tanh(typval_T *argvars, typval_T *rettv)
8129{
8130 float_T f = 0.0;
8131
8132 rettv->v_type = VAR_FLOAT;
8133 if (get_float_arg(argvars, &f) == OK)
8134 rettv->vval.v_float = tanh(f);
8135 else
8136 rettv->vval.v_float = 0.0;
8137}
8138#endif
8139
8140/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008141 * "tolower(string)" function
8142 */
8143 static void
8144f_tolower(typval_T *argvars, typval_T *rettv)
8145{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008147 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148}
8149
8150/*
8151 * "toupper(string)" function
8152 */
8153 static void
8154f_toupper(typval_T *argvars, typval_T *rettv)
8155{
8156 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008157 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158}
8159
8160/*
8161 * "tr(string, fromstr, tostr)" function
8162 */
8163 static void
8164f_tr(typval_T *argvars, typval_T *rettv)
8165{
8166 char_u *in_str;
8167 char_u *fromstr;
8168 char_u *tostr;
8169 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008170 int inlen;
8171 int fromlen;
8172 int tolen;
8173 int idx;
8174 char_u *cpstr;
8175 int cplen;
8176 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008177 char_u buf[NUMBUFLEN];
8178 char_u buf2[NUMBUFLEN];
8179 garray_T ga;
8180
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008181 in_str = tv_get_string(&argvars[0]);
8182 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8183 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008185 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186 rettv->v_type = VAR_STRING;
8187 rettv->vval.v_string = NULL;
8188 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008189 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190 ga_init2(&ga, (int)sizeof(char), 80);
8191
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008193 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008194 if (STRLEN(fromstr) != STRLEN(tostr))
8195 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008196error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008197 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008198 ga_clear(&ga);
8199 return;
8200 }
8201
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008202 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008203 while (*in_str != NUL)
8204 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008205 if (has_mbyte)
8206 {
8207 inlen = (*mb_ptr2len)(in_str);
8208 cpstr = in_str;
8209 cplen = inlen;
8210 idx = 0;
8211 for (p = fromstr; *p != NUL; p += fromlen)
8212 {
8213 fromlen = (*mb_ptr2len)(p);
8214 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8215 {
8216 for (p = tostr; *p != NUL; p += tolen)
8217 {
8218 tolen = (*mb_ptr2len)(p);
8219 if (idx-- == 0)
8220 {
8221 cplen = tolen;
8222 cpstr = p;
8223 break;
8224 }
8225 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008226 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008227 goto error;
8228 break;
8229 }
8230 ++idx;
8231 }
8232
8233 if (first && cpstr == in_str)
8234 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008235 // Check that fromstr and tostr have the same number of
8236 // (multi-byte) characters. Done only once when a character
8237 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238 first = FALSE;
8239 for (p = tostr; *p != NUL; p += tolen)
8240 {
8241 tolen = (*mb_ptr2len)(p);
8242 --idx;
8243 }
8244 if (idx != 0)
8245 goto error;
8246 }
8247
8248 (void)ga_grow(&ga, cplen);
8249 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8250 ga.ga_len += cplen;
8251
8252 in_str += inlen;
8253 }
8254 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008255 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008256 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257 p = vim_strchr(fromstr, *in_str);
8258 if (p != NULL)
8259 ga_append(&ga, tostr[p - fromstr]);
8260 else
8261 ga_append(&ga, *in_str);
8262 ++in_str;
8263 }
8264 }
8265
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008266 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008267 (void)ga_grow(&ga, 1);
8268 ga_append(&ga, NUL);
8269
8270 rettv->vval.v_string = ga.ga_data;
8271}
8272
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008273/*
8274 * "trim({expr})" function
8275 */
8276 static void
8277f_trim(typval_T *argvars, typval_T *rettv)
8278{
8279 char_u buf1[NUMBUFLEN];
8280 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008281 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008282 char_u *mask = NULL;
8283 char_u *tail;
8284 char_u *prev;
8285 char_u *p;
8286 int c1;
8287
8288 rettv->v_type = VAR_STRING;
8289 if (head == NULL)
8290 {
8291 rettv->vval.v_string = NULL;
8292 return;
8293 }
8294
8295 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008296 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008297
8298 while (*head != NUL)
8299 {
8300 c1 = PTR2CHAR(head);
8301 if (mask == NULL)
8302 {
8303 if (c1 > ' ' && c1 != 0xa0)
8304 break;
8305 }
8306 else
8307 {
8308 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8309 if (c1 == PTR2CHAR(p))
8310 break;
8311 if (*p == NUL)
8312 break;
8313 }
8314 MB_PTR_ADV(head);
8315 }
8316
8317 for (tail = head + STRLEN(head); tail > head; tail = prev)
8318 {
8319 prev = tail;
8320 MB_PTR_BACK(head, prev);
8321 c1 = PTR2CHAR(prev);
8322 if (mask == NULL)
8323 {
8324 if (c1 > ' ' && c1 != 0xa0)
8325 break;
8326 }
8327 else
8328 {
8329 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8330 if (c1 == PTR2CHAR(p))
8331 break;
8332 if (*p == NUL)
8333 break;
8334 }
8335 }
8336 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8337}
8338
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339#ifdef FEAT_FLOAT
8340/*
8341 * "trunc({float})" function
8342 */
8343 static void
8344f_trunc(typval_T *argvars, typval_T *rettv)
8345{
8346 float_T f = 0.0;
8347
8348 rettv->v_type = VAR_FLOAT;
8349 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008350 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008351 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8352 else
8353 rettv->vval.v_float = 0.0;
8354}
8355#endif
8356
8357/*
8358 * "type(expr)" function
8359 */
8360 static void
8361f_type(typval_T *argvars, typval_T *rettv)
8362{
8363 int n = -1;
8364
8365 switch (argvars[0].v_type)
8366 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008367 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8368 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008369 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008370 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8371 case VAR_LIST: n = VAR_TYPE_LIST; break;
8372 case VAR_DICT: n = VAR_TYPE_DICT; break;
8373 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8374 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8375 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008376 case VAR_JOB: n = VAR_TYPE_JOB; break;
8377 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008378 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008379 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008380 case VAR_VOID:
Bram Moolenaardd589232020-02-29 17:38:12 +01008381 internal_error_no_abort("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008382 n = -1;
8383 break;
8384 }
8385 rettv->vval.v_number = n;
8386}
8387
8388/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008389 * "virtcol(string)" function
8390 */
8391 static void
8392f_virtcol(typval_T *argvars, typval_T *rettv)
8393{
8394 colnr_T vcol = 0;
8395 pos_T *fp;
8396 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008397 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398
8399 fp = var2fpos(&argvars[0], FALSE, &fnum);
8400 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8401 && fnum == curbuf->b_fnum)
8402 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008403 // Limit the column to a valid value, getvvcol() doesn't check.
8404 if (fp->col < 0)
8405 fp->col = 0;
8406 else
8407 {
8408 len = (int)STRLEN(ml_get(fp->lnum));
8409 if (fp->col > len)
8410 fp->col = len;
8411 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008412 getvvcol(curwin, fp, NULL, NULL, &vcol);
8413 ++vcol;
8414 }
8415
8416 rettv->vval.v_number = vcol;
8417}
8418
8419/*
8420 * "visualmode()" function
8421 */
8422 static void
8423f_visualmode(typval_T *argvars, typval_T *rettv)
8424{
8425 char_u str[2];
8426
8427 rettv->v_type = VAR_STRING;
8428 str[0] = curbuf->b_visual_mode_eval;
8429 str[1] = NUL;
8430 rettv->vval.v_string = vim_strsave(str);
8431
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008432 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008433 if (non_zero_arg(&argvars[0]))
8434 curbuf->b_visual_mode_eval = NUL;
8435}
8436
8437/*
8438 * "wildmenumode()" function
8439 */
8440 static void
8441f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8442{
8443#ifdef FEAT_WILDMENU
8444 if (wild_menu_showing)
8445 rettv->vval.v_number = 1;
8446#endif
8447}
8448
8449/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008450 * "windowsversion()" function
8451 */
8452 static void
8453f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8454{
8455 rettv->v_type = VAR_STRING;
8456 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8457}
8458
8459/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008460 * "wordcount()" function
8461 */
8462 static void
8463f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8464{
8465 if (rettv_dict_alloc(rettv) == FAIL)
8466 return;
8467 cursor_pos_info(rettv->vval.v_dict);
8468}
8469
8470/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008471 * "xor(expr, expr)" function
8472 */
8473 static void
8474f_xor(typval_T *argvars, typval_T *rettv)
8475{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008476 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8477 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008478}
8479
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008480#endif // FEAT_EVAL