blob: 66be42c241a43fa463c975f885caca2439ccf639 [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 Moolenaar10455d42019-11-21 15:36:18 +010023#if defined(MACOS_X)
Bram Moolenaar8d71b542019-08-30 15:46:30 +020024# include <time.h> // for time_t
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020025#endif
26
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027#ifdef FEAT_FLOAT
28static void f_abs(typval_T *argvars, typval_T *rettv);
29static void f_acos(typval_T *argvars, typval_T *rettv);
30#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020031static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020032#ifdef FEAT_FLOAT
33static void f_asin(typval_T *argvars, typval_T *rettv);
34static void f_atan(typval_T *argvars, typval_T *rettv);
35static void f_atan2(typval_T *argvars, typval_T *rettv);
36#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010037#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020038static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010039static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010040# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010041static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_byte2line(typval_T *argvars, typval_T *rettv);
45static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
46static void f_byteidx(typval_T *argvars, typval_T *rettv);
47static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
48static void f_call(typval_T *argvars, typval_T *rettv);
49#ifdef FEAT_FLOAT
50static void f_ceil(typval_T *argvars, typval_T *rettv);
51#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_changenr(typval_T *argvars, typval_T *rettv);
53static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_confirm(typval_T *argvars, typval_T *rettv);
56static void f_copy(typval_T *argvars, typval_T *rettv);
57#ifdef FEAT_FLOAT
58static void f_cos(typval_T *argvars, typval_T *rettv);
59static void f_cosh(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010062#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020063static void f_debugbreak(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020065static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020068static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_escape(typval_T *argvars, typval_T *rettv);
70static void f_eval(typval_T *argvars, typval_T *rettv);
71static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_exists(typval_T *argvars, typval_T *rettv);
74#ifdef FEAT_FLOAT
75static void f_exp(typval_T *argvars, typval_T *rettv);
76#endif
77static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020078static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020079static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080#ifdef FEAT_FLOAT
81static void f_float2nr(typval_T *argvars, typval_T *rettv);
82static void f_floor(typval_T *argvars, typval_T *rettv);
83static void f_fmod(typval_T *argvars, typval_T *rettv);
84#endif
85static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020086static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020087static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020088static void f_function(typval_T *argvars, typval_T *rettv);
89static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
90static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010091static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020094static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020095static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010096static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020097static void f_getpid(typval_T *argvars, typval_T *rettv);
98static void f_getcurpos(typval_T *argvars, typval_T *rettv);
99static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_getreg(typval_T *argvars, typval_T *rettv);
101static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100102static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
104static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_hlID(typval_T *argvars, typval_T *rettv);
106static void f_hlexists(typval_T *argvars, typval_T *rettv);
107static void f_hostname(typval_T *argvars, typval_T *rettv);
108static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200109static void f_index(typval_T *argvars, typval_T *rettv);
110static void f_input(typval_T *argvars, typval_T *rettv);
111static void f_inputdialog(typval_T *argvars, typval_T *rettv);
112static void f_inputlist(typval_T *argvars, typval_T *rettv);
113static void f_inputrestore(typval_T *argvars, typval_T *rettv);
114static void f_inputsave(typval_T *argvars, typval_T *rettv);
115static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100116static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_islocked(typval_T *argvars, typval_T *rettv);
119#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200120static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200121static void f_isnan(typval_T *argvars, typval_T *rettv);
122#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200123static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
124static void f_len(typval_T *argvars, typval_T *rettv);
125static void f_libcall(typval_T *argvars, typval_T *rettv);
126static void f_libcallnr(typval_T *argvars, typval_T *rettv);
127static void f_line(typval_T *argvars, typval_T *rettv);
128static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_localtime(typval_T *argvars, typval_T *rettv);
130#ifdef FEAT_FLOAT
131static void f_log(typval_T *argvars, typval_T *rettv);
132static void f_log10(typval_T *argvars, typval_T *rettv);
133#endif
134#ifdef FEAT_LUA
135static void f_luaeval(typval_T *argvars, typval_T *rettv);
136#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_maparg(typval_T *argvars, typval_T *rettv);
138static void f_mapcheck(typval_T *argvars, typval_T *rettv);
139static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200140static void f_matchend(typval_T *argvars, typval_T *rettv);
141static void f_matchlist(typval_T *argvars, typval_T *rettv);
142static void f_matchstr(typval_T *argvars, typval_T *rettv);
143static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
144static void f_max(typval_T *argvars, typval_T *rettv);
145static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200146#ifdef FEAT_MZSCHEME
147static void f_mzeval(typval_T *argvars, typval_T *rettv);
148#endif
149static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
150static void f_nr2char(typval_T *argvars, typval_T *rettv);
151static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200152#ifdef FEAT_PERL
153static void f_perleval(typval_T *argvars, typval_T *rettv);
154#endif
155#ifdef FEAT_FLOAT
156static void f_pow(typval_T *argvars, typval_T *rettv);
157#endif
158static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
159static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200160static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200161static void f_pumvisible(typval_T *argvars, typval_T *rettv);
162#ifdef FEAT_PYTHON3
163static void f_py3eval(typval_T *argvars, typval_T *rettv);
164#endif
165#ifdef FEAT_PYTHON
166static void f_pyeval(typval_T *argvars, typval_T *rettv);
167#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100168#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
169static void f_pyxeval(typval_T *argvars, typval_T *rettv);
170#endif
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100171static void f_test_srand_seed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100172static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200173static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200174static void f_reg_executing(typval_T *argvars, typval_T *rettv);
175static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200176static void f_reltime(typval_T *argvars, typval_T *rettv);
177#ifdef FEAT_FLOAT
178static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
179#endif
180static void f_reltimestr(typval_T *argvars, typval_T *rettv);
181static void f_remote_expr(typval_T *argvars, typval_T *rettv);
182static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
183static void f_remote_peek(typval_T *argvars, typval_T *rettv);
184static void f_remote_read(typval_T *argvars, typval_T *rettv);
185static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100186static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187static void f_rename(typval_T *argvars, typval_T *rettv);
188static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200189#ifdef FEAT_FLOAT
190static void f_round(typval_T *argvars, typval_T *rettv);
191#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100192#ifdef FEAT_RUBY
193static void f_rubyeval(typval_T *argvars, typval_T *rettv);
194#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200195static void f_screenattr(typval_T *argvars, typval_T *rettv);
196static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100197static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200198static void f_screencol(typval_T *argvars, typval_T *rettv);
199static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100200static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_search(typval_T *argvars, typval_T *rettv);
202static void f_searchdecl(typval_T *argvars, typval_T *rettv);
203static void f_searchpair(typval_T *argvars, typval_T *rettv);
204static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
205static void f_searchpos(typval_T *argvars, typval_T *rettv);
206static void f_server2client(typval_T *argvars, typval_T *rettv);
207static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200208static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200209static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200210static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200211static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200212static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100213static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200214#ifdef FEAT_CRYPT
215static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200216#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200217static void f_shellescape(typval_T *argvars, typval_T *rettv);
218static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200219#ifdef FEAT_FLOAT
220static void f_sin(typval_T *argvars, typval_T *rettv);
221static void f_sinh(typval_T *argvars, typval_T *rettv);
222#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200223static void f_soundfold(typval_T *argvars, typval_T *rettv);
224static void f_spellbadword(typval_T *argvars, typval_T *rettv);
225static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
226static void f_split(typval_T *argvars, typval_T *rettv);
227#ifdef FEAT_FLOAT
228static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100229#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100230static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100231#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200232static void f_str2float(typval_T *argvars, typval_T *rettv);
233#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200234static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200235static void f_str2nr(typval_T *argvars, typval_T *rettv);
236static void f_strchars(typval_T *argvars, typval_T *rettv);
237#ifdef HAVE_STRFTIME
238static void f_strftime(typval_T *argvars, typval_T *rettv);
239#endif
240static void f_strgetchar(typval_T *argvars, typval_T *rettv);
241static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200242static void f_strlen(typval_T *argvars, typval_T *rettv);
243static void f_strcharpart(typval_T *argvars, typval_T *rettv);
244static void f_strpart(typval_T *argvars, typval_T *rettv);
Bram Moolenaar10455d42019-11-21 15:36:18 +0100245#ifdef HAVE_STRPTIME
246static void f_strptime(typval_T *argvars, typval_T *rettv);
247#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248static void f_strridx(typval_T *argvars, typval_T *rettv);
249static void f_strtrans(typval_T *argvars, typval_T *rettv);
250static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
251static void f_strwidth(typval_T *argvars, typval_T *rettv);
252static void f_submatch(typval_T *argvars, typval_T *rettv);
253static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200254static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200255static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256static void f_synID(typval_T *argvars, typval_T *rettv);
257static void f_synIDattr(typval_T *argvars, typval_T *rettv);
258static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
259static void f_synstack(typval_T *argvars, typval_T *rettv);
260static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200262static void f_taglist(typval_T *argvars, typval_T *rettv);
263static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264#ifdef FEAT_FLOAT
265static void f_tan(typval_T *argvars, typval_T *rettv);
266static void f_tanh(typval_T *argvars, typval_T *rettv);
267#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200268static void f_tolower(typval_T *argvars, typval_T *rettv);
269static void f_toupper(typval_T *argvars, typval_T *rettv);
270static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100271static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200272#ifdef FEAT_FLOAT
273static void f_trunc(typval_T *argvars, typval_T *rettv);
274#endif
275static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200276static void f_virtcol(typval_T *argvars, typval_T *rettv);
277static void f_visualmode(typval_T *argvars, typval_T *rettv);
278static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100279static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200280static void f_wordcount(typval_T *argvars, typval_T *rettv);
281static void f_xor(typval_T *argvars, typval_T *rettv);
282
283/*
284 * Array with names and number of arguments of all internal functions
285 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
286 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200287typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200288{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200289 char *f_name; // function name
290 char f_min_argc; // minimal number of arguments
291 char f_max_argc; // maximal number of arguments
292 char f_argtype; // for method: FEARG_ values
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100293 type_T *f_rettype; // return type
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200294 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200295 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200296} funcentry_T;
297
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200298// values for f_argtype; zero means it cannot be used as a method
299#define FEARG_1 1 // base is the first argument
300#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200301#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200302#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200303#define FEARG_LAST 9 // base is the last argument
304
Bram Moolenaarac92e252019-08-03 21:58:38 +0200305static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200306{
307#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100308 {"abs", 1, 1, FEARG_1, &t_any, f_abs},
309 {"acos", 1, 1, FEARG_1, &t_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200310#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100311 {"add", 2, 2, FEARG_1, &t_any, f_add},
312 {"and", 2, 2, FEARG_1, &t_number, f_and},
313 {"append", 2, 2, FEARG_LAST, &t_number, f_append},
314 {"appendbufline", 3, 3, FEARG_LAST, &t_number, f_appendbufline},
315 {"argc", 0, 1, 0, &t_number, f_argc},
316 {"argidx", 0, 0, 0, &t_number, f_argidx},
317 {"arglistid", 0, 2, 0, &t_number, f_arglistid},
318 {"argv", 0, 2, 0, &t_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200319#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100320 {"asin", 1, 1, FEARG_1, &t_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200321#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100322 {"assert_beeps", 1, 2, FEARG_1, &t_number, f_assert_beeps},
323 {"assert_equal", 2, 3, FEARG_2, &t_number, f_assert_equal},
324 {"assert_equalfile", 2, 2, FEARG_1, &t_number, f_assert_equalfile},
325 {"assert_exception", 1, 2, 0, &t_number, f_assert_exception},
326 {"assert_fails", 1, 3, FEARG_1, &t_number, f_assert_fails},
327 {"assert_false", 1, 2, FEARG_1, &t_number, f_assert_false},
328 {"assert_inrange", 3, 4, FEARG_3, &t_number, f_assert_inrange},
329 {"assert_match", 2, 3, FEARG_2, &t_number, f_assert_match},
330 {"assert_notequal", 2, 3, FEARG_2, &t_number, f_assert_notequal},
331 {"assert_notmatch", 2, 3, FEARG_2, &t_number, f_assert_notmatch},
332 {"assert_report", 1, 1, FEARG_1, &t_number, f_assert_report},
333 {"assert_true", 1, 2, FEARG_1, &t_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200334#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100335 {"atan", 1, 1, FEARG_1, &t_float, f_atan},
336 {"atan2", 2, 2, FEARG_1, &t_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200337#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100338#ifdef FEAT_BEVAL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100339 {"balloon_gettext", 0, 0, 0, &t_string, f_balloon_gettext},
340 {"balloon_show", 1, 1, FEARG_1, &t_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100341# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100342 {"balloon_split", 1, 1, FEARG_1, &t_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100343# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100344#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100345 {"browse", 4, 4, 0, &t_string, f_browse},
346 {"browsedir", 2, 2, 0, &t_string, f_browsedir},
347 {"bufadd", 1, 1, FEARG_1, &t_number, f_bufadd},
348 {"bufexists", 1, 1, FEARG_1, &t_number, f_bufexists},
349 {"buffer_exists", 1, 1, FEARG_1, &t_number, f_bufexists}, // obsolete
350 {"buffer_name", 0, 1, FEARG_1, &t_string, f_bufname}, // obsolete
351 {"buffer_number", 0, 1, FEARG_1, &t_number, f_bufnr}, // obsolete
352 {"buflisted", 1, 1, FEARG_1, &t_number, f_buflisted},
353 {"bufload", 1, 1, FEARG_1, &t_void, f_bufload},
354 {"bufloaded", 1, 1, FEARG_1, &t_number, f_bufloaded},
355 {"bufname", 0, 1, FEARG_1, &t_string, f_bufname},
356 {"bufnr", 0, 2, FEARG_1, &t_number, f_bufnr},
357 {"bufwinid", 1, 1, FEARG_1, &t_number, f_bufwinid},
358 {"bufwinnr", 1, 1, FEARG_1, &t_number, f_bufwinnr},
359 {"byte2line", 1, 1, FEARG_1, &t_number, f_byte2line},
360 {"byteidx", 2, 2, FEARG_1, &t_number, f_byteidx},
361 {"byteidxcomp", 2, 2, FEARG_1, &t_number, f_byteidxcomp},
362 {"call", 2, 3, FEARG_1, &t_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200363#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100364 {"ceil", 1, 1, FEARG_1, &t_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200365#endif
366#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100367 {"ch_canread", 1, 1, FEARG_1, &t_number, f_ch_canread},
368 {"ch_close", 1, 1, FEARG_1, &t_void, f_ch_close},
369 {"ch_close_in", 1, 1, FEARG_1, &t_void, f_ch_close_in},
370 {"ch_evalexpr", 2, 3, FEARG_1, &t_any, f_ch_evalexpr},
371 {"ch_evalraw", 2, 3, FEARG_1, &t_any, f_ch_evalraw},
372 {"ch_getbufnr", 2, 2, FEARG_1, &t_number, f_ch_getbufnr},
373 {"ch_getjob", 1, 1, FEARG_1, &t_job, f_ch_getjob},
374 {"ch_info", 1, 1, FEARG_1, &t_dict_any, f_ch_info},
375 {"ch_log", 1, 2, FEARG_1, &t_void, f_ch_log},
376 {"ch_logfile", 1, 2, FEARG_1, &t_void, f_ch_logfile},
377 {"ch_open", 1, 2, FEARG_1, &t_channel, f_ch_open},
378 {"ch_read", 1, 2, FEARG_1, &t_string, f_ch_read},
379 {"ch_readblob", 1, 2, FEARG_1, &t_blob, f_ch_readblob},
380 {"ch_readraw", 1, 2, FEARG_1, &t_string, f_ch_readraw},
381 {"ch_sendexpr", 2, 3, FEARG_1, &t_void, f_ch_sendexpr},
382 {"ch_sendraw", 2, 3, FEARG_1, &t_void, f_ch_sendraw},
383 {"ch_setoptions", 2, 2, FEARG_1, &t_void, f_ch_setoptions},
384 {"ch_status", 1, 2, FEARG_1, &t_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200385#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100386 {"changenr", 0, 0, 0, &t_number, f_changenr},
387 {"char2nr", 1, 2, FEARG_1, &t_number, f_char2nr},
388 {"chdir", 1, 1, FEARG_1, &t_string, f_chdir},
389 {"cindent", 1, 1, FEARG_1, &t_number, f_cindent},
390 {"clearmatches", 0, 1, FEARG_1, &t_void, f_clearmatches},
391 {"col", 1, 1, FEARG_1, &t_number, f_col},
392 {"complete", 2, 2, FEARG_2, &t_void, f_complete},
393 {"complete_add", 1, 1, FEARG_1, &t_number, f_complete_add},
394 {"complete_check", 0, 0, 0, &t_number, f_complete_check},
395 {"complete_info", 0, 1, FEARG_1, &t_dict_any, f_complete_info},
396 {"confirm", 1, 4, FEARG_1, &t_number, f_confirm},
397 {"copy", 1, 1, FEARG_1, &t_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200398#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100399 {"cos", 1, 1, FEARG_1, &t_float, f_cos},
400 {"cosh", 1, 1, FEARG_1, &t_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200401#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100402 {"count", 2, 4, FEARG_1, &t_number, f_count},
403 {"cscope_connection",0,3, 0, &t_number, f_cscope_connection},
404 {"cursor", 1, 3, FEARG_1, &t_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100405#ifdef MSWIN
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100406 {"debugbreak", 1, 1, FEARG_1, &t_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200407#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100408 {"deepcopy", 1, 2, FEARG_1, &t_any, f_deepcopy},
409 {"delete", 1, 2, FEARG_1, &t_number, f_delete},
410 {"deletebufline", 2, 3, FEARG_1, &t_number, f_deletebufline},
411 {"did_filetype", 0, 0, 0, &t_number, f_did_filetype},
412 {"diff_filler", 1, 1, FEARG_1, &t_number, f_diff_filler},
413 {"diff_hlID", 2, 2, FEARG_1, &t_number, f_diff_hlID},
414 {"empty", 1, 1, FEARG_1, &t_number, f_empty},
415 {"environ", 0, 0, 0, &t_dict_string, f_environ},
416 {"escape", 2, 2, FEARG_1, &t_string, f_escape},
417 {"eval", 1, 1, FEARG_1, &t_any, f_eval},
418 {"eventhandler", 0, 0, 0, &t_number, f_eventhandler},
419 {"executable", 1, 1, FEARG_1, &t_number, f_executable},
420 {"execute", 1, 2, FEARG_1, &t_string, f_execute},
421 {"exepath", 1, 1, FEARG_1, &t_string, f_exepath},
422 {"exists", 1, 1, FEARG_1, &t_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200423#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100424 {"exp", 1, 1, FEARG_1, &t_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200425#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100426 {"expand", 1, 3, FEARG_1, &t_any, f_expand},
427 {"expandcmd", 1, 1, FEARG_1, &t_string, f_expandcmd},
428 {"extend", 2, 3, FEARG_1, &t_any, f_extend},
429 {"feedkeys", 1, 2, FEARG_1, &t_void, f_feedkeys},
430 {"file_readable", 1, 1, FEARG_1, &t_number, f_filereadable}, // obsolete
431 {"filereadable", 1, 1, FEARG_1, &t_number, f_filereadable},
432 {"filewritable", 1, 1, FEARG_1, &t_number, f_filewritable},
433 {"filter", 2, 2, FEARG_1, &t_any, f_filter},
434 {"finddir", 1, 3, FEARG_1, &t_string, f_finddir},
435 {"findfile", 1, 3, FEARG_1, &t_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100437 {"float2nr", 1, 1, FEARG_1, &t_number, f_float2nr},
438 {"floor", 1, 1, FEARG_1, &t_float, f_floor},
439 {"fmod", 2, 2, FEARG_1, &t_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200440#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100441 {"fnameescape", 1, 1, FEARG_1, &t_string, f_fnameescape},
442 {"fnamemodify", 2, 2, FEARG_1, &t_string, f_fnamemodify},
443 {"foldclosed", 1, 1, FEARG_1, &t_number, f_foldclosed},
444 {"foldclosedend", 1, 1, FEARG_1, &t_number, f_foldclosedend},
445 {"foldlevel", 1, 1, FEARG_1, &t_number, f_foldlevel},
446 {"foldtext", 0, 0, 0, &t_string, f_foldtext},
447 {"foldtextresult", 1, 1, FEARG_1, &t_string, f_foldtextresult},
448 {"foreground", 0, 0, 0, &t_void, f_foreground},
449 {"funcref", 1, 3, FEARG_1, &t_any, f_funcref},
450 {"function", 1, 3, FEARG_1, &t_any, f_function},
451 {"garbagecollect", 0, 1, 0, &t_void, f_garbagecollect},
452 {"get", 2, 3, FEARG_1, &t_any, f_get},
453 {"getbufinfo", 0, 1, 0, &t_list_dict_any, f_getbufinfo},
454 {"getbufline", 2, 3, FEARG_1, &t_list_string, f_getbufline},
455 {"getbufvar", 2, 3, FEARG_1, &t_any, f_getbufvar},
456 {"getchangelist", 0, 1, FEARG_1, &t_list_any, f_getchangelist},
457 {"getchar", 0, 1, 0, &t_number, f_getchar},
458 {"getcharmod", 0, 0, 0, &t_number, f_getcharmod},
459 {"getcharsearch", 0, 0, 0, &t_dict_any, f_getcharsearch},
460 {"getcmdline", 0, 0, 0, &t_string, f_getcmdline},
461 {"getcmdpos", 0, 0, 0, &t_number, f_getcmdpos},
462 {"getcmdtype", 0, 0, 0, &t_string, f_getcmdtype},
463 {"getcmdwintype", 0, 0, 0, &t_string, f_getcmdwintype},
464 {"getcompletion", 2, 3, FEARG_1, &t_list_string, f_getcompletion},
465 {"getcurpos", 0, 0, 0, &t_list_number, f_getcurpos},
466 {"getcwd", 0, 2, FEARG_1, &t_string, f_getcwd},
467 {"getenv", 1, 1, FEARG_1, &t_string, f_getenv},
468 {"getfontname", 0, 1, 0, &t_string, f_getfontname},
469 {"getfperm", 1, 1, FEARG_1, &t_string, f_getfperm},
470 {"getfsize", 1, 1, FEARG_1, &t_number, f_getfsize},
471 {"getftime", 1, 1, FEARG_1, &t_number, f_getftime},
472 {"getftype", 1, 1, FEARG_1, &t_string, f_getftype},
473 {"getimstatus", 0, 0, 0, &t_number, f_getimstatus},
474 {"getjumplist", 0, 2, FEARG_1, &t_list_any, f_getjumplist},
475 {"getline", 1, 2, FEARG_1, &t_string, f_getline},
476 {"getloclist", 1, 2, 0, &t_list_dict_any, f_getloclist},
477 {"getmatches", 0, 1, 0, &t_list_dict_any, f_getmatches},
478 {"getmousepos", 0, 0, 0, &t_dict_number, f_getmousepos},
479 {"getpid", 0, 0, 0, &t_number, f_getpid},
480 {"getpos", 1, 1, FEARG_1, &t_list_number, f_getpos},
481 {"getqflist", 0, 1, 0, &t_list_dict_any, f_getqflist},
482 {"getreg", 0, 3, FEARG_1, &t_string, f_getreg},
483 {"getregtype", 0, 1, FEARG_1, &t_string, f_getregtype},
484 {"gettabinfo", 0, 1, FEARG_1, &t_list_dict_any, f_gettabinfo},
485 {"gettabvar", 2, 3, FEARG_1, &t_any, f_gettabvar},
486 {"gettabwinvar", 3, 4, FEARG_1, &t_any, f_gettabwinvar},
487 {"gettagstack", 0, 1, FEARG_1, &t_dict_any, f_gettagstack},
488 {"getwininfo", 0, 1, FEARG_1, &t_list_dict_any, f_getwininfo},
489 {"getwinpos", 0, 1, FEARG_1, &t_list_number, f_getwinpos},
490 {"getwinposx", 0, 0, 0, &t_number, f_getwinposx},
491 {"getwinposy", 0, 0, 0, &t_number, f_getwinposy},
492 {"getwinvar", 2, 3, FEARG_1, &t_any, f_getwinvar},
493 {"glob", 1, 4, FEARG_1, &t_any, f_glob},
494 {"glob2regpat", 1, 1, FEARG_1, &t_string, f_glob2regpat},
495 {"globpath", 2, 5, FEARG_2, &t_any, f_globpath},
496 {"has", 1, 1, 0, &t_number, f_has},
497 {"has_key", 2, 2, FEARG_1, &t_number, f_has_key},
498 {"haslocaldir", 0, 2, FEARG_1, &t_number, f_haslocaldir},
499 {"hasmapto", 1, 3, FEARG_1, &t_number, f_hasmapto},
500 {"highlightID", 1, 1, FEARG_1, &t_number, f_hlID}, // obsolete
501 {"highlight_exists",1, 1, FEARG_1, &t_number, f_hlexists}, // obsolete
502 {"histadd", 2, 2, FEARG_2, &t_number, f_histadd},
503 {"histdel", 1, 2, FEARG_1, &t_number, f_histdel},
504 {"histget", 1, 2, FEARG_1, &t_string, f_histget},
505 {"histnr", 1, 1, FEARG_1, &t_number, f_histnr},
506 {"hlID", 1, 1, FEARG_1, &t_number, f_hlID},
507 {"hlexists", 1, 1, FEARG_1, &t_number, f_hlexists},
508 {"hostname", 0, 0, 0, &t_string, f_hostname},
509 {"iconv", 3, 3, FEARG_1, &t_string, f_iconv},
510 {"indent", 1, 1, FEARG_1, &t_number, f_indent},
511 {"index", 2, 4, FEARG_1, &t_number, f_index},
512 {"input", 1, 3, FEARG_1, &t_string, f_input},
513 {"inputdialog", 1, 3, FEARG_1, &t_string, f_inputdialog},
514 {"inputlist", 1, 1, FEARG_1, &t_number, f_inputlist},
515 {"inputrestore", 0, 0, 0, &t_number, f_inputrestore},
516 {"inputsave", 0, 0, 0, &t_number, f_inputsave},
517 {"inputsecret", 1, 2, FEARG_1, &t_string, f_inputsecret},
518 {"insert", 2, 3, FEARG_1, &t_any, f_insert},
519 {"interrupt", 0, 0, 0, &t_void, f_interrupt},
520 {"invert", 1, 1, FEARG_1, &t_number, f_invert},
521 {"isdirectory", 1, 1, FEARG_1, &t_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200522#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100523 {"isinf", 1, 1, FEARG_1, &t_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200524#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100525 {"islocked", 1, 1, FEARG_1, &t_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100527 {"isnan", 1, 1, FEARG_1, &t_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100529 {"items", 1, 1, FEARG_1, &t_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200530#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100531 {"job_getchannel", 1, 1, FEARG_1, &t_channel, f_job_getchannel},
532 {"job_info", 0, 1, FEARG_1, &t_dict_any, f_job_info},
533 {"job_setoptions", 2, 2, FEARG_1, &t_void, f_job_setoptions},
534 {"job_start", 1, 2, FEARG_1, &t_job, f_job_start},
535 {"job_status", 1, 1, FEARG_1, &t_string, f_job_status},
536 {"job_stop", 1, 2, FEARG_1, &t_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100538 {"join", 1, 2, FEARG_1, &t_string, f_join},
539 {"js_decode", 1, 1, FEARG_1, &t_any, f_js_decode},
540 {"js_encode", 1, 1, FEARG_1, &t_string, f_js_encode},
541 {"json_decode", 1, 1, FEARG_1, &t_any, f_json_decode},
542 {"json_encode", 1, 1, FEARG_1, &t_string, f_json_encode},
543 {"keys", 1, 1, FEARG_1, &t_list_any, f_keys},
544 {"last_buffer_nr", 0, 0, 0, &t_number, f_last_buffer_nr}, // obsolete
545 {"len", 1, 1, FEARG_1, &t_number, f_len},
546 {"libcall", 3, 3, FEARG_3, &t_string, f_libcall},
547 {"libcallnr", 3, 3, FEARG_3, &t_number, f_libcallnr},
548 {"line", 1, 2, FEARG_1, &t_number, f_line},
549 {"line2byte", 1, 1, FEARG_1, &t_number, f_line2byte},
550 {"lispindent", 1, 1, FEARG_1, &t_number, f_lispindent},
551 {"list2str", 1, 2, FEARG_1, &t_string, f_list2str},
552 {"listener_add", 1, 2, FEARG_2, &t_number, f_listener_add},
553 {"listener_flush", 0, 1, FEARG_1, &t_void, f_listener_flush},
554 {"listener_remove", 1, 1, FEARG_1, &t_number, f_listener_remove},
555 {"localtime", 0, 0, 0, &t_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200556#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100557 {"log", 1, 1, FEARG_1, &t_float, f_log},
558 {"log10", 1, 1, FEARG_1, &t_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200559#endif
560#ifdef FEAT_LUA
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100561 {"luaeval", 1, 2, FEARG_1, &t_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200562#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100563 {"map", 2, 2, FEARG_1, &t_any, f_map},
564 {"maparg", 1, 4, FEARG_1, &t_string, f_maparg},
565 {"mapcheck", 1, 3, FEARG_1, &t_string, f_mapcheck},
566 {"match", 2, 4, FEARG_1, &t_any, f_match},
567 {"matchadd", 2, 5, FEARG_1, &t_number, f_matchadd},
568 {"matchaddpos", 2, 5, FEARG_1, &t_number, f_matchaddpos},
569 {"matcharg", 1, 1, FEARG_1, &t_list_string, f_matcharg},
570 {"matchdelete", 1, 2, FEARG_1, &t_number, f_matchdelete},
571 {"matchend", 2, 4, FEARG_1, &t_number, f_matchend},
572 {"matchlist", 2, 4, FEARG_1, &t_list_any, f_matchlist},
573 {"matchstr", 2, 4, FEARG_1, &t_string, f_matchstr},
574 {"matchstrpos", 2, 4, FEARG_1, &t_list_any, f_matchstrpos},
575 {"max", 1, 1, FEARG_1, &t_any, f_max},
576 {"min", 1, 1, FEARG_1, &t_any, f_min},
577 {"mkdir", 1, 3, FEARG_1, &t_number, f_mkdir},
578 {"mode", 0, 1, FEARG_1, &t_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200579#ifdef FEAT_MZSCHEME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100580 {"mzeval", 1, 1, FEARG_1, &t_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200581#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100582 {"nextnonblank", 1, 1, FEARG_1, &t_number, f_nextnonblank},
583 {"nr2char", 1, 2, FEARG_1, &t_string, f_nr2char},
584 {"or", 2, 2, FEARG_1, &t_number, f_or},
585 {"pathshorten", 1, 1, FEARG_1, &t_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200586#ifdef FEAT_PERL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100587 {"perleval", 1, 1, FEARG_1, &t_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200588#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100589#ifdef FEAT_PROP_POPUP
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100590 {"popup_atcursor", 2, 2, FEARG_1, &t_number, f_popup_atcursor},
591 {"popup_beval", 2, 2, FEARG_1, &t_number, f_popup_beval},
592 {"popup_clear", 0, 0, 0, &t_void, f_popup_clear},
593 {"popup_close", 1, 2, FEARG_1, &t_void, f_popup_close},
594 {"popup_create", 2, 2, FEARG_1, &t_number, f_popup_create},
595 {"popup_dialog", 2, 2, FEARG_1, &t_number, f_popup_dialog},
596 {"popup_filter_menu", 2, 2, 0, &t_number, f_popup_filter_menu},
597 {"popup_filter_yesno", 2, 2, 0, &t_number, f_popup_filter_yesno},
598 {"popup_findinfo", 0, 0, 0, &t_number, f_popup_findinfo},
599 {"popup_findpreview", 0, 0, 0, &t_number, f_popup_findpreview},
600 {"popup_getoptions", 1, 1, FEARG_1, &t_dict_any, f_popup_getoptions},
601 {"popup_getpos", 1, 1, FEARG_1, &t_dict_any, f_popup_getpos},
602 {"popup_hide", 1, 1, FEARG_1, &t_void, f_popup_hide},
603 {"popup_locate", 2, 2, 0, &t_number, f_popup_locate},
604 {"popup_menu", 2, 2, FEARG_1, &t_number, f_popup_menu},
605 {"popup_move", 2, 2, FEARG_1, &t_void, f_popup_move},
606 {"popup_notification", 2, 2, FEARG_1, &t_number, f_popup_notification},
607 {"popup_setoptions", 2, 2, FEARG_1, &t_void, f_popup_setoptions},
608 {"popup_settext", 2, 2, FEARG_1, &t_void, f_popup_settext},
609 {"popup_show", 1, 1, FEARG_1, &t_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200610#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200611#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100612 {"pow", 2, 2, FEARG_1, &t_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200613#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100614 {"prevnonblank", 1, 1, FEARG_1, &t_number, f_prevnonblank},
615 {"printf", 1, 19, FEARG_2, &t_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200616#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100617 {"prompt_setcallback", 2, 2, FEARG_1, &t_void, f_prompt_setcallback},
618 {"prompt_setinterrupt", 2, 2, FEARG_1,&t_void, f_prompt_setinterrupt},
619 {"prompt_setprompt", 2, 2, FEARG_1, &t_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200620#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100621#ifdef FEAT_PROP_POPUP
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100622 {"prop_add", 3, 3, FEARG_1, &t_void, f_prop_add},
623 {"prop_clear", 1, 3, FEARG_1, &t_void, f_prop_clear},
624 {"prop_find", 1, 2, FEARG_1, &t_dict_any, f_prop_find},
625 {"prop_list", 1, 2, FEARG_1, &t_list_any, f_prop_list},
626 {"prop_remove", 1, 3, FEARG_1, &t_number, f_prop_remove},
627 {"prop_type_add", 2, 2, FEARG_1, &t_void, f_prop_type_add},
628 {"prop_type_change", 2, 2, FEARG_1, &t_void, f_prop_type_change},
629 {"prop_type_delete", 1, 2, FEARG_1, &t_void, f_prop_type_delete},
630 {"prop_type_get", 1, 2, FEARG_1, &t_dict_any, f_prop_type_get},
631 {"prop_type_list", 0, 1, FEARG_1, &t_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100632#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100633 {"pum_getpos", 0, 0, 0, &t_dict_number, f_pum_getpos},
634 {"pumvisible", 0, 0, 0, &t_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#ifdef FEAT_PYTHON3
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100636 {"py3eval", 1, 1, FEARG_1, &t_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637#endif
638#ifdef FEAT_PYTHON
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100639 {"pyeval", 1, 1, FEARG_1, &t_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100641#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100642 {"pyxeval", 1, 1, FEARG_1, &t_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100643#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100644 {"rand", 0, 1, FEARG_1, &t_number, f_rand},
645 {"range", 1, 3, FEARG_1, &t_list_number, f_range},
646 {"readdir", 1, 2, FEARG_1, &t_list_string, f_readdir},
647 {"readfile", 1, 3, FEARG_1, &t_any, f_readfile},
648 {"reg_executing", 0, 0, 0, &t_string, f_reg_executing},
649 {"reg_recording", 0, 0, 0, &t_string, f_reg_recording},
650 {"reltime", 0, 2, FEARG_1, &t_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200651#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100652 {"reltimefloat", 1, 1, FEARG_1, &t_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100654 {"reltimestr", 1, 1, FEARG_1, &t_string, f_reltimestr},
655 {"remote_expr", 2, 4, FEARG_1, &t_string, f_remote_expr},
656 {"remote_foreground", 1, 1, FEARG_1, &t_string, f_remote_foreground},
657 {"remote_peek", 1, 2, FEARG_1, &t_number, f_remote_peek},
658 {"remote_read", 1, 2, FEARG_1, &t_string, f_remote_read},
659 {"remote_send", 2, 3, FEARG_1, &t_string, f_remote_send},
660 {"remote_startserver", 1, 1, FEARG_1, &t_void, f_remote_startserver},
661 {"remove", 2, 3, FEARG_1, &t_any, f_remove},
662 {"rename", 2, 2, FEARG_1, &t_number, f_rename},
663 {"repeat", 2, 2, FEARG_1, &t_any, f_repeat},
664 {"resolve", 1, 1, FEARG_1, &t_string, f_resolve},
665 {"reverse", 1, 1, FEARG_1, &t_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100667 {"round", 1, 1, FEARG_1, &t_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200668#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100669#ifdef FEAT_RUBY
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100670 {"rubyeval", 1, 1, FEARG_1, &t_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100671#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100672 {"screenattr", 2, 2, FEARG_1, &t_number, f_screenattr},
673 {"screenchar", 2, 2, FEARG_1, &t_number, f_screenchar},
674 {"screenchars", 2, 2, FEARG_1, &t_list_number, f_screenchars},
675 {"screencol", 0, 0, 0, &t_number, f_screencol},
676 {"screenpos", 3, 3, FEARG_1, &t_dict_number, f_screenpos},
677 {"screenrow", 0, 0, 0, &t_number, f_screenrow},
678 {"screenstring", 2, 2, FEARG_1, &t_string, f_screenstring},
679 {"search", 1, 4, FEARG_1, &t_number, f_search},
680 {"searchdecl", 1, 3, FEARG_1, &t_number, f_searchdecl},
681 {"searchpair", 3, 7, 0, &t_number, f_searchpair},
682 {"searchpairpos", 3, 7, 0, &t_list_number, f_searchpairpos},
683 {"searchpos", 1, 4, FEARG_1, &t_list_number, f_searchpos},
684 {"server2client", 2, 2, FEARG_1, &t_number, f_server2client},
685 {"serverlist", 0, 0, 0, &t_string, f_serverlist},
686 {"setbufline", 3, 3, FEARG_3, &t_number, f_setbufline},
687 {"setbufvar", 3, 3, FEARG_3, &t_void, f_setbufvar},
688 {"setcharsearch", 1, 1, FEARG_1, &t_void, f_setcharsearch},
689 {"setcmdpos", 1, 1, FEARG_1, &t_number, f_setcmdpos},
690 {"setenv", 2, 2, FEARG_2, &t_void, f_setenv},
691 {"setfperm", 2, 2, FEARG_1, &t_number, f_setfperm},
692 {"setline", 2, 2, FEARG_2, &t_number, f_setline},
693 {"setloclist", 2, 4, FEARG_2, &t_number, f_setloclist},
694 {"setmatches", 1, 2, FEARG_1, &t_number, f_setmatches},
695 {"setpos", 2, 2, FEARG_2, &t_number, f_setpos},
696 {"setqflist", 1, 3, FEARG_1, &t_number, f_setqflist},
697 {"setreg", 2, 3, FEARG_2, &t_number, f_setreg},
698 {"settabvar", 3, 3, FEARG_3, &t_void, f_settabvar},
699 {"settabwinvar", 4, 4, FEARG_4, &t_void, f_settabwinvar},
700 {"settagstack", 2, 3, FEARG_2, &t_number, f_settagstack},
701 {"setwinvar", 3, 3, FEARG_3, &t_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200702#ifdef FEAT_CRYPT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100703 {"sha256", 1, 1, FEARG_1, &t_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200704#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100705 {"shellescape", 1, 2, FEARG_1, &t_string, f_shellescape},
706 {"shiftwidth", 0, 1, FEARG_1, &t_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100707#ifdef FEAT_SIGNS
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100708 {"sign_define", 1, 2, FEARG_1, &t_any, f_sign_define},
709 {"sign_getdefined", 0, 1, FEARG_1, &t_list_dict_any, f_sign_getdefined},
710 {"sign_getplaced", 0, 2, FEARG_1, &t_list_dict_any, f_sign_getplaced},
711 {"sign_jump", 3, 3, FEARG_1, &t_number, f_sign_jump},
712 {"sign_place", 4, 5, FEARG_1, &t_number, f_sign_place},
713 {"sign_placelist", 1, 1, FEARG_1, &t_list_number, f_sign_placelist},
714 {"sign_undefine", 0, 1, FEARG_1, &t_number, f_sign_undefine},
715 {"sign_unplace", 1, 2, FEARG_1, &t_number, f_sign_unplace},
716 {"sign_unplacelist", 1, 2, FEARG_1, &t_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100717#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100718 {"simplify", 1, 1, 0, &t_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200719#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100720 {"sin", 1, 1, FEARG_1, &t_float, f_sin},
721 {"sinh", 1, 1, FEARG_1, &t_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200722#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100723 {"sort", 1, 3, FEARG_1, &t_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200724#ifdef FEAT_SOUND
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100725 {"sound_clear", 0, 0, 0, &t_void, f_sound_clear},
726 {"sound_playevent", 1, 2, FEARG_1, &t_number, f_sound_playevent},
727 {"sound_playfile", 1, 2, FEARG_1, &t_number, f_sound_playfile},
728 {"sound_stop", 1, 1, FEARG_1, &t_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200729#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100730 {"soundfold", 1, 1, FEARG_1, &t_string, f_soundfold},
731 {"spellbadword", 0, 1, FEARG_1, &t_list_string, f_spellbadword},
732 {"spellsuggest", 1, 3, FEARG_1, &t_list_string, f_spellsuggest},
733 {"split", 1, 3, FEARG_1, &t_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200734#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100735 {"sqrt", 1, 1, FEARG_1, &t_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200736#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100737 {"srand", 0, 1, FEARG_1, &t_list_number, f_srand},
738 {"state", 0, 1, FEARG_1, &t_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200739#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100740 {"str2float", 1, 1, FEARG_1, &t_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200741#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100742 {"str2list", 1, 2, FEARG_1, &t_list_number, f_str2list},
743 {"str2nr", 1, 3, FEARG_1, &t_number, f_str2nr},
744 {"strcharpart", 2, 3, FEARG_1, &t_string, f_strcharpart},
745 {"strchars", 1, 2, FEARG_1, &t_number, f_strchars},
746 {"strdisplaywidth", 1, 2, FEARG_1, &t_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200747#ifdef HAVE_STRFTIME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100748 {"strftime", 1, 2, FEARG_1, &t_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200749#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100750 {"strgetchar", 2, 2, FEARG_1, &t_number, f_strgetchar},
751 {"stridx", 2, 3, FEARG_1, &t_number, f_stridx},
752 {"string", 1, 1, FEARG_1, &t_string, f_string},
753 {"strlen", 1, 1, FEARG_1, &t_number, f_strlen},
754 {"strpart", 2, 3, FEARG_1, &t_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100755#ifdef HAVE_STRPTIME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100756 {"strptime", 2, 2, FEARG_1, &t_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100757#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100758 {"strridx", 2, 3, FEARG_1, &t_number, f_strridx},
759 {"strtrans", 1, 1, FEARG_1, &t_string, f_strtrans},
760 {"strwidth", 1, 1, FEARG_1, &t_number, f_strwidth},
761 {"submatch", 1, 2, FEARG_1, &t_string, f_submatch},
762 {"substitute", 4, 4, FEARG_1, &t_string, f_substitute},
763 {"swapinfo", 1, 1, FEARG_1, &t_dict_any, f_swapinfo},
764 {"swapname", 1, 1, FEARG_1, &t_string, f_swapname},
765 {"synID", 3, 3, 0, &t_number, f_synID},
766 {"synIDattr", 2, 3, FEARG_1, &t_string, f_synIDattr},
767 {"synIDtrans", 1, 1, FEARG_1, &t_number, f_synIDtrans},
768 {"synconcealed", 2, 2, 0, &t_list_any, f_synconcealed},
769 {"synstack", 2, 2, 0, &t_list_number, f_synstack},
770 {"system", 1, 2, FEARG_1, &t_string, f_system},
771 {"systemlist", 1, 2, FEARG_1, &t_list_string, f_systemlist},
772 {"tabpagebuflist", 0, 1, FEARG_1, &t_list_number, f_tabpagebuflist},
773 {"tabpagenr", 0, 1, 0, &t_number, f_tabpagenr},
774 {"tabpagewinnr", 1, 2, FEARG_1, &t_number, f_tabpagewinnr},
775 {"tagfiles", 0, 0, 0, &t_list_string, f_tagfiles},
776 {"taglist", 1, 2, FEARG_1, &t_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100778 {"tan", 1, 1, FEARG_1, &t_float, f_tan},
779 {"tanh", 1, 1, FEARG_1, &t_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200780#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100781 {"tempname", 0, 0, 0, &t_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200782#ifdef FEAT_TERMINAL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100783 {"term_dumpdiff", 2, 3, FEARG_1, &t_number, f_term_dumpdiff},
784 {"term_dumpload", 1, 2, FEARG_1, &t_number, f_term_dumpload},
785 {"term_dumpwrite", 2, 3, FEARG_2, &t_void, f_term_dumpwrite},
786 {"term_getaltscreen", 1, 1, FEARG_1, &t_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200787# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100788 {"term_getansicolors", 1, 1, FEARG_1, &t_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200789# endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100790 {"term_getattr", 2, 2, FEARG_1, &t_number, f_term_getattr},
791 {"term_getcursor", 1, 1, FEARG_1, &t_list_any, f_term_getcursor},
792 {"term_getjob", 1, 1, FEARG_1, &t_job, f_term_getjob},
793 {"term_getline", 2, 2, FEARG_1, &t_string, f_term_getline},
794 {"term_getscrolled", 1, 1, FEARG_1, &t_number, f_term_getscrolled},
795 {"term_getsize", 1, 1, FEARG_1, &t_list_number, f_term_getsize},
796 {"term_getstatus", 1, 1, FEARG_1, &t_string, f_term_getstatus},
797 {"term_gettitle", 1, 1, FEARG_1, &t_string, f_term_gettitle},
798 {"term_gettty", 1, 2, FEARG_1, &t_string, f_term_gettty},
799 {"term_list", 0, 0, 0, &t_list_number, f_term_list},
800 {"term_scrape", 2, 2, FEARG_1, &t_list_dict_any, f_term_scrape},
801 {"term_sendkeys", 2, 2, FEARG_1, &t_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200802# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100803 {"term_setansicolors", 2, 2, FEARG_1, &t_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200804# endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100805 {"term_setapi", 2, 2, FEARG_1, &t_void, f_term_setapi},
806 {"term_setkill", 2, 2, FEARG_1, &t_void, f_term_setkill},
807 {"term_setrestore", 2, 2, FEARG_1, &t_void, f_term_setrestore},
808 {"term_setsize", 3, 3, FEARG_1, &t_void, f_term_setsize},
809 {"term_start", 1, 2, FEARG_1, &t_number, f_term_start},
810 {"term_wait", 1, 2, FEARG_1, &t_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200811#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100812 {"test_alloc_fail", 3, 3, FEARG_1, &t_void, f_test_alloc_fail},
813 {"test_autochdir", 0, 0, 0, &t_void, f_test_autochdir},
Bram Moolenaar07ada5f2020-02-05 20:38:22 +0100814 {"test_clear_search_pat", 0, 0, 0, &t_void, f_test_clear_search_pat},
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100815 {"test_feedinput", 1, 1, FEARG_1, &t_void, f_test_feedinput},
816 {"test_garbagecollect_now", 0, 0, 0, &t_void, f_test_garbagecollect_now},
817 {"test_garbagecollect_soon", 0, 0, 0, &t_void, f_test_garbagecollect_soon},
818 {"test_getvalue", 1, 1, FEARG_1, &t_number, f_test_getvalue},
819 {"test_ignore_error", 1, 1, FEARG_1, &t_void, f_test_ignore_error},
820 {"test_null_blob", 0, 0, 0, &t_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100822 {"test_null_channel", 0, 0, 0, &t_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100824 {"test_null_dict", 0, 0, 0, &t_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100826 {"test_null_job", 0, 0, 0, &t_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100828 {"test_null_list", 0, 0, 0, &t_list_any, f_test_null_list},
829 {"test_null_partial", 0, 0, 0, &t_partial_void, f_test_null_partial},
830 {"test_null_string", 0, 0, 0, &t_string, f_test_null_string},
831 {"test_option_not_set", 1, 1, FEARG_1,&t_void, f_test_option_not_set},
832 {"test_override", 2, 2, FEARG_2, &t_void, f_test_override},
833 {"test_refcount", 1, 1, FEARG_1, &t_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200834#ifdef FEAT_GUI
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100835 {"test_scrollbar", 3, 3, FEARG_2, &t_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200836#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100837 {"test_setmouse", 2, 2, 0, &t_void, f_test_setmouse},
838 {"test_settime", 1, 1, FEARG_1, &t_void, f_test_settime},
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100839 {"test_srand_seed", 0, 1, FEARG_1, &t_void, f_test_srand_seed},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200840#ifdef FEAT_TIMERS
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100841 {"timer_info", 0, 1, FEARG_1, &t_list_dict_any, f_timer_info},
842 {"timer_pause", 2, 2, FEARG_1, &t_void, f_timer_pause},
843 {"timer_start", 2, 3, FEARG_1, &t_number, f_timer_start},
844 {"timer_stop", 1, 1, FEARG_1, &t_void, f_timer_stop},
845 {"timer_stopall", 0, 0, 0, &t_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200846#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100847 {"tolower", 1, 1, FEARG_1, &t_string, f_tolower},
848 {"toupper", 1, 1, FEARG_1, &t_string, f_toupper},
849 {"tr", 3, 3, FEARG_1, &t_string, f_tr},
850 {"trim", 1, 2, FEARG_1, &t_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100852 {"trunc", 1, 1, FEARG_1, &t_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100854 {"type", 1, 1, FEARG_1, &t_number, f_type},
855 {"undofile", 1, 1, FEARG_1, &t_string, f_undofile},
856 {"undotree", 0, 0, 0, &t_dict_any, f_undotree},
857 {"uniq", 1, 3, FEARG_1, &t_list_any, f_uniq},
858 {"values", 1, 1, FEARG_1, &t_list_any, f_values},
859 {"virtcol", 1, 1, FEARG_1, &t_number, f_virtcol},
860 {"visualmode", 0, 1, 0, &t_string, f_visualmode},
861 {"wildmenumode", 0, 0, 0, &t_number, f_wildmenumode},
862 {"win_execute", 2, 3, FEARG_2, &t_string, f_win_execute},
863 {"win_findbuf", 1, 1, FEARG_1, &t_list_number, f_win_findbuf},
864 {"win_getid", 0, 2, FEARG_1, &t_number, f_win_getid},
865 {"win_gotoid", 1, 1, FEARG_1, &t_number, f_win_gotoid},
866 {"win_id2tabwin", 1, 1, FEARG_1, &t_list_number, f_win_id2tabwin},
867 {"win_id2win", 1, 1, FEARG_1, &t_number, f_win_id2win},
868 {"win_screenpos", 1, 1, FEARG_1, &t_list_number, f_win_screenpos},
869 {"win_splitmove", 2, 3, FEARG_1, &t_number, f_win_splitmove},
870 {"winbufnr", 1, 1, FEARG_1, &t_number, f_winbufnr},
871 {"wincol", 0, 0, 0, &t_number, f_wincol},
872 {"windowsversion", 0, 0, 0, &t_string, f_windowsversion},
873 {"winheight", 1, 1, FEARG_1, &t_number, f_winheight},
874 {"winlayout", 0, 1, FEARG_1, &t_list_any, f_winlayout},
875 {"winline", 0, 0, 0, &t_number, f_winline},
876 {"winnr", 0, 1, FEARG_1, &t_number, f_winnr},
877 {"winrestcmd", 0, 0, 0, &t_string, f_winrestcmd},
878 {"winrestview", 1, 1, FEARG_1, &t_void, f_winrestview},
879 {"winsaveview", 0, 0, 0, &t_dict_any, f_winsaveview},
880 {"winwidth", 1, 1, FEARG_1, &t_number, f_winwidth},
881 {"wordcount", 0, 0, 0, &t_dict_number, f_wordcount},
882 {"writefile", 2, 3, FEARG_1, &t_number, f_writefile},
883 {"xor", 2, 2, FEARG_1, &t_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200884};
885
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200886/*
887 * Function given to ExpandGeneric() to obtain the list of internal
888 * or user defined function names.
889 */
890 char_u *
891get_function_name(expand_T *xp, int idx)
892{
893 static int intidx = -1;
894 char_u *name;
895
896 if (idx == 0)
897 intidx = -1;
898 if (intidx < 0)
899 {
900 name = get_user_func_name(xp, idx);
901 if (name != NULL)
902 return name;
903 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200904 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200905 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200906 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200907 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200908 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200909 STRCAT(IObuff, ")");
910 return IObuff;
911 }
912
913 return NULL;
914}
915
916/*
917 * Function given to ExpandGeneric() to obtain the list of internal or
918 * user defined variable or function names.
919 */
920 char_u *
921get_expr_name(expand_T *xp, int idx)
922{
923 static int intidx = -1;
924 char_u *name;
925
926 if (idx == 0)
927 intidx = -1;
928 if (intidx < 0)
929 {
930 name = get_function_name(xp, idx);
931 if (name != NULL)
932 return name;
933 }
934 return get_user_var_name(xp, ++intidx);
935}
936
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200937/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200938 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200939 * Return index, or -1 if not found
940 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100941 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200942find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200943{
944 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200945 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200946 int cmp;
947 int x;
948
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200949 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200950
951 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200952 while (first <= last)
953 {
954 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200955 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200956 if (cmp < 0)
957 last = x - 1;
958 else if (cmp > 0)
959 first = x + 1;
960 else
961 return x;
962 }
963 return -1;
964}
965
966 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200967has_internal_func(char_u *name)
968{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200969 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200970}
971
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100972 char *
973internal_func_name(int idx)
974{
975 return global_functions[idx].f_name;
976}
977
978 type_T *
979internal_func_ret_type(int idx, int argcount)
980{
981 funcentry_T *fe = &global_functions[idx];
982
983 if (fe->f_func == f_getline)
984 return argcount == 1 ? &t_string : &t_list_string;
985 return fe->f_rettype;
986}
987
988/*
989 * Check the argument count to use for internal function "idx".
990 * Returns OK or FAIL;
991 */
992 int
993check_internal_func(int idx, int argcount)
994{
995 int res;
996 char *name;
997
998 if (argcount < global_functions[idx].f_min_argc)
999 res = FCERR_TOOFEW;
1000 else if (argcount > global_functions[idx].f_max_argc)
1001 res = FCERR_TOOMANY;
1002 else
1003 return OK;
1004
1005 name = internal_func_name(idx);
1006 if (res == FCERR_TOOMANY)
1007 semsg(_(e_toomanyarg), name);
1008 else
1009 semsg(_(e_toofewarg), name);
1010 return FAIL;
1011}
1012
Bram Moolenaarac92e252019-08-03 21:58:38 +02001013 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001014call_internal_func(
1015 char_u *name,
1016 int argcount,
1017 typval_T *argvars,
1018 typval_T *rettv)
1019{
1020 int i;
1021
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001022 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001023 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001024 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001025 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001026 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001027 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001028 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001029 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001030 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001031 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001032}
1033
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001034 void
1035call_internal_func_by_idx(
1036 int idx,
1037 typval_T *argvars,
1038 typval_T *rettv)
1039{
1040 global_functions[idx].f_func(argvars, rettv);
1041}
1042
Bram Moolenaarac92e252019-08-03 21:58:38 +02001043/*
1044 * Invoke a method for base->method().
1045 */
1046 int
1047call_internal_method(
1048 char_u *name,
1049 int argcount,
1050 typval_T *argvars,
1051 typval_T *rettv,
1052 typval_T *basetv)
1053{
1054 int i;
1055 int fi;
1056 typval_T argv[MAX_FUNC_ARGS + 1];
1057
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001058 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001059 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001060 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001061 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001062 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001063 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001064 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001065 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001066 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001067
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001068 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001069 {
1070 // base value goes last
1071 for (i = 0; i < argcount; ++i)
1072 argv[i] = argvars[i];
1073 argv[argcount] = *basetv;
1074 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001075 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001076 {
1077 // base value goes second
1078 argv[0] = argvars[0];
1079 argv[1] = *basetv;
1080 for (i = 1; i < argcount; ++i)
1081 argv[i + 1] = argvars[i];
1082 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001083 else if (global_functions[fi].f_argtype == FEARG_3)
1084 {
1085 // base value goes third
1086 argv[0] = argvars[0];
1087 argv[1] = argvars[1];
1088 argv[2] = *basetv;
1089 for (i = 2; i < argcount; ++i)
1090 argv[i + 1] = argvars[i];
1091 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001092 else if (global_functions[fi].f_argtype == FEARG_4)
1093 {
1094 // base value goes fourth
1095 argv[0] = argvars[0];
1096 argv[1] = argvars[1];
1097 argv[2] = argvars[2];
1098 argv[3] = *basetv;
1099 for (i = 3; i < argcount; ++i)
1100 argv[i + 1] = argvars[i];
1101 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001102 else
1103 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001104 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001105 argv[0] = *basetv;
1106 for (i = 0; i < argcount; ++i)
1107 argv[i + 1] = argvars[i];
1108 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001109 argv[argcount + 1].v_type = VAR_UNKNOWN;
1110
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001111 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001112 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001113}
1114
1115/*
1116 * Return TRUE for a non-zero Number and a non-empty String.
1117 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001118 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001119non_zero_arg(typval_T *argvars)
1120{
1121 return ((argvars[0].v_type == VAR_NUMBER
1122 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001123 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001124 && argvars[0].vval.v_number == VVAL_TRUE)
1125 || (argvars[0].v_type == VAR_STRING
1126 && argvars[0].vval.v_string != NULL
1127 && *argvars[0].vval.v_string != NUL));
1128}
1129
1130/*
1131 * Get the lnum from the first argument.
1132 * Also accepts ".", "$", etc., but that only works for the current buffer.
1133 * Returns -1 on error.
1134 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001135 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001136tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001137{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001138 linenr_T lnum;
1139
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001140 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001141 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001142 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001143 int fnum;
1144 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1145
1146 if (fp != NULL)
1147 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001148 }
1149 return lnum;
1150}
1151
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001152/*
1153 * Get the lnum from the first argument.
1154 * Also accepts "$", then "buf" is used.
1155 * Returns 0 on error.
1156 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001157 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001158tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1159{
1160 if (argvars[0].v_type == VAR_STRING
1161 && argvars[0].vval.v_string != NULL
1162 && argvars[0].vval.v_string[0] == '$'
1163 && buf != NULL)
1164 return buf->b_ml.ml_line_count;
1165 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1166}
1167
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001168#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001169/*
1170 * Get the float value of "argvars[0]" into "f".
1171 * Returns FAIL when the argument is not a Number or Float.
1172 */
1173 static int
1174get_float_arg(typval_T *argvars, float_T *f)
1175{
1176 if (argvars[0].v_type == VAR_FLOAT)
1177 {
1178 *f = argvars[0].vval.v_float;
1179 return OK;
1180 }
1181 if (argvars[0].v_type == VAR_NUMBER)
1182 {
1183 *f = (float_T)argvars[0].vval.v_number;
1184 return OK;
1185 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001186 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001187 return FAIL;
1188}
1189
1190/*
1191 * "abs(expr)" function
1192 */
1193 static void
1194f_abs(typval_T *argvars, typval_T *rettv)
1195{
1196 if (argvars[0].v_type == VAR_FLOAT)
1197 {
1198 rettv->v_type = VAR_FLOAT;
1199 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1200 }
1201 else
1202 {
1203 varnumber_T n;
1204 int error = FALSE;
1205
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001206 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001207 if (error)
1208 rettv->vval.v_number = -1;
1209 else if (n > 0)
1210 rettv->vval.v_number = n;
1211 else
1212 rettv->vval.v_number = -n;
1213 }
1214}
1215
1216/*
1217 * "acos()" function
1218 */
1219 static void
1220f_acos(typval_T *argvars, typval_T *rettv)
1221{
1222 float_T f = 0.0;
1223
1224 rettv->v_type = VAR_FLOAT;
1225 if (get_float_arg(argvars, &f) == OK)
1226 rettv->vval.v_float = acos(f);
1227 else
1228 rettv->vval.v_float = 0.0;
1229}
1230#endif
1231
1232/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001233 * "and(expr, expr)" function
1234 */
1235 static void
1236f_and(typval_T *argvars, typval_T *rettv)
1237{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001238 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1239 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001240}
1241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001242#ifdef FEAT_FLOAT
1243/*
1244 * "asin()" function
1245 */
1246 static void
1247f_asin(typval_T *argvars, typval_T *rettv)
1248{
1249 float_T f = 0.0;
1250
1251 rettv->v_type = VAR_FLOAT;
1252 if (get_float_arg(argvars, &f) == OK)
1253 rettv->vval.v_float = asin(f);
1254 else
1255 rettv->vval.v_float = 0.0;
1256}
1257
1258/*
1259 * "atan()" function
1260 */
1261 static void
1262f_atan(typval_T *argvars, typval_T *rettv)
1263{
1264 float_T f = 0.0;
1265
1266 rettv->v_type = VAR_FLOAT;
1267 if (get_float_arg(argvars, &f) == OK)
1268 rettv->vval.v_float = atan(f);
1269 else
1270 rettv->vval.v_float = 0.0;
1271}
1272
1273/*
1274 * "atan2()" function
1275 */
1276 static void
1277f_atan2(typval_T *argvars, typval_T *rettv)
1278{
1279 float_T fx = 0.0, fy = 0.0;
1280
1281 rettv->v_type = VAR_FLOAT;
1282 if (get_float_arg(argvars, &fx) == OK
1283 && get_float_arg(&argvars[1], &fy) == OK)
1284 rettv->vval.v_float = atan2(fx, fy);
1285 else
1286 rettv->vval.v_float = 0.0;
1287}
1288#endif
1289
1290/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001291 * "balloon_show()" function
1292 */
1293#ifdef FEAT_BEVAL
1294 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001295f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1296{
1297 rettv->v_type = VAR_STRING;
1298 if (balloonEval != NULL)
1299 {
1300 if (balloonEval->msg == NULL)
1301 rettv->vval.v_string = NULL;
1302 else
1303 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1304 }
1305}
1306
1307 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001308f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1309{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001310 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001311 {
1312 if (argvars[0].v_type == VAR_LIST
1313# ifdef FEAT_GUI
1314 && !gui.in_use
1315# endif
1316 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001317 {
1318 list_T *l = argvars[0].vval.v_list;
1319
1320 // empty list removes the balloon
1321 post_balloon(balloonEval, NULL,
1322 l == NULL || l->lv_len == 0 ? NULL : l);
1323 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001324 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001325 {
1326 char_u *mesg = tv_get_string_chk(&argvars[0]);
1327
1328 if (mesg != NULL)
1329 // empty string removes the balloon
1330 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1331 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001332 }
1333}
1334
Bram Moolenaar669a8282017-11-19 20:13:05 +01001335# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001336 static void
1337f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1338{
1339 if (rettv_list_alloc(rettv) == OK)
1340 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001341 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001342
1343 if (msg != NULL)
1344 {
1345 pumitem_T *array;
1346 int size = split_message(msg, &array);
1347 int i;
1348
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001349 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001350 for (i = 1; i < size - 1; ++i)
1351 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001352 while (size > 0)
1353 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001354 vim_free(array);
1355 }
1356 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001357}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001358# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001359#endif
1360
1361/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 * Get buffer by number or pattern.
1363 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001364 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001365tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001366{
1367 char_u *name = tv->vval.v_string;
1368 buf_T *buf;
1369
1370 if (tv->v_type == VAR_NUMBER)
1371 return buflist_findnr((int)tv->vval.v_number);
1372 if (tv->v_type != VAR_STRING)
1373 return NULL;
1374 if (name == NULL || *name == NUL)
1375 return curbuf;
1376 if (name[0] == '$' && name[1] == NUL)
1377 return lastbuf;
1378
1379 buf = buflist_find_by_name(name, curtab_only);
1380
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001381 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382 if (buf == NULL)
1383 buf = find_buffer(tv);
1384
1385 return buf;
1386}
1387
1388/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001389 * Get the buffer from "arg" and give an error and return NULL if it is not
1390 * valid.
1391 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001392 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001393get_buf_arg(typval_T *arg)
1394{
1395 buf_T *buf;
1396
1397 ++emsg_off;
1398 buf = tv_get_buf(arg, FALSE);
1399 --emsg_off;
1400 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001401 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001402 return buf;
1403}
1404
1405/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001406 * "byte2line(byte)" function
1407 */
1408 static void
1409f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1410{
1411#ifndef FEAT_BYTEOFF
1412 rettv->vval.v_number = -1;
1413#else
1414 long boff = 0;
1415
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001416 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001417 if (boff < 0)
1418 rettv->vval.v_number = -1;
1419 else
1420 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1421 (linenr_T)0, &boff);
1422#endif
1423}
1424
1425 static void
1426byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1427{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001428 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001429 char_u *str;
1430 varnumber_T idx;
1431
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001432 str = tv_get_string_chk(&argvars[0]);
1433 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434 rettv->vval.v_number = -1;
1435 if (str == NULL || idx < 0)
1436 return;
1437
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001438 t = str;
1439 for ( ; idx > 0; idx--)
1440 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001441 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001442 return;
1443 if (enc_utf8 && comp)
1444 t += utf_ptr2len(t);
1445 else
1446 t += (*mb_ptr2len)(t);
1447 }
1448 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001449}
1450
1451/*
1452 * "byteidx()" function
1453 */
1454 static void
1455f_byteidx(typval_T *argvars, typval_T *rettv)
1456{
1457 byteidx(argvars, rettv, FALSE);
1458}
1459
1460/*
1461 * "byteidxcomp()" function
1462 */
1463 static void
1464f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1465{
1466 byteidx(argvars, rettv, TRUE);
1467}
1468
1469/*
1470 * "call(func, arglist [, dict])" function
1471 */
1472 static void
1473f_call(typval_T *argvars, typval_T *rettv)
1474{
1475 char_u *func;
1476 partial_T *partial = NULL;
1477 dict_T *selfdict = NULL;
1478
1479 if (argvars[1].v_type != VAR_LIST)
1480 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001481 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001482 return;
1483 }
1484 if (argvars[1].vval.v_list == NULL)
1485 return;
1486
1487 if (argvars[0].v_type == VAR_FUNC)
1488 func = argvars[0].vval.v_string;
1489 else if (argvars[0].v_type == VAR_PARTIAL)
1490 {
1491 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001492 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001493 }
1494 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001495 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001496 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001497 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001498
1499 if (argvars[2].v_type != VAR_UNKNOWN)
1500 {
1501 if (argvars[2].v_type != VAR_DICT)
1502 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001503 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001504 return;
1505 }
1506 selfdict = argvars[2].vval.v_dict;
1507 }
1508
1509 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1510}
1511
1512#ifdef FEAT_FLOAT
1513/*
1514 * "ceil({float})" function
1515 */
1516 static void
1517f_ceil(typval_T *argvars, typval_T *rettv)
1518{
1519 float_T f = 0.0;
1520
1521 rettv->v_type = VAR_FLOAT;
1522 if (get_float_arg(argvars, &f) == OK)
1523 rettv->vval.v_float = ceil(f);
1524 else
1525 rettv->vval.v_float = 0.0;
1526}
1527#endif
1528
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001529/*
1530 * "changenr()" function
1531 */
1532 static void
1533f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1534{
1535 rettv->vval.v_number = curbuf->b_u_seq_cur;
1536}
1537
1538/*
1539 * "char2nr(string)" function
1540 */
1541 static void
1542f_char2nr(typval_T *argvars, typval_T *rettv)
1543{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001544 if (has_mbyte)
1545 {
1546 int utf8 = 0;
1547
1548 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001549 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001550
1551 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001552 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001553 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001554 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001555 }
1556 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001557 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001558}
1559
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001560 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001561get_optional_window(typval_T *argvars, int idx)
1562{
1563 win_T *win = curwin;
1564
1565 if (argvars[idx].v_type != VAR_UNKNOWN)
1566 {
1567 win = find_win_by_nr_or_id(&argvars[idx]);
1568 if (win == NULL)
1569 {
1570 emsg(_(e_invalwindow));
1571 return NULL;
1572 }
1573 }
1574 return win;
1575}
1576
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001577/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578 * "col(string)" function
1579 */
1580 static void
1581f_col(typval_T *argvars, typval_T *rettv)
1582{
1583 colnr_T col = 0;
1584 pos_T *fp;
1585 int fnum = curbuf->b_fnum;
1586
1587 fp = var2fpos(&argvars[0], FALSE, &fnum);
1588 if (fp != NULL && fnum == curbuf->b_fnum)
1589 {
1590 if (fp->col == MAXCOL)
1591 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001592 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001593 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1594 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1595 else
1596 col = MAXCOL;
1597 }
1598 else
1599 {
1600 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001601 // col(".") when the cursor is on the NUL at the end of the line
1602 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001603 if (virtual_active() && fp == &curwin->w_cursor)
1604 {
1605 char_u *p = ml_get_cursor();
1606
1607 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1608 curwin->w_virtcol - curwin->w_cursor.coladd))
1609 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001610 int l;
1611
1612 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1613 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001614 }
1615 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616 }
1617 }
1618 rettv->vval.v_number = col;
1619}
1620
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001621/*
1622 * "confirm(message, buttons[, default [, type]])" function
1623 */
1624 static void
1625f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1626{
1627#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1628 char_u *message;
1629 char_u *buttons = NULL;
1630 char_u buf[NUMBUFLEN];
1631 char_u buf2[NUMBUFLEN];
1632 int def = 1;
1633 int type = VIM_GENERIC;
1634 char_u *typestr;
1635 int error = FALSE;
1636
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001637 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001638 if (message == NULL)
1639 error = TRUE;
1640 if (argvars[1].v_type != VAR_UNKNOWN)
1641 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001642 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001643 if (buttons == NULL)
1644 error = TRUE;
1645 if (argvars[2].v_type != VAR_UNKNOWN)
1646 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001647 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648 if (argvars[3].v_type != VAR_UNKNOWN)
1649 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001650 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651 if (typestr == NULL)
1652 error = TRUE;
1653 else
1654 {
1655 switch (TOUPPER_ASC(*typestr))
1656 {
1657 case 'E': type = VIM_ERROR; break;
1658 case 'Q': type = VIM_QUESTION; break;
1659 case 'I': type = VIM_INFO; break;
1660 case 'W': type = VIM_WARNING; break;
1661 case 'G': type = VIM_GENERIC; break;
1662 }
1663 }
1664 }
1665 }
1666 }
1667
1668 if (buttons == NULL || *buttons == NUL)
1669 buttons = (char_u *)_("&Ok");
1670
1671 if (!error)
1672 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1673 def, NULL, FALSE);
1674#endif
1675}
1676
1677/*
1678 * "copy()" function
1679 */
1680 static void
1681f_copy(typval_T *argvars, typval_T *rettv)
1682{
1683 item_copy(&argvars[0], rettv, FALSE, 0);
1684}
1685
1686#ifdef FEAT_FLOAT
1687/*
1688 * "cos()" function
1689 */
1690 static void
1691f_cos(typval_T *argvars, typval_T *rettv)
1692{
1693 float_T f = 0.0;
1694
1695 rettv->v_type = VAR_FLOAT;
1696 if (get_float_arg(argvars, &f) == OK)
1697 rettv->vval.v_float = cos(f);
1698 else
1699 rettv->vval.v_float = 0.0;
1700}
1701
1702/*
1703 * "cosh()" function
1704 */
1705 static void
1706f_cosh(typval_T *argvars, typval_T *rettv)
1707{
1708 float_T f = 0.0;
1709
1710 rettv->v_type = VAR_FLOAT;
1711 if (get_float_arg(argvars, &f) == OK)
1712 rettv->vval.v_float = cosh(f);
1713 else
1714 rettv->vval.v_float = 0.0;
1715}
1716#endif
1717
1718/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001719 * "cursor(lnum, col)" function, or
1720 * "cursor(list)"
1721 *
1722 * Moves the cursor to the specified line and column.
1723 * Returns 0 when the position could be set, -1 otherwise.
1724 */
1725 static void
1726f_cursor(typval_T *argvars, typval_T *rettv)
1727{
1728 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001729 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001730 int set_curswant = TRUE;
1731
1732 rettv->vval.v_number = -1;
1733 if (argvars[1].v_type == VAR_UNKNOWN)
1734 {
1735 pos_T pos;
1736 colnr_T curswant = -1;
1737
1738 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1739 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001740 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001741 return;
1742 }
1743 line = pos.lnum;
1744 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001745 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001746 if (curswant >= 0)
1747 {
1748 curwin->w_curswant = curswant - 1;
1749 set_curswant = FALSE;
1750 }
1751 }
1752 else
1753 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001754 line = tv_get_lnum(argvars);
1755 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001756 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001757 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001758 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001759 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001760 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001761 if (line > 0)
1762 curwin->w_cursor.lnum = line;
1763 if (col > 0)
1764 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001765 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001766
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001767 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001768 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001769 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001770 if (has_mbyte)
1771 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001772
1773 curwin->w_set_curswant = set_curswant;
1774 rettv->vval.v_number = 0;
1775}
1776
Bram Moolenaar4f974752019-02-17 17:44:42 +01001777#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001778/*
1779 * "debugbreak()" function
1780 */
1781 static void
1782f_debugbreak(typval_T *argvars, typval_T *rettv)
1783{
1784 int pid;
1785
1786 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001787 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001788 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001789 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001790 else
1791 {
1792 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1793
1794 if (hProcess != NULL)
1795 {
1796 DebugBreakProcess(hProcess);
1797 CloseHandle(hProcess);
1798 rettv->vval.v_number = OK;
1799 }
1800 }
1801}
1802#endif
1803
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001804/*
1805 * "deepcopy()" function
1806 */
1807 static void
1808f_deepcopy(typval_T *argvars, typval_T *rettv)
1809{
1810 int noref = 0;
1811 int copyID;
1812
1813 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001814 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001815 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001816 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001817 else
1818 {
1819 copyID = get_copyID();
1820 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1821 }
1822}
1823
1824/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001825 * "did_filetype()" function
1826 */
1827 static void
1828f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1829{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001831}
1832
1833/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001834 * "empty({expr})" function
1835 */
1836 static void
1837f_empty(typval_T *argvars, typval_T *rettv)
1838{
1839 int n = FALSE;
1840
1841 switch (argvars[0].v_type)
1842 {
1843 case VAR_STRING:
1844 case VAR_FUNC:
1845 n = argvars[0].vval.v_string == NULL
1846 || *argvars[0].vval.v_string == NUL;
1847 break;
1848 case VAR_PARTIAL:
1849 n = FALSE;
1850 break;
1851 case VAR_NUMBER:
1852 n = argvars[0].vval.v_number == 0;
1853 break;
1854 case VAR_FLOAT:
1855#ifdef FEAT_FLOAT
1856 n = argvars[0].vval.v_float == 0.0;
1857 break;
1858#endif
1859 case VAR_LIST:
1860 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001861 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001862 break;
1863 case VAR_DICT:
1864 n = argvars[0].vval.v_dict == NULL
1865 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1866 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001867 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001868 case VAR_SPECIAL:
1869 n = argvars[0].vval.v_number != VVAL_TRUE;
1870 break;
1871
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001872 case VAR_BLOB:
1873 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001874 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1875 break;
1876
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001877 case VAR_JOB:
1878#ifdef FEAT_JOB_CHANNEL
1879 n = argvars[0].vval.v_job == NULL
1880 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1881 break;
1882#endif
1883 case VAR_CHANNEL:
1884#ifdef FEAT_JOB_CHANNEL
1885 n = argvars[0].vval.v_channel == NULL
1886 || !channel_is_open(argvars[0].vval.v_channel);
1887 break;
1888#endif
1889 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001890 case VAR_VOID:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001891 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001892 n = TRUE;
1893 break;
1894 }
1895
1896 rettv->vval.v_number = n;
1897}
1898
1899/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001900 * "environ()" function
1901 */
1902 static void
1903f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1904{
1905#if !defined(AMIGA)
1906 int i = 0;
1907 char_u *entry, *value;
1908# ifdef MSWIN
1909 extern wchar_t **_wenviron;
1910# else
1911 extern char **environ;
1912# endif
1913
1914 if (rettv_dict_alloc(rettv) != OK)
1915 return;
1916
1917# ifdef MSWIN
1918 if (*_wenviron == NULL)
1919 return;
1920# else
1921 if (*environ == NULL)
1922 return;
1923# endif
1924
1925 for (i = 0; ; ++i)
1926 {
1927# ifdef MSWIN
1928 short_u *p;
1929
1930 if ((p = (short_u *)_wenviron[i]) == NULL)
1931 return;
1932 entry = utf16_to_enc(p, NULL);
1933# else
1934 if ((entry = (char_u *)environ[i]) == NULL)
1935 return;
1936 entry = vim_strsave(entry);
1937# endif
1938 if (entry == NULL) // out of memory
1939 return;
1940 if ((value = vim_strchr(entry, '=')) == NULL)
1941 {
1942 vim_free(entry);
1943 continue;
1944 }
1945 *value++ = NUL;
1946 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1947 vim_free(entry);
1948 }
1949#endif
1950}
1951
1952/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001953 * "escape({string}, {chars})" function
1954 */
1955 static void
1956f_escape(typval_T *argvars, typval_T *rettv)
1957{
1958 char_u buf[NUMBUFLEN];
1959
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001960 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1961 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001962 rettv->v_type = VAR_STRING;
1963}
1964
1965/*
1966 * "eval()" function
1967 */
1968 static void
1969f_eval(typval_T *argvars, typval_T *rettv)
1970{
1971 char_u *s, *p;
1972
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001973 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001974 if (s != NULL)
1975 s = skipwhite(s);
1976
1977 p = s;
1978 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1979 {
1980 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001981 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001982 need_clr_eos = FALSE;
1983 rettv->v_type = VAR_NUMBER;
1984 rettv->vval.v_number = 0;
1985 }
1986 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001987 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001988}
1989
1990/*
1991 * "eventhandler()" function
1992 */
1993 static void
1994f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1995{
1996 rettv->vval.v_number = vgetc_busy;
1997}
1998
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001999static garray_T redir_execute_ga;
2000
2001/*
2002 * Append "value[value_len]" to the execute() output.
2003 */
2004 void
2005execute_redir_str(char_u *value, int value_len)
2006{
2007 int len;
2008
2009 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002010 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002011 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002012 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013 if (ga_grow(&redir_execute_ga, len) == OK)
2014 {
2015 mch_memmove((char *)redir_execute_ga.ga_data
2016 + redir_execute_ga.ga_len, value, len);
2017 redir_execute_ga.ga_len += len;
2018 }
2019}
2020
2021/*
2022 * Get next line from a list.
2023 * Called by do_cmdline() to get the next line.
2024 * Returns allocated string, or NULL for end of function.
2025 */
2026
2027 static char_u *
2028get_list_line(
2029 int c UNUSED,
2030 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002031 int indent UNUSED,
2032 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002033{
2034 listitem_T **p = (listitem_T **)cookie;
2035 listitem_T *item = *p;
2036 char_u buf[NUMBUFLEN];
2037 char_u *s;
2038
2039 if (item == NULL)
2040 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002041 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002042 *p = item->li_next;
2043 return s == NULL ? NULL : vim_strsave(s);
2044}
2045
2046/*
2047 * "execute()" function
2048 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002049 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002050execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002051{
2052 char_u *cmd = NULL;
2053 list_T *list = NULL;
2054 int save_msg_silent = msg_silent;
2055 int save_emsg_silent = emsg_silent;
2056 int save_emsg_noredir = emsg_noredir;
2057 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002058 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002059 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002060 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002061 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002062
2063 rettv->vval.v_string = NULL;
2064 rettv->v_type = VAR_STRING;
2065
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002066 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002067 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002068 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002069 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002070 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002071 return;
2072 ++list->lv_refcount;
2073 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002074 else if (argvars[arg_off].v_type == VAR_JOB
2075 || argvars[arg_off].v_type == VAR_CHANNEL)
2076 {
2077 emsg(_(e_inval_string));
2078 return;
2079 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002080 else
2081 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002082 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002083 if (cmd == NULL)
2084 return;
2085 }
2086
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002087 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088 {
2089 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002090 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002091
2092 if (s == NULL)
2093 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002094 if (*s == NUL)
2095 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002096 if (STRNCMP(s, "silent", 6) == 0)
2097 ++msg_silent;
2098 if (STRCMP(s, "silent!") == 0)
2099 {
2100 emsg_silent = TRUE;
2101 emsg_noredir = TRUE;
2102 }
2103 }
2104 else
2105 ++msg_silent;
2106
2107 if (redir_execute)
2108 save_ga = redir_execute_ga;
2109 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2110 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002111 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002112 if (!echo_output)
2113 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002114
2115 if (cmd != NULL)
2116 do_cmdline_cmd(cmd);
2117 else
2118 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002119 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002121 range_list_materialize(list);
2122 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002123 do_cmdline(NULL, get_list_line, (void *)&item,
2124 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2125 --list->lv_refcount;
2126 }
2127
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002128 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002129 if (ga_grow(&redir_execute_ga, 1) == OK)
2130 {
2131 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2132 rettv->vval.v_string = redir_execute_ga.ga_data;
2133 }
2134 else
2135 {
2136 ga_clear(&redir_execute_ga);
2137 rettv->vval.v_string = NULL;
2138 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002139 msg_silent = save_msg_silent;
2140 emsg_silent = save_emsg_silent;
2141 emsg_noredir = save_emsg_noredir;
2142
2143 redir_execute = save_redir_execute;
2144 if (redir_execute)
2145 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002146 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002148 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002149 if (echo_output)
2150 // When not working silently: put it in column zero. A following
2151 // "echon" will overwrite the message, unavoidably.
2152 msg_col = 0;
2153 else
2154 // When working silently: Put it back where it was, since nothing
2155 // should have been written.
2156 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002157}
2158
2159/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002160 * "execute()" function
2161 */
2162 static void
2163f_execute(typval_T *argvars, typval_T *rettv)
2164{
2165 execute_common(argvars, rettv, 0);
2166}
2167
2168/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002169 * "exists()" function
2170 */
2171 static void
2172f_exists(typval_T *argvars, typval_T *rettv)
2173{
2174 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002177 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002178 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002179 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002180 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002181 if (mch_getenv(p + 1) != NULL)
2182 n = TRUE;
2183 else
2184 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002185 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002186 p = expand_env_save(p);
2187 if (p != NULL && *p != '$')
2188 n = TRUE;
2189 vim_free(p);
2190 }
2191 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002192 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002193 {
2194 n = (get_option_tv(&p, NULL, TRUE) == OK);
2195 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002196 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002197 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002198 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002199 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002200 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002201 }
2202 else if (*p == ':')
2203 {
2204 n = cmd_exists(p + 1);
2205 }
2206 else if (*p == '#')
2207 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002208 if (p[1] == '#')
2209 n = autocmd_supported(p + 2);
2210 else
2211 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002212 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002213 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002214 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002215 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002216 }
2217
2218 rettv->vval.v_number = n;
2219}
2220
2221#ifdef FEAT_FLOAT
2222/*
2223 * "exp()" function
2224 */
2225 static void
2226f_exp(typval_T *argvars, typval_T *rettv)
2227{
2228 float_T f = 0.0;
2229
2230 rettv->v_type = VAR_FLOAT;
2231 if (get_float_arg(argvars, &f) == OK)
2232 rettv->vval.v_float = exp(f);
2233 else
2234 rettv->vval.v_float = 0.0;
2235}
2236#endif
2237
2238/*
2239 * "expand()" function
2240 */
2241 static void
2242f_expand(typval_T *argvars, typval_T *rettv)
2243{
2244 char_u *s;
2245 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002246 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002247 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2248 expand_T xpc;
2249 int error = FALSE;
2250 char_u *result;
2251
2252 rettv->v_type = VAR_STRING;
2253 if (argvars[1].v_type != VAR_UNKNOWN
2254 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002255 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002257 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002258
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002259 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002260 if (*s == '%' || *s == '#' || *s == '<')
2261 {
2262 ++emsg_off;
2263 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2264 --emsg_off;
2265 if (rettv->v_type == VAR_LIST)
2266 {
2267 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2268 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002269 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002270 }
2271 else
2272 rettv->vval.v_string = result;
2273 }
2274 else
2275 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002276 // When the optional second argument is non-zero, don't remove matches
2277 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002278 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002279 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 options |= WILD_KEEP_ALL;
2281 if (!error)
2282 {
2283 ExpandInit(&xpc);
2284 xpc.xp_context = EXPAND_FILES;
2285 if (p_wic)
2286 options += WILD_ICASE;
2287 if (rettv->v_type == VAR_STRING)
2288 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2289 options, WILD_ALL);
2290 else if (rettv_list_alloc(rettv) != FAIL)
2291 {
2292 int i;
2293
2294 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2295 for (i = 0; i < xpc.xp_numfiles; i++)
2296 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2297 ExpandCleanup(&xpc);
2298 }
2299 }
2300 else
2301 rettv->vval.v_string = NULL;
2302 }
2303}
2304
2305/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002306 * "expandcmd()" function
2307 * Expand all the special characters in a command string.
2308 */
2309 static void
2310f_expandcmd(typval_T *argvars, typval_T *rettv)
2311{
2312 exarg_T eap;
2313 char_u *cmdstr;
2314 char *errormsg = NULL;
2315
2316 rettv->v_type = VAR_STRING;
2317 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2318
2319 memset(&eap, 0, sizeof(eap));
2320 eap.cmd = cmdstr;
2321 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002322 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002323 eap.usefilter = FALSE;
2324 eap.nextcmd = NULL;
2325 eap.cmdidx = CMD_USER;
2326
2327 expand_filename(&eap, &cmdstr, &errormsg);
2328 if (errormsg != NULL && *errormsg != NUL)
2329 emsg(errormsg);
2330
2331 rettv->vval.v_string = cmdstr;
2332}
2333
2334/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002335 * "feedkeys()" function
2336 */
2337 static void
2338f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2339{
2340 int remap = TRUE;
2341 int insert = FALSE;
2342 char_u *keys, *flags;
2343 char_u nbuf[NUMBUFLEN];
2344 int typed = FALSE;
2345 int execute = FALSE;
2346 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002347 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002348 char_u *keys_esc;
2349
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002350 // This is not allowed in the sandbox. If the commands would still be
2351 // executed in the sandbox it would be OK, but it probably happens later,
2352 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353 if (check_secure())
2354 return;
2355
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002356 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002357
2358 if (argvars[1].v_type != VAR_UNKNOWN)
2359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002360 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002361 for ( ; *flags != NUL; ++flags)
2362 {
2363 switch (*flags)
2364 {
2365 case 'n': remap = FALSE; break;
2366 case 'm': remap = TRUE; break;
2367 case 't': typed = TRUE; break;
2368 case 'i': insert = TRUE; break;
2369 case 'x': execute = TRUE; break;
2370 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002371 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002372 }
2373 }
2374 }
2375
2376 if (*keys != NUL || execute)
2377 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002378 // Need to escape K_SPECIAL and CSI before putting the string in the
2379 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002380 keys_esc = vim_strsave_escape_csi(keys);
2381 if (keys_esc != NULL)
2382 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002383 if (lowlevel)
2384 {
2385#ifdef USE_INPUT_BUF
2386 add_to_input_buf(keys, (int)STRLEN(keys));
2387#else
2388 emsg(_("E980: lowlevel input not supported"));
2389#endif
2390 }
2391 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002392 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002393 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002394 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002395 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002396#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002397 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002398#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002399 )
2400 typebuf_was_filled = TRUE;
2401 }
2402 vim_free(keys_esc);
2403
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002404 if (execute)
2405 {
2406 int save_msg_scroll = msg_scroll;
2407
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002408 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002409 msg_scroll = FALSE;
2410
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002411 if (!dangerous)
2412 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002413 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002414 if (!dangerous)
2415 --ex_normal_busy;
2416
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002417 msg_scroll |= save_msg_scroll;
2418 }
2419 }
2420 }
2421}
2422
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002423#ifdef FEAT_FLOAT
2424/*
2425 * "float2nr({float})" function
2426 */
2427 static void
2428f_float2nr(typval_T *argvars, typval_T *rettv)
2429{
2430 float_T f = 0.0;
2431
2432 if (get_float_arg(argvars, &f) == OK)
2433 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002434 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002435 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002436 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002437 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002438 else
2439 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440 }
2441}
2442
2443/*
2444 * "floor({float})" function
2445 */
2446 static void
2447f_floor(typval_T *argvars, typval_T *rettv)
2448{
2449 float_T f = 0.0;
2450
2451 rettv->v_type = VAR_FLOAT;
2452 if (get_float_arg(argvars, &f) == OK)
2453 rettv->vval.v_float = floor(f);
2454 else
2455 rettv->vval.v_float = 0.0;
2456}
2457
2458/*
2459 * "fmod()" function
2460 */
2461 static void
2462f_fmod(typval_T *argvars, typval_T *rettv)
2463{
2464 float_T fx = 0.0, fy = 0.0;
2465
2466 rettv->v_type = VAR_FLOAT;
2467 if (get_float_arg(argvars, &fx) == OK
2468 && get_float_arg(&argvars[1], &fy) == OK)
2469 rettv->vval.v_float = fmod(fx, fy);
2470 else
2471 rettv->vval.v_float = 0.0;
2472}
2473#endif
2474
2475/*
2476 * "fnameescape({string})" function
2477 */
2478 static void
2479f_fnameescape(typval_T *argvars, typval_T *rettv)
2480{
2481 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002482 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002483 rettv->v_type = VAR_STRING;
2484}
2485
2486/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002487 * "foreground()" function
2488 */
2489 static void
2490f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2491{
2492#ifdef FEAT_GUI
2493 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002494 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002495 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002496 return;
2497 }
2498#endif
2499#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002500 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002501#endif
2502}
2503
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002504 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002505common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002506{
2507 char_u *s;
2508 char_u *name;
2509 int use_string = FALSE;
2510 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002511 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002512
2513 if (argvars[0].v_type == VAR_FUNC)
2514 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002515 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002516 s = argvars[0].vval.v_string;
2517 }
2518 else if (argvars[0].v_type == VAR_PARTIAL
2519 && argvars[0].vval.v_partial != NULL)
2520 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002521 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002522 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002523 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002524 }
2525 else
2526 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002527 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002528 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002529 use_string = TRUE;
2530 }
2531
Bram Moolenaar843b8842016-08-21 14:36:15 +02002532 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002533 {
2534 name = s;
2535 trans_name = trans_function_name(&name, FALSE,
2536 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2537 if (*name != NUL)
2538 s = NULL;
2539 }
2540
Bram Moolenaar843b8842016-08-21 14:36:15 +02002541 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2542 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002543 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002544 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002545 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002546 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002547 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002548 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002549 else
2550 {
2551 int dict_idx = 0;
2552 int arg_idx = 0;
2553 list_T *list = NULL;
2554
2555 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2556 {
2557 char sid_buf[25];
2558 int off = *s == 's' ? 2 : 5;
2559
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002560 // Expand s: and <SID> into <SNR>nr_, so that the function can
2561 // also be called from another script. Using trans_function_name()
2562 // would also work, but some plugins depend on the name being
2563 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002564 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002565 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002566 if (name != NULL)
2567 {
2568 STRCPY(name, sid_buf);
2569 STRCAT(name, s + off);
2570 }
2571 }
2572 else
2573 name = vim_strsave(s);
2574
2575 if (argvars[1].v_type != VAR_UNKNOWN)
2576 {
2577 if (argvars[2].v_type != VAR_UNKNOWN)
2578 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002579 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002580 arg_idx = 1;
2581 dict_idx = 2;
2582 }
2583 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002584 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002585 dict_idx = 1;
2586 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002587 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002588 arg_idx = 1;
2589 if (dict_idx > 0)
2590 {
2591 if (argvars[dict_idx].v_type != VAR_DICT)
2592 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002593 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002595 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002596 }
2597 if (argvars[dict_idx].vval.v_dict == NULL)
2598 dict_idx = 0;
2599 }
2600 if (arg_idx > 0)
2601 {
2602 if (argvars[arg_idx].v_type != VAR_LIST)
2603 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002604 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002605 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002606 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002607 }
2608 list = argvars[arg_idx].vval.v_list;
2609 if (list == NULL || list->lv_len == 0)
2610 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002611 else if (list->lv_len > MAX_FUNC_ARGS)
2612 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002613 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002614 vim_free(name);
2615 goto theend;
2616 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002617 }
2618 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002619 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002621 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002622
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002623 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002624 if (pt == NULL)
2625 vim_free(name);
2626 else
2627 {
2628 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2629 {
2630 listitem_T *li;
2631 int i = 0;
2632 int arg_len = 0;
2633 int lv_len = 0;
2634
2635 if (arg_pt != NULL)
2636 arg_len = arg_pt->pt_argc;
2637 if (list != NULL)
2638 lv_len = list->lv_len;
2639 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002640 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002641 if (pt->pt_argv == NULL)
2642 {
2643 vim_free(pt);
2644 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002645 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002646 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002647 for (i = 0; i < arg_len; i++)
2648 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2649 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002650 {
2651 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002652 for (li = list->lv_first; li != NULL;
2653 li = li->li_next)
2654 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002655 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 }
2657
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002658 // For "function(dict.func, [], dict)" and "func" is a partial
2659 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002660 if (dict_idx > 0)
2661 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002662 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002663 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2664 ++pt->pt_dict->dv_refcount;
2665 }
2666 else if (arg_pt != NULL)
2667 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002668 // If the dict was bound automatically the result is also
2669 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002670 pt->pt_dict = arg_pt->pt_dict;
2671 pt->pt_auto = arg_pt->pt_auto;
2672 if (pt->pt_dict != NULL)
2673 ++pt->pt_dict->dv_refcount;
2674 }
2675
2676 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002677 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2678 {
2679 pt->pt_func = arg_pt->pt_func;
2680 func_ptr_ref(pt->pt_func);
2681 vim_free(name);
2682 }
2683 else if (is_funcref)
2684 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002685 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002686 func_ptr_ref(pt->pt_func);
2687 vim_free(name);
2688 }
2689 else
2690 {
2691 pt->pt_name = name;
2692 func_ref(name);
2693 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002694 }
2695 rettv->v_type = VAR_PARTIAL;
2696 rettv->vval.v_partial = pt;
2697 }
2698 else
2699 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002700 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002701 rettv->v_type = VAR_FUNC;
2702 rettv->vval.v_string = name;
2703 func_ref(name);
2704 }
2705 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002706theend:
2707 vim_free(trans_name);
2708}
2709
2710/*
2711 * "funcref()" function
2712 */
2713 static void
2714f_funcref(typval_T *argvars, typval_T *rettv)
2715{
2716 common_function(argvars, rettv, TRUE);
2717}
2718
2719/*
2720 * "function()" function
2721 */
2722 static void
2723f_function(typval_T *argvars, typval_T *rettv)
2724{
2725 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002726}
2727
2728/*
2729 * "garbagecollect()" function
2730 */
2731 static void
2732f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2733{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002734 // This is postponed until we are back at the toplevel, because we may be
2735 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002736 want_garbage_collect = TRUE;
2737
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002738 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002739 garbage_collect_at_exit = TRUE;
2740}
2741
2742/*
2743 * "get()" function
2744 */
2745 static void
2746f_get(typval_T *argvars, typval_T *rettv)
2747{
2748 listitem_T *li;
2749 list_T *l;
2750 dictitem_T *di;
2751 dict_T *d;
2752 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002753 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002754
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002755 if (argvars[0].v_type == VAR_BLOB)
2756 {
2757 int error = FALSE;
2758 int idx = tv_get_number_chk(&argvars[1], &error);
2759
2760 if (!error)
2761 {
2762 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002763 if (idx < 0)
2764 idx = blob_len(argvars[0].vval.v_blob) + idx;
2765 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2766 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002767 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002768 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002769 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002770 tv = rettv;
2771 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002772 }
2773 }
2774 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002775 {
2776 if ((l = argvars[0].vval.v_list) != NULL)
2777 {
2778 int error = FALSE;
2779
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002780 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002781 if (!error && li != NULL)
2782 tv = &li->li_tv;
2783 }
2784 }
2785 else if (argvars[0].v_type == VAR_DICT)
2786 {
2787 if ((d = argvars[0].vval.v_dict) != NULL)
2788 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002789 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002790 if (di != NULL)
2791 tv = &di->di_tv;
2792 }
2793 }
2794 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2795 {
2796 partial_T *pt;
2797 partial_T fref_pt;
2798
2799 if (argvars[0].v_type == VAR_PARTIAL)
2800 pt = argvars[0].vval.v_partial;
2801 else
2802 {
2803 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2804 fref_pt.pt_name = argvars[0].vval.v_string;
2805 pt = &fref_pt;
2806 }
2807
2808 if (pt != NULL)
2809 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002810 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002811 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002812
2813 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2814 {
2815 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002816 n = partial_name(pt);
2817 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002818 rettv->vval.v_string = NULL;
2819 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002820 {
2821 rettv->vval.v_string = vim_strsave(n);
2822 if (rettv->v_type == VAR_FUNC)
2823 func_ref(rettv->vval.v_string);
2824 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002825 }
2826 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002827 {
2828 what_is_dict = TRUE;
2829 if (pt->pt_dict != NULL)
2830 rettv_dict_set(rettv, pt->pt_dict);
2831 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002832 else if (STRCMP(what, "args") == 0)
2833 {
2834 rettv->v_type = VAR_LIST;
2835 if (rettv_list_alloc(rettv) == OK)
2836 {
2837 int i;
2838
2839 for (i = 0; i < pt->pt_argc; ++i)
2840 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2841 }
2842 }
2843 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002844 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002845
2846 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2847 // third argument
2848 if (!what_is_dict)
2849 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002850 }
2851 }
2852 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002853 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002854
2855 if (tv == NULL)
2856 {
2857 if (argvars[2].v_type != VAR_UNKNOWN)
2858 copy_tv(&argvars[2], rettv);
2859 }
2860 else
2861 copy_tv(tv, rettv);
2862}
2863
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002864/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002865 * "getchangelist()" function
2866 */
2867 static void
2868f_getchangelist(typval_T *argvars, typval_T *rettv)
2869{
2870#ifdef FEAT_JUMPLIST
2871 buf_T *buf;
2872 int i;
2873 list_T *l;
2874 dict_T *d;
2875#endif
2876
2877 if (rettv_list_alloc(rettv) != OK)
2878 return;
2879
2880#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002881 if (argvars[0].v_type == VAR_UNKNOWN)
2882 buf = curbuf;
2883 else
2884 {
2885 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2886 ++emsg_off;
2887 buf = tv_get_buf(&argvars[0], FALSE);
2888 --emsg_off;
2889 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002890 if (buf == NULL)
2891 return;
2892
2893 l = list_alloc();
2894 if (l == NULL)
2895 return;
2896
2897 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2898 return;
2899 /*
2900 * The current window change list index tracks only the position in the
2901 * current buffer change list. For other buffers, use the change list
2902 * length as the current index.
2903 */
2904 list_append_number(rettv->vval.v_list,
2905 (varnumber_T)((buf == curwin->w_buffer)
2906 ? curwin->w_changelistidx : buf->b_changelistlen));
2907
2908 for (i = 0; i < buf->b_changelistlen; ++i)
2909 {
2910 if (buf->b_changelist[i].lnum == 0)
2911 continue;
2912 if ((d = dict_alloc()) == NULL)
2913 return;
2914 if (list_append_dict(l, d) == FAIL)
2915 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002916 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2917 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002918 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002919 }
2920#endif
2921}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002922
2923/*
2924 * "getcharsearch()" function
2925 */
2926 static void
2927f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2928{
2929 if (rettv_dict_alloc(rettv) != FAIL)
2930 {
2931 dict_T *dict = rettv->vval.v_dict;
2932
Bram Moolenaare0be1672018-07-08 16:50:37 +02002933 dict_add_string(dict, "char", last_csearch());
2934 dict_add_number(dict, "forward", last_csearch_forward());
2935 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002936 }
2937}
2938
2939/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940 * "getcmdwintype()" function
2941 */
2942 static void
2943f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2944{
2945 rettv->v_type = VAR_STRING;
2946 rettv->vval.v_string = NULL;
2947#ifdef FEAT_CMDWIN
2948 rettv->vval.v_string = alloc(2);
2949 if (rettv->vval.v_string != NULL)
2950 {
2951 rettv->vval.v_string[0] = cmdwin_type;
2952 rettv->vval.v_string[1] = NUL;
2953 }
2954#endif
2955}
2956
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002957/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002958 * "getenv()" function
2959 */
2960 static void
2961f_getenv(typval_T *argvars, typval_T *rettv)
2962{
2963 int mustfree = FALSE;
2964 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2965
2966 if (p == NULL)
2967 {
2968 rettv->v_type = VAR_SPECIAL;
2969 rettv->vval.v_number = VVAL_NULL;
2970 return;
2971 }
2972 if (!mustfree)
2973 p = vim_strsave(p);
2974 rettv->vval.v_string = p;
2975 rettv->v_type = VAR_STRING;
2976}
2977
2978/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002979 * "getfontname()" function
2980 */
2981 static void
2982f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2983{
2984 rettv->v_type = VAR_STRING;
2985 rettv->vval.v_string = NULL;
2986#ifdef FEAT_GUI
2987 if (gui.in_use)
2988 {
2989 GuiFont font;
2990 char_u *name = NULL;
2991
2992 if (argvars[0].v_type == VAR_UNKNOWN)
2993 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002994 // Get the "Normal" font. Either the name saved by
2995 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002996 font = gui.norm_font;
2997 name = hl_get_font_name();
2998 }
2999 else
3000 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003001 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003002 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003003 return;
3004 font = gui_mch_get_font(name, FALSE);
3005 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003006 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003007 }
3008 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3009 if (argvars[0].v_type != VAR_UNKNOWN)
3010 gui_mch_free_font(font);
3011 }
3012#endif
3013}
3014
3015/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003016 * "getjumplist()" function
3017 */
3018 static void
3019f_getjumplist(typval_T *argvars, typval_T *rettv)
3020{
3021#ifdef FEAT_JUMPLIST
3022 win_T *wp;
3023 int i;
3024 list_T *l;
3025 dict_T *d;
3026#endif
3027
3028 if (rettv_list_alloc(rettv) != OK)
3029 return;
3030
3031#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003032 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003033 if (wp == NULL)
3034 return;
3035
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003036 cleanup_jumplist(wp, TRUE);
3037
Bram Moolenaar4f505882018-02-10 21:06:32 +01003038 l = list_alloc();
3039 if (l == NULL)
3040 return;
3041
3042 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3043 return;
3044 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3045
3046 for (i = 0; i < wp->w_jumplistlen; ++i)
3047 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003048 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3049 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003050 if ((d = dict_alloc()) == NULL)
3051 return;
3052 if (list_append_dict(l, d) == FAIL)
3053 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003054 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3055 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003056 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003057 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003058 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003059 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003060 }
3061#endif
3062}
3063
3064/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003065 * "getpid()" function
3066 */
3067 static void
3068f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3069{
3070 rettv->vval.v_number = mch_get_pid();
3071}
3072
3073 static void
3074getpos_both(
3075 typval_T *argvars,
3076 typval_T *rettv,
3077 int getcurpos)
3078{
3079 pos_T *fp;
3080 list_T *l;
3081 int fnum = -1;
3082
3083 if (rettv_list_alloc(rettv) == OK)
3084 {
3085 l = rettv->vval.v_list;
3086 if (getcurpos)
3087 fp = &curwin->w_cursor;
3088 else
3089 fp = var2fpos(&argvars[0], TRUE, &fnum);
3090 if (fnum != -1)
3091 list_append_number(l, (varnumber_T)fnum);
3092 else
3093 list_append_number(l, (varnumber_T)0);
3094 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3095 : (varnumber_T)0);
3096 list_append_number(l, (fp != NULL)
3097 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3098 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003099 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003100 (varnumber_T)0);
3101 if (getcurpos)
3102 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003103 int save_set_curswant = curwin->w_set_curswant;
3104 colnr_T save_curswant = curwin->w_curswant;
3105 colnr_T save_virtcol = curwin->w_virtcol;
3106
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003107 update_curswant();
3108 list_append_number(l, curwin->w_curswant == MAXCOL ?
3109 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003110
3111 // Do not change "curswant", as it is unexpected that a get
3112 // function has a side effect.
3113 if (save_set_curswant)
3114 {
3115 curwin->w_set_curswant = save_set_curswant;
3116 curwin->w_curswant = save_curswant;
3117 curwin->w_virtcol = save_virtcol;
3118 curwin->w_valid &= ~VALID_VIRTCOL;
3119 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003120 }
3121 }
3122 else
3123 rettv->vval.v_number = FALSE;
3124}
3125
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003126/*
3127 * "getcurpos()" function
3128 */
3129 static void
3130f_getcurpos(typval_T *argvars, typval_T *rettv)
3131{
3132 getpos_both(argvars, rettv, TRUE);
3133}
3134
3135/*
3136 * "getpos(string)" function
3137 */
3138 static void
3139f_getpos(typval_T *argvars, typval_T *rettv)
3140{
3141 getpos_both(argvars, rettv, FALSE);
3142}
3143
3144/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003145 * "getreg()" function
3146 */
3147 static void
3148f_getreg(typval_T *argvars, typval_T *rettv)
3149{
3150 char_u *strregname;
3151 int regname;
3152 int arg2 = FALSE;
3153 int return_list = FALSE;
3154 int error = FALSE;
3155
3156 if (argvars[0].v_type != VAR_UNKNOWN)
3157 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003158 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003159 error = strregname == NULL;
3160 if (argvars[1].v_type != VAR_UNKNOWN)
3161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003162 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003163 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003164 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003165 }
3166 }
3167 else
3168 strregname = get_vim_var_str(VV_REG);
3169
3170 if (error)
3171 return;
3172
3173 regname = (strregname == NULL ? '"' : *strregname);
3174 if (regname == 0)
3175 regname = '"';
3176
3177 if (return_list)
3178 {
3179 rettv->v_type = VAR_LIST;
3180 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3181 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3182 if (rettv->vval.v_list == NULL)
3183 (void)rettv_list_alloc(rettv);
3184 else
3185 ++rettv->vval.v_list->lv_refcount;
3186 }
3187 else
3188 {
3189 rettv->v_type = VAR_STRING;
3190 rettv->vval.v_string = get_reg_contents(regname,
3191 arg2 ? GREG_EXPR_SRC : 0);
3192 }
3193}
3194
3195/*
3196 * "getregtype()" function
3197 */
3198 static void
3199f_getregtype(typval_T *argvars, typval_T *rettv)
3200{
3201 char_u *strregname;
3202 int regname;
3203 char_u buf[NUMBUFLEN + 2];
3204 long reglen = 0;
3205
3206 if (argvars[0].v_type != VAR_UNKNOWN)
3207 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003208 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003209 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003210 {
3211 rettv->v_type = VAR_STRING;
3212 rettv->vval.v_string = NULL;
3213 return;
3214 }
3215 }
3216 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003217 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003218 strregname = get_vim_var_str(VV_REG);
3219
3220 regname = (strregname == NULL ? '"' : *strregname);
3221 if (regname == 0)
3222 regname = '"';
3223
3224 buf[0] = NUL;
3225 buf[1] = NUL;
3226 switch (get_reg_type(regname, &reglen))
3227 {
3228 case MLINE: buf[0] = 'V'; break;
3229 case MCHAR: buf[0] = 'v'; break;
3230 case MBLOCK:
3231 buf[0] = Ctrl_V;
3232 sprintf((char *)buf + 1, "%ld", reglen + 1);
3233 break;
3234 }
3235 rettv->v_type = VAR_STRING;
3236 rettv->vval.v_string = vim_strsave(buf);
3237}
3238
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003239/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003240 * "gettagstack()" function
3241 */
3242 static void
3243f_gettagstack(typval_T *argvars, typval_T *rettv)
3244{
3245 win_T *wp = curwin; // default is current window
3246
3247 if (rettv_dict_alloc(rettv) != OK)
3248 return;
3249
3250 if (argvars[0].v_type != VAR_UNKNOWN)
3251 {
3252 wp = find_win_by_nr_or_id(&argvars[0]);
3253 if (wp == NULL)
3254 return;
3255 }
3256
3257 get_tagstack(wp, rettv->vval.v_dict);
3258}
3259
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003260// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003261#include "version.h"
3262
3263/*
3264 * "has()" function
3265 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003266 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003267f_has(typval_T *argvars, typval_T *rettv)
3268{
3269 int i;
3270 char_u *name;
3271 int n = FALSE;
3272 static char *(has_list[]) =
3273 {
3274#ifdef AMIGA
3275 "amiga",
3276# ifdef FEAT_ARP
3277 "arp",
3278# endif
3279#endif
3280#ifdef __BEOS__
3281 "beos",
3282#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003283#if defined(BSD) && !defined(MACOS_X)
3284 "bsd",
3285#endif
3286#ifdef hpux
3287 "hpux",
3288#endif
3289#ifdef __linux__
3290 "linux",
3291#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003292#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003293 "mac", // Mac OS X (and, once, Mac OS Classic)
3294 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003295# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003296 "macunix", // Mac OS X, with the darwin feature
3297 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003298# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003299#endif
3300#ifdef __QNX__
3301 "qnx",
3302#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003303#ifdef SUN_SYSTEM
3304 "sun",
3305#else
3306 "moon",
3307#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308#ifdef UNIX
3309 "unix",
3310#endif
3311#ifdef VMS
3312 "vms",
3313#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003314#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003315 "win32",
3316#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003317#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003318 "win32unix",
3319#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003320#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003321 "win64",
3322#endif
3323#ifdef EBCDIC
3324 "ebcdic",
3325#endif
3326#ifndef CASE_INSENSITIVE_FILENAME
3327 "fname_case",
3328#endif
3329#ifdef HAVE_ACL
3330 "acl",
3331#endif
3332#ifdef FEAT_ARABIC
3333 "arabic",
3334#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003335 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003336#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003337 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003338#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003339#ifdef FEAT_AUTOSERVERNAME
3340 "autoservername",
3341#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003342#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003343 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003344# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003345 "balloon_multiline",
3346# endif
3347#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003348#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003349 "balloon_eval_term",
3350#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003351#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3352 "builtin_terms",
3353# ifdef ALL_BUILTIN_TCAPS
3354 "all_builtin_terms",
3355# endif
3356#endif
3357#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003358 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003359 || defined(FEAT_GUI_MOTIF))
3360 "browsefilter",
3361#endif
3362#ifdef FEAT_BYTEOFF
3363 "byte_offset",
3364#endif
3365#ifdef FEAT_JOB_CHANNEL
3366 "channel",
3367#endif
3368#ifdef FEAT_CINDENT
3369 "cindent",
3370#endif
3371#ifdef FEAT_CLIENTSERVER
3372 "clientserver",
3373#endif
3374#ifdef FEAT_CLIPBOARD
3375 "clipboard",
3376#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003378 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003379 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003380#ifdef FEAT_CONCEAL
3381 "conceal",
3382#endif
3383#ifdef FEAT_CRYPT
3384 "cryptv",
3385 "crypt-blowfish",
3386 "crypt-blowfish2",
3387#endif
3388#ifdef FEAT_CSCOPE
3389 "cscope",
3390#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392#ifdef CURSOR_SHAPE
3393 "cursorshape",
3394#endif
3395#ifdef DEBUG
3396 "debug",
3397#endif
3398#ifdef FEAT_CON_DIALOG
3399 "dialog_con",
3400#endif
3401#ifdef FEAT_GUI_DIALOG
3402 "dialog_gui",
3403#endif
3404#ifdef FEAT_DIFF
3405 "diff",
3406#endif
3407#ifdef FEAT_DIGRAPHS
3408 "digraphs",
3409#endif
3410#ifdef FEAT_DIRECTX
3411 "directx",
3412#endif
3413#ifdef FEAT_DND
3414 "dnd",
3415#endif
3416#ifdef FEAT_EMACS_TAGS
3417 "emacs_tags",
3418#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003419 "eval", // always present, of course!
3420 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003421#ifdef FEAT_SEARCH_EXTRA
3422 "extra_search",
3423#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003424#ifdef FEAT_SEARCHPATH
3425 "file_in_path",
3426#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003427#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428 "filterpipe",
3429#endif
3430#ifdef FEAT_FIND_ID
3431 "find_in_path",
3432#endif
3433#ifdef FEAT_FLOAT
3434 "float",
3435#endif
3436#ifdef FEAT_FOLDING
3437 "folding",
3438#endif
3439#ifdef FEAT_FOOTER
3440 "footer",
3441#endif
3442#if !defined(USE_SYSTEM) && defined(UNIX)
3443 "fork",
3444#endif
3445#ifdef FEAT_GETTEXT
3446 "gettext",
3447#endif
3448#ifdef FEAT_GUI
3449 "gui",
3450#endif
3451#ifdef FEAT_GUI_ATHENA
3452# ifdef FEAT_GUI_NEXTAW
3453 "gui_neXtaw",
3454# else
3455 "gui_athena",
3456# endif
3457#endif
3458#ifdef FEAT_GUI_GTK
3459 "gui_gtk",
3460# ifdef USE_GTK3
3461 "gui_gtk3",
3462# else
3463 "gui_gtk2",
3464# endif
3465#endif
3466#ifdef FEAT_GUI_GNOME
3467 "gui_gnome",
3468#endif
3469#ifdef FEAT_GUI_MAC
3470 "gui_mac",
3471#endif
3472#ifdef FEAT_GUI_MOTIF
3473 "gui_motif",
3474#endif
3475#ifdef FEAT_GUI_PHOTON
3476 "gui_photon",
3477#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003478#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003479 "gui_win32",
3480#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003481#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3482 "iconv",
3483#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003484 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003485#ifdef FEAT_JOB_CHANNEL
3486 "job",
3487#endif
3488#ifdef FEAT_JUMPLIST
3489 "jumplist",
3490#endif
3491#ifdef FEAT_KEYMAP
3492 "keymap",
3493#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003494 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003495#ifdef FEAT_LANGMAP
3496 "langmap",
3497#endif
3498#ifdef FEAT_LIBCALL
3499 "libcall",
3500#endif
3501#ifdef FEAT_LINEBREAK
3502 "linebreak",
3503#endif
3504#ifdef FEAT_LISP
3505 "lispindent",
3506#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003507 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003508 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003509#ifdef FEAT_LUA
3510# ifndef DYNAMIC_LUA
3511 "lua",
3512# endif
3513#endif
3514#ifdef FEAT_MENU
3515 "menu",
3516#endif
3517#ifdef FEAT_SESSION
3518 "mksession",
3519#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003521 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003522#ifdef FEAT_MOUSESHAPE
3523 "mouseshape",
3524#endif
3525#if defined(UNIX) || defined(VMS)
3526# ifdef FEAT_MOUSE_DEC
3527 "mouse_dec",
3528# endif
3529# ifdef FEAT_MOUSE_GPM
3530 "mouse_gpm",
3531# endif
3532# ifdef FEAT_MOUSE_JSB
3533 "mouse_jsbterm",
3534# endif
3535# ifdef FEAT_MOUSE_NET
3536 "mouse_netterm",
3537# endif
3538# ifdef FEAT_MOUSE_PTERM
3539 "mouse_pterm",
3540# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003541# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003542 "mouse_sgr",
3543# endif
3544# ifdef FEAT_SYSMOUSE
3545 "mouse_sysmouse",
3546# endif
3547# ifdef FEAT_MOUSE_URXVT
3548 "mouse_urxvt",
3549# endif
3550# ifdef FEAT_MOUSE_XTERM
3551 "mouse_xterm",
3552# endif
3553#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003554 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003555#ifdef FEAT_MBYTE_IME
3556 "multi_byte_ime",
3557#endif
3558#ifdef FEAT_MULTI_LANG
3559 "multi_lang",
3560#endif
3561#ifdef FEAT_MZSCHEME
3562#ifndef DYNAMIC_MZSCHEME
3563 "mzscheme",
3564#endif
3565#endif
3566#ifdef FEAT_NUM64
3567 "num64",
3568#endif
3569#ifdef FEAT_OLE
3570 "ole",
3571#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003572#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003573 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003574#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003575#ifdef FEAT_PATH_EXTRA
3576 "path_extra",
3577#endif
3578#ifdef FEAT_PERL
3579#ifndef DYNAMIC_PERL
3580 "perl",
3581#endif
3582#endif
3583#ifdef FEAT_PERSISTENT_UNDO
3584 "persistent_undo",
3585#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003586#if defined(FEAT_PYTHON)
3587 "python_compiled",
3588# if defined(DYNAMIC_PYTHON)
3589 "python_dynamic",
3590# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003591 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003592 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003593# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003594#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003595#if defined(FEAT_PYTHON3)
3596 "python3_compiled",
3597# if defined(DYNAMIC_PYTHON3)
3598 "python3_dynamic",
3599# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003601 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003602# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003604#ifdef FEAT_PROP_POPUP
3605 "popupwin",
3606#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003607#ifdef FEAT_POSTSCRIPT
3608 "postscript",
3609#endif
3610#ifdef FEAT_PRINTER
3611 "printer",
3612#endif
3613#ifdef FEAT_PROFILE
3614 "profile",
3615#endif
3616#ifdef FEAT_RELTIME
3617 "reltime",
3618#endif
3619#ifdef FEAT_QUICKFIX
3620 "quickfix",
3621#endif
3622#ifdef FEAT_RIGHTLEFT
3623 "rightleft",
3624#endif
3625#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3626 "ruby",
3627#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003628 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003629#ifdef FEAT_CMDL_INFO
3630 "showcmd",
3631 "cmdline_info",
3632#endif
3633#ifdef FEAT_SIGNS
3634 "signs",
3635#endif
3636#ifdef FEAT_SMARTINDENT
3637 "smartindent",
3638#endif
3639#ifdef STARTUPTIME
3640 "startuptime",
3641#endif
3642#ifdef FEAT_STL_OPT
3643 "statusline",
3644#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003645#ifdef FEAT_NETBEANS_INTG
3646 "netbeans_intg",
3647#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003648#ifdef FEAT_SOUND
3649 "sound",
3650#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003651#ifdef FEAT_SPELL
3652 "spell",
3653#endif
3654#ifdef FEAT_SYN_HL
3655 "syntax",
3656#endif
3657#if defined(USE_SYSTEM) || !defined(UNIX)
3658 "system",
3659#endif
3660#ifdef FEAT_TAG_BINS
3661 "tag_binary",
3662#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003663#ifdef FEAT_TCL
3664# ifndef DYNAMIC_TCL
3665 "tcl",
3666# endif
3667#endif
3668#ifdef FEAT_TERMGUICOLORS
3669 "termguicolors",
3670#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003671#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003672 "terminal",
3673#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003674#ifdef TERMINFO
3675 "terminfo",
3676#endif
3677#ifdef FEAT_TERMRESPONSE
3678 "termresponse",
3679#endif
3680#ifdef FEAT_TEXTOBJ
3681 "textobjects",
3682#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003683#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003684 "textprop",
3685#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003686#ifdef HAVE_TGETENT
3687 "tgetent",
3688#endif
3689#ifdef FEAT_TIMERS
3690 "timers",
3691#endif
3692#ifdef FEAT_TITLE
3693 "title",
3694#endif
3695#ifdef FEAT_TOOLBAR
3696 "toolbar",
3697#endif
3698#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3699 "unnamedplus",
3700#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003701 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003702 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003703#ifdef FEAT_VARTABS
3704 "vartabs",
3705#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003706 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003707#ifdef FEAT_VIMINFO
3708 "viminfo",
3709#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003710 "vimscript-1",
3711 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003712 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003713 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003715 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003716 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003717 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003718#ifdef FEAT_VTP
3719 "vtp",
3720#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003721#ifdef FEAT_WILDIGN
3722 "wildignore",
3723#endif
3724#ifdef FEAT_WILDMENU
3725 "wildmenu",
3726#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003727 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003728#ifdef FEAT_WAK
3729 "winaltkeys",
3730#endif
3731#ifdef FEAT_WRITEBACKUP
3732 "writebackup",
3733#endif
3734#ifdef FEAT_XIM
3735 "xim",
3736#endif
3737#ifdef FEAT_XFONTSET
3738 "xfontset",
3739#endif
3740#ifdef FEAT_XPM_W32
3741 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003742 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003743#else
3744# if defined(HAVE_XPM)
3745 "xpm",
3746# endif
3747#endif
3748#ifdef USE_XSMP
3749 "xsmp",
3750#endif
3751#ifdef USE_XSMP_INTERACT
3752 "xsmp_interact",
3753#endif
3754#ifdef FEAT_XCLIPBOARD
3755 "xterm_clipboard",
3756#endif
3757#ifdef FEAT_XTERM_SAVE
3758 "xterm_save",
3759#endif
3760#if defined(UNIX) && defined(FEAT_X11)
3761 "X11",
3762#endif
3763 NULL
3764 };
3765
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003766 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767 for (i = 0; has_list[i] != NULL; ++i)
3768 if (STRICMP(name, has_list[i]) == 0)
3769 {
3770 n = TRUE;
3771 break;
3772 }
3773
3774 if (n == FALSE)
3775 {
3776 if (STRNICMP(name, "patch", 5) == 0)
3777 {
3778 if (name[5] == '-'
3779 && STRLEN(name) >= 11
3780 && vim_isdigit(name[6])
3781 && vim_isdigit(name[8])
3782 && vim_isdigit(name[10]))
3783 {
3784 int major = atoi((char *)name + 6);
3785 int minor = atoi((char *)name + 8);
3786
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003787 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003788 n = (major < VIM_VERSION_MAJOR
3789 || (major == VIM_VERSION_MAJOR
3790 && (minor < VIM_VERSION_MINOR
3791 || (minor == VIM_VERSION_MINOR
3792 && has_patch(atoi((char *)name + 10))))));
3793 }
3794 else
3795 n = has_patch(atoi((char *)name + 5));
3796 }
3797 else if (STRICMP(name, "vim_starting") == 0)
3798 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003799 else if (STRICMP(name, "ttyin") == 0)
3800 n = mch_input_isatty();
3801 else if (STRICMP(name, "ttyout") == 0)
3802 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003803 else if (STRICMP(name, "multi_byte_encoding") == 0)
3804 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003805#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003806 else if (STRICMP(name, "balloon_multiline") == 0)
3807 n = multiline_balloon_available();
3808#endif
3809#ifdef DYNAMIC_TCL
3810 else if (STRICMP(name, "tcl") == 0)
3811 n = tcl_enabled(FALSE);
3812#endif
3813#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3814 else if (STRICMP(name, "iconv") == 0)
3815 n = iconv_enabled(FALSE);
3816#endif
3817#ifdef DYNAMIC_LUA
3818 else if (STRICMP(name, "lua") == 0)
3819 n = lua_enabled(FALSE);
3820#endif
3821#ifdef DYNAMIC_MZSCHEME
3822 else if (STRICMP(name, "mzscheme") == 0)
3823 n = mzscheme_enabled(FALSE);
3824#endif
3825#ifdef DYNAMIC_RUBY
3826 else if (STRICMP(name, "ruby") == 0)
3827 n = ruby_enabled(FALSE);
3828#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003829#ifdef DYNAMIC_PYTHON
3830 else if (STRICMP(name, "python") == 0)
3831 n = python_enabled(FALSE);
3832#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003833#ifdef DYNAMIC_PYTHON3
3834 else if (STRICMP(name, "python3") == 0)
3835 n = python3_enabled(FALSE);
3836#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003837#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3838 else if (STRICMP(name, "pythonx") == 0)
3839 {
3840# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3841 if (p_pyx == 0)
3842 n = python3_enabled(FALSE) || python_enabled(FALSE);
3843 else if (p_pyx == 3)
3844 n = python3_enabled(FALSE);
3845 else if (p_pyx == 2)
3846 n = python_enabled(FALSE);
3847# elif defined(DYNAMIC_PYTHON)
3848 n = python_enabled(FALSE);
3849# elif defined(DYNAMIC_PYTHON3)
3850 n = python3_enabled(FALSE);
3851# endif
3852 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003853#endif
3854#ifdef DYNAMIC_PERL
3855 else if (STRICMP(name, "perl") == 0)
3856 n = perl_enabled(FALSE);
3857#endif
3858#ifdef FEAT_GUI
3859 else if (STRICMP(name, "gui_running") == 0)
3860 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003861# ifdef FEAT_BROWSE
3862 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003863 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864# endif
3865#endif
3866#ifdef FEAT_SYN_HL
3867 else if (STRICMP(name, "syntax_items") == 0)
3868 n = syntax_present(curwin);
3869#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003870#ifdef FEAT_VTP
3871 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003872 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003873#endif
3874#ifdef FEAT_NETBEANS_INTG
3875 else if (STRICMP(name, "netbeans_enabled") == 0)
3876 n = netbeans_active();
3877#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003878#ifdef FEAT_MOUSE_GPM
3879 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3880 n = gpm_enabled();
3881#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003882#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003883 else if (STRICMP(name, "terminal") == 0)
3884 n = terminal_enabled();
3885#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003886#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003887 else if (STRICMP(name, "conpty") == 0)
3888 n = use_conpty();
3889#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003890#ifdef FEAT_CLIPBOARD
3891 else if (STRICMP(name, "clipboard_working") == 0)
3892 n = clip_star.available;
3893#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003894#ifdef VIMDLL
3895 else if (STRICMP(name, "filterpipe") == 0)
3896 n = gui.in_use || gui.starting;
3897#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003898 }
3899
3900 rettv->vval.v_number = n;
3901}
3902
3903/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003904 * "haslocaldir()" function
3905 */
3906 static void
3907f_haslocaldir(typval_T *argvars, typval_T *rettv)
3908{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003909 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003910 win_T *wp = NULL;
3911
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003912 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3913
3914 // Check for window-local and tab-local directories
3915 if (wp != NULL && wp->w_localdir != NULL)
3916 rettv->vval.v_number = 1;
3917 else if (tp != NULL && tp->tp_localdir != NULL)
3918 rettv->vval.v_number = 2;
3919 else
3920 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003921}
3922
3923/*
3924 * "hasmapto()" function
3925 */
3926 static void
3927f_hasmapto(typval_T *argvars, typval_T *rettv)
3928{
3929 char_u *name;
3930 char_u *mode;
3931 char_u buf[NUMBUFLEN];
3932 int abbr = FALSE;
3933
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003934 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003935 if (argvars[1].v_type == VAR_UNKNOWN)
3936 mode = (char_u *)"nvo";
3937 else
3938 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003939 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003940 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003941 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003942 }
3943
3944 if (map_to_exists(name, mode, abbr))
3945 rettv->vval.v_number = TRUE;
3946 else
3947 rettv->vval.v_number = FALSE;
3948}
3949
3950/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003951 * "highlightID(name)" function
3952 */
3953 static void
3954f_hlID(typval_T *argvars, typval_T *rettv)
3955{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003956 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003957}
3958
3959/*
3960 * "highlight_exists()" function
3961 */
3962 static void
3963f_hlexists(typval_T *argvars, typval_T *rettv)
3964{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003965 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003966}
3967
3968/*
3969 * "hostname()" function
3970 */
3971 static void
3972f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3973{
3974 char_u hostname[256];
3975
3976 mch_get_host_name(hostname, 256);
3977 rettv->v_type = VAR_STRING;
3978 rettv->vval.v_string = vim_strsave(hostname);
3979}
3980
3981/*
3982 * iconv() function
3983 */
3984 static void
3985f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3986{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003987 char_u buf1[NUMBUFLEN];
3988 char_u buf2[NUMBUFLEN];
3989 char_u *from, *to, *str;
3990 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003991
3992 rettv->v_type = VAR_STRING;
3993 rettv->vval.v_string = NULL;
3994
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003995 str = tv_get_string(&argvars[0]);
3996 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3997 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003998 vimconv.vc_type = CONV_NONE;
3999 convert_setup(&vimconv, from, to);
4000
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004001 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004002 if (vimconv.vc_type == CONV_NONE)
4003 rettv->vval.v_string = vim_strsave(str);
4004 else
4005 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4006
4007 convert_setup(&vimconv, NULL, NULL);
4008 vim_free(from);
4009 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004010}
4011
4012/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 * "index()" function
4014 */
4015 static void
4016f_index(typval_T *argvars, typval_T *rettv)
4017{
4018 list_T *l;
4019 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004020 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004021 long idx = 0;
4022 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004023 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004024
4025 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004026 if (argvars[0].v_type == VAR_BLOB)
4027 {
4028 typval_T tv;
4029 int start = 0;
4030
4031 if (argvars[2].v_type != VAR_UNKNOWN)
4032 {
4033 start = tv_get_number_chk(&argvars[2], &error);
4034 if (error)
4035 return;
4036 }
4037 b = argvars[0].vval.v_blob;
4038 if (b == NULL)
4039 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004040 if (start < 0)
4041 {
4042 start = blob_len(b) + start;
4043 if (start < 0)
4044 start = 0;
4045 }
4046
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004047 for (idx = start; idx < blob_len(b); ++idx)
4048 {
4049 tv.v_type = VAR_NUMBER;
4050 tv.vval.v_number = blob_get(b, idx);
4051 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4052 {
4053 rettv->vval.v_number = idx;
4054 return;
4055 }
4056 }
4057 return;
4058 }
4059 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004060 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004061 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004062 return;
4063 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004064
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004065 l = argvars[0].vval.v_list;
4066 if (l != NULL)
4067 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004068 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004069 item = l->lv_first;
4070 if (argvars[2].v_type != VAR_UNKNOWN)
4071 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004072 // Start at specified item. Use the cached index that list_find()
4073 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004074 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004075 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004076 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004077 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004078 if (error)
4079 item = NULL;
4080 }
4081
4082 for ( ; item != NULL; item = item->li_next, ++idx)
4083 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4084 {
4085 rettv->vval.v_number = idx;
4086 break;
4087 }
4088 }
4089}
4090
4091static int inputsecret_flag = 0;
4092
4093/*
4094 * "input()" function
4095 * Also handles inputsecret() when inputsecret is set.
4096 */
4097 static void
4098f_input(typval_T *argvars, typval_T *rettv)
4099{
4100 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4101}
4102
4103/*
4104 * "inputdialog()" function
4105 */
4106 static void
4107f_inputdialog(typval_T *argvars, typval_T *rettv)
4108{
4109#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004110 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004111 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4112 {
4113 char_u *message;
4114 char_u buf[NUMBUFLEN];
4115 char_u *defstr = (char_u *)"";
4116
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004117 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004118 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004119 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004120 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4121 else
4122 IObuff[0] = NUL;
4123 if (message != NULL && defstr != NULL
4124 && do_dialog(VIM_QUESTION, NULL, message,
4125 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4126 rettv->vval.v_string = vim_strsave(IObuff);
4127 else
4128 {
4129 if (message != NULL && defstr != NULL
4130 && argvars[1].v_type != VAR_UNKNOWN
4131 && argvars[2].v_type != VAR_UNKNOWN)
4132 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004133 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004134 else
4135 rettv->vval.v_string = NULL;
4136 }
4137 rettv->v_type = VAR_STRING;
4138 }
4139 else
4140#endif
4141 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4142}
4143
4144/*
4145 * "inputlist()" function
4146 */
4147 static void
4148f_inputlist(typval_T *argvars, typval_T *rettv)
4149{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004150 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004151 listitem_T *li;
4152 int selected;
4153 int mouse_used;
4154
4155#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004156 // While starting up, there is no place to enter text. When running tests
4157 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004158 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004159 return;
4160#endif
4161 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4162 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004163 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004164 return;
4165 }
4166
4167 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004168 msg_row = Rows - 1; // for when 'cmdheight' > 1
4169 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004170 msg_scroll = TRUE;
4171 msg_clr_eos();
4172
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004173 l = argvars[0].vval.v_list;
4174 range_list_materialize(l);
4175 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004176 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004177 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004178 msg_putchar('\n');
4179 }
4180
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004181 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004182 selected = prompt_for_number(&mouse_used);
4183 if (mouse_used)
4184 selected -= lines_left;
4185
4186 rettv->vval.v_number = selected;
4187}
4188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004189static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4190
4191/*
4192 * "inputrestore()" function
4193 */
4194 static void
4195f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4196{
4197 if (ga_userinput.ga_len > 0)
4198 {
4199 --ga_userinput.ga_len;
4200 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4201 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004202 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004203 }
4204 else if (p_verbose > 1)
4205 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004206 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004207 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004208 }
4209}
4210
4211/*
4212 * "inputsave()" function
4213 */
4214 static void
4215f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4216{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004217 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004218 if (ga_grow(&ga_userinput, 1) == OK)
4219 {
4220 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4221 + ga_userinput.ga_len);
4222 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004223 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004224 }
4225 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004226 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004227}
4228
4229/*
4230 * "inputsecret()" function
4231 */
4232 static void
4233f_inputsecret(typval_T *argvars, typval_T *rettv)
4234{
4235 ++cmdline_star;
4236 ++inputsecret_flag;
4237 f_input(argvars, rettv);
4238 --cmdline_star;
4239 --inputsecret_flag;
4240}
4241
4242/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004243 * "interrupt()" function
4244 */
4245 static void
4246f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4247{
4248 got_int = TRUE;
4249}
4250
4251/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004252 * "invert(expr)" function
4253 */
4254 static void
4255f_invert(typval_T *argvars, typval_T *rettv)
4256{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004257 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004258}
4259
4260/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004261 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4262 * or it refers to a List or Dictionary that is locked.
4263 */
4264 static int
4265tv_islocked(typval_T *tv)
4266{
4267 return (tv->v_lock & VAR_LOCKED)
4268 || (tv->v_type == VAR_LIST
4269 && tv->vval.v_list != NULL
4270 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4271 || (tv->v_type == VAR_DICT
4272 && tv->vval.v_dict != NULL
4273 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4274}
4275
4276/*
4277 * "islocked()" function
4278 */
4279 static void
4280f_islocked(typval_T *argvars, typval_T *rettv)
4281{
4282 lval_T lv;
4283 char_u *end;
4284 dictitem_T *di;
4285
4286 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004287 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004288 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004289 if (end != NULL && lv.ll_name != NULL)
4290 {
4291 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004292 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004293 else
4294 {
4295 if (lv.ll_tv == NULL)
4296 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004297 di = find_var(lv.ll_name, NULL, TRUE);
4298 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004299 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004300 // Consider a variable locked when:
4301 // 1. the variable itself is locked
4302 // 2. the value of the variable is locked.
4303 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004304 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4305 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004306 }
4307 }
4308 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004309 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004310 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004311 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004312 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004313 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004314 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4315 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004316 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004317 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4318 }
4319 }
4320
4321 clear_lval(&lv);
4322}
4323
4324#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4325/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004326 * "isinf()" function
4327 */
4328 static void
4329f_isinf(typval_T *argvars, typval_T *rettv)
4330{
4331 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4332 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4333}
4334
4335/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004336 * "isnan()" function
4337 */
4338 static void
4339f_isnan(typval_T *argvars, typval_T *rettv)
4340{
4341 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4342 && isnan(argvars[0].vval.v_float);
4343}
4344#endif
4345
4346/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004347 * "last_buffer_nr()" function.
4348 */
4349 static void
4350f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4351{
4352 int n = 0;
4353 buf_T *buf;
4354
Bram Moolenaar29323592016-07-24 22:04:11 +02004355 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004356 if (n < buf->b_fnum)
4357 n = buf->b_fnum;
4358
4359 rettv->vval.v_number = n;
4360}
4361
4362/*
4363 * "len()" function
4364 */
4365 static void
4366f_len(typval_T *argvars, typval_T *rettv)
4367{
4368 switch (argvars[0].v_type)
4369 {
4370 case VAR_STRING:
4371 case VAR_NUMBER:
4372 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004373 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004374 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004375 case VAR_BLOB:
4376 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4377 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004378 case VAR_LIST:
4379 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4380 break;
4381 case VAR_DICT:
4382 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4383 break;
4384 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004385 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004386 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004387 case VAR_SPECIAL:
4388 case VAR_FLOAT:
4389 case VAR_FUNC:
4390 case VAR_PARTIAL:
4391 case VAR_JOB:
4392 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004393 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004394 break;
4395 }
4396}
4397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004398 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004399libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004400{
4401#ifdef FEAT_LIBCALL
4402 char_u *string_in;
4403 char_u **string_result;
4404 int nr_result;
4405#endif
4406
4407 rettv->v_type = type;
4408 if (type != VAR_NUMBER)
4409 rettv->vval.v_string = NULL;
4410
4411 if (check_restricted() || check_secure())
4412 return;
4413
4414#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004415 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004416 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4417 {
4418 string_in = NULL;
4419 if (argvars[2].v_type == VAR_STRING)
4420 string_in = argvars[2].vval.v_string;
4421 if (type == VAR_NUMBER)
4422 string_result = NULL;
4423 else
4424 string_result = &rettv->vval.v_string;
4425 if (mch_libcall(argvars[0].vval.v_string,
4426 argvars[1].vval.v_string,
4427 string_in,
4428 argvars[2].vval.v_number,
4429 string_result,
4430 &nr_result) == OK
4431 && type == VAR_NUMBER)
4432 rettv->vval.v_number = nr_result;
4433 }
4434#endif
4435}
4436
4437/*
4438 * "libcall()" function
4439 */
4440 static void
4441f_libcall(typval_T *argvars, typval_T *rettv)
4442{
4443 libcall_common(argvars, rettv, VAR_STRING);
4444}
4445
4446/*
4447 * "libcallnr()" function
4448 */
4449 static void
4450f_libcallnr(typval_T *argvars, typval_T *rettv)
4451{
4452 libcall_common(argvars, rettv, VAR_NUMBER);
4453}
4454
4455/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004456 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004457 */
4458 static void
4459f_line(typval_T *argvars, typval_T *rettv)
4460{
4461 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004462 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004463 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004464 int id;
4465 tabpage_T *tp;
4466 win_T *wp;
4467 win_T *save_curwin;
4468 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004469
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004470 if (argvars[1].v_type != VAR_UNKNOWN)
4471 {
4472 // use window specified in the second argument
4473 id = (int)tv_get_number(&argvars[1]);
4474 wp = win_id2wp_tp(id, &tp);
4475 if (wp != NULL && tp != NULL)
4476 {
4477 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4478 == OK)
4479 {
4480 check_cursor();
4481 fp = var2fpos(&argvars[0], TRUE, &fnum);
4482 }
4483 restore_win_noblock(save_curwin, save_curtab, TRUE);
4484 }
4485 }
4486 else
4487 // use current window
4488 fp = var2fpos(&argvars[0], TRUE, &fnum);
4489
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004490 if (fp != NULL)
4491 lnum = fp->lnum;
4492 rettv->vval.v_number = lnum;
4493}
4494
4495/*
4496 * "line2byte(lnum)" function
4497 */
4498 static void
4499f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4500{
4501#ifndef FEAT_BYTEOFF
4502 rettv->vval.v_number = -1;
4503#else
4504 linenr_T lnum;
4505
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004506 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004507 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4508 rettv->vval.v_number = -1;
4509 else
4510 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4511 if (rettv->vval.v_number >= 0)
4512 ++rettv->vval.v_number;
4513#endif
4514}
4515
4516/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004517 * "localtime()" function
4518 */
4519 static void
4520f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4521{
4522 rettv->vval.v_number = (varnumber_T)time(NULL);
4523}
4524
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004525#ifdef FEAT_FLOAT
4526/*
4527 * "log()" function
4528 */
4529 static void
4530f_log(typval_T *argvars, typval_T *rettv)
4531{
4532 float_T f = 0.0;
4533
4534 rettv->v_type = VAR_FLOAT;
4535 if (get_float_arg(argvars, &f) == OK)
4536 rettv->vval.v_float = log(f);
4537 else
4538 rettv->vval.v_float = 0.0;
4539}
4540
4541/*
4542 * "log10()" function
4543 */
4544 static void
4545f_log10(typval_T *argvars, typval_T *rettv)
4546{
4547 float_T f = 0.0;
4548
4549 rettv->v_type = VAR_FLOAT;
4550 if (get_float_arg(argvars, &f) == OK)
4551 rettv->vval.v_float = log10(f);
4552 else
4553 rettv->vval.v_float = 0.0;
4554}
4555#endif
4556
4557#ifdef FEAT_LUA
4558/*
4559 * "luaeval()" function
4560 */
4561 static void
4562f_luaeval(typval_T *argvars, typval_T *rettv)
4563{
4564 char_u *str;
4565 char_u buf[NUMBUFLEN];
4566
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004567 if (check_restricted() || check_secure())
4568 return;
4569
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004570 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004571 do_luaeval(str, argvars + 1, rettv);
4572}
4573#endif
4574
4575/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004576 * "maparg()" function
4577 */
4578 static void
4579f_maparg(typval_T *argvars, typval_T *rettv)
4580{
4581 get_maparg(argvars, rettv, TRUE);
4582}
4583
4584/*
4585 * "mapcheck()" function
4586 */
4587 static void
4588f_mapcheck(typval_T *argvars, typval_T *rettv)
4589{
4590 get_maparg(argvars, rettv, FALSE);
4591}
4592
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004593typedef enum
4594{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004595 MATCH_END, // matchend()
4596 MATCH_MATCH, // match()
4597 MATCH_STR, // matchstr()
4598 MATCH_LIST, // matchlist()
4599 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004600} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004601
4602 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004603find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004604{
4605 char_u *str = NULL;
4606 long len = 0;
4607 char_u *expr = NULL;
4608 char_u *pat;
4609 regmatch_T regmatch;
4610 char_u patbuf[NUMBUFLEN];
4611 char_u strbuf[NUMBUFLEN];
4612 char_u *save_cpo;
4613 long start = 0;
4614 long nth = 1;
4615 colnr_T startcol = 0;
4616 int match = 0;
4617 list_T *l = NULL;
4618 listitem_T *li = NULL;
4619 long idx = 0;
4620 char_u *tofree = NULL;
4621
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004622 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004623 save_cpo = p_cpo;
4624 p_cpo = (char_u *)"";
4625
4626 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004627 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004628 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004629 // type MATCH_LIST: return empty list when there are no matches.
4630 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004631 if (rettv_list_alloc(rettv) == FAIL)
4632 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004633 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004634 && (list_append_string(rettv->vval.v_list,
4635 (char_u *)"", 0) == FAIL
4636 || list_append_number(rettv->vval.v_list,
4637 (varnumber_T)-1) == FAIL
4638 || list_append_number(rettv->vval.v_list,
4639 (varnumber_T)-1) == FAIL
4640 || list_append_number(rettv->vval.v_list,
4641 (varnumber_T)-1) == FAIL))
4642 {
4643 list_free(rettv->vval.v_list);
4644 rettv->vval.v_list = NULL;
4645 goto theend;
4646 }
4647 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004648 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004649 {
4650 rettv->v_type = VAR_STRING;
4651 rettv->vval.v_string = NULL;
4652 }
4653
4654 if (argvars[0].v_type == VAR_LIST)
4655 {
4656 if ((l = argvars[0].vval.v_list) == NULL)
4657 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004658 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004659 li = l->lv_first;
4660 }
4661 else
4662 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004663 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004664 len = (long)STRLEN(str);
4665 }
4666
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004667 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004668 if (pat == NULL)
4669 goto theend;
4670
4671 if (argvars[2].v_type != VAR_UNKNOWN)
4672 {
4673 int error = FALSE;
4674
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004675 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004676 if (error)
4677 goto theend;
4678 if (l != NULL)
4679 {
4680 li = list_find(l, start);
4681 if (li == NULL)
4682 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004683 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004684 }
4685 else
4686 {
4687 if (start < 0)
4688 start = 0;
4689 if (start > len)
4690 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004691 // When "count" argument is there ignore matches before "start",
4692 // otherwise skip part of the string. Differs when pattern is "^"
4693 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004694 if (argvars[3].v_type != VAR_UNKNOWN)
4695 startcol = start;
4696 else
4697 {
4698 str += start;
4699 len -= start;
4700 }
4701 }
4702
4703 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004704 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004705 if (error)
4706 goto theend;
4707 }
4708
4709 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4710 if (regmatch.regprog != NULL)
4711 {
4712 regmatch.rm_ic = p_ic;
4713
4714 for (;;)
4715 {
4716 if (l != NULL)
4717 {
4718 if (li == NULL)
4719 {
4720 match = FALSE;
4721 break;
4722 }
4723 vim_free(tofree);
4724 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4725 if (str == NULL)
4726 break;
4727 }
4728
4729 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4730
4731 if (match && --nth <= 0)
4732 break;
4733 if (l == NULL && !match)
4734 break;
4735
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004736 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004737 if (l != NULL)
4738 {
4739 li = li->li_next;
4740 ++idx;
4741 }
4742 else
4743 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004744 startcol = (colnr_T)(regmatch.startp[0]
4745 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746 if (startcol > (colnr_T)len
4747 || str + startcol <= regmatch.startp[0])
4748 {
4749 match = FALSE;
4750 break;
4751 }
4752 }
4753 }
4754
4755 if (match)
4756 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004757 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004758 {
4759 listitem_T *li1 = rettv->vval.v_list->lv_first;
4760 listitem_T *li2 = li1->li_next;
4761 listitem_T *li3 = li2->li_next;
4762 listitem_T *li4 = li3->li_next;
4763
4764 vim_free(li1->li_tv.vval.v_string);
4765 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4766 (int)(regmatch.endp[0] - regmatch.startp[0]));
4767 li3->li_tv.vval.v_number =
4768 (varnumber_T)(regmatch.startp[0] - expr);
4769 li4->li_tv.vval.v_number =
4770 (varnumber_T)(regmatch.endp[0] - expr);
4771 if (l != NULL)
4772 li2->li_tv.vval.v_number = (varnumber_T)idx;
4773 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004774 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004775 {
4776 int i;
4777
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004778 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004779 for (i = 0; i < NSUBEXP; ++i)
4780 {
4781 if (regmatch.endp[i] == NULL)
4782 {
4783 if (list_append_string(rettv->vval.v_list,
4784 (char_u *)"", 0) == FAIL)
4785 break;
4786 }
4787 else if (list_append_string(rettv->vval.v_list,
4788 regmatch.startp[i],
4789 (int)(regmatch.endp[i] - regmatch.startp[i]))
4790 == FAIL)
4791 break;
4792 }
4793 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004794 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004795 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004796 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004797 if (l != NULL)
4798 copy_tv(&li->li_tv, rettv);
4799 else
4800 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4801 (int)(regmatch.endp[0] - regmatch.startp[0]));
4802 }
4803 else if (l != NULL)
4804 rettv->vval.v_number = idx;
4805 else
4806 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004807 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004808 rettv->vval.v_number =
4809 (varnumber_T)(regmatch.startp[0] - str);
4810 else
4811 rettv->vval.v_number =
4812 (varnumber_T)(regmatch.endp[0] - str);
4813 rettv->vval.v_number += (varnumber_T)(str - expr);
4814 }
4815 }
4816 vim_regfree(regmatch.regprog);
4817 }
4818
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004819theend:
4820 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004821 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004822 listitem_remove(rettv->vval.v_list,
4823 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004824 vim_free(tofree);
4825 p_cpo = save_cpo;
4826}
4827
4828/*
4829 * "match()" function
4830 */
4831 static void
4832f_match(typval_T *argvars, typval_T *rettv)
4833{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004834 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004835}
4836
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004837/*
4838 * "matchend()" function
4839 */
4840 static void
4841f_matchend(typval_T *argvars, typval_T *rettv)
4842{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004843 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004844}
4845
4846/*
4847 * "matchlist()" function
4848 */
4849 static void
4850f_matchlist(typval_T *argvars, typval_T *rettv)
4851{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004852 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853}
4854
4855/*
4856 * "matchstr()" function
4857 */
4858 static void
4859f_matchstr(typval_T *argvars, typval_T *rettv)
4860{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004861 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004862}
4863
4864/*
4865 * "matchstrpos()" function
4866 */
4867 static void
4868f_matchstrpos(typval_T *argvars, typval_T *rettv)
4869{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004870 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004871}
4872
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004873 static void
4874max_min(typval_T *argvars, typval_T *rettv, int domax)
4875{
4876 varnumber_T n = 0;
4877 varnumber_T i;
4878 int error = FALSE;
4879
4880 if (argvars[0].v_type == VAR_LIST)
4881 {
4882 list_T *l;
4883 listitem_T *li;
4884
4885 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004886 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004887 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004888 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004889 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004890 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4891 n = l->lv_u.nonmat.lv_start;
4892 else
4893 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4894 * l->lv_u.nonmat.lv_stride;
4895 }
4896 else
4897 {
4898 li = l->lv_first;
4899 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004900 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004901 n = tv_get_number_chk(&li->li_tv, &error);
4902 for (;;)
4903 {
4904 li = li->li_next;
4905 if (li == NULL)
4906 break;
4907 i = tv_get_number_chk(&li->li_tv, &error);
4908 if (domax ? i > n : i < n)
4909 n = i;
4910 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911 }
4912 }
4913 }
4914 }
4915 else if (argvars[0].v_type == VAR_DICT)
4916 {
4917 dict_T *d;
4918 int first = TRUE;
4919 hashitem_T *hi;
4920 int todo;
4921
4922 d = argvars[0].vval.v_dict;
4923 if (d != NULL)
4924 {
4925 todo = (int)d->dv_hashtab.ht_used;
4926 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4927 {
4928 if (!HASHITEM_EMPTY(hi))
4929 {
4930 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004931 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004932 if (first)
4933 {
4934 n = i;
4935 first = FALSE;
4936 }
4937 else if (domax ? i > n : i < n)
4938 n = i;
4939 }
4940 }
4941 }
4942 }
4943 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004944 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945 rettv->vval.v_number = error ? 0 : n;
4946}
4947
4948/*
4949 * "max()" function
4950 */
4951 static void
4952f_max(typval_T *argvars, typval_T *rettv)
4953{
4954 max_min(argvars, rettv, TRUE);
4955}
4956
4957/*
4958 * "min()" function
4959 */
4960 static void
4961f_min(typval_T *argvars, typval_T *rettv)
4962{
4963 max_min(argvars, rettv, FALSE);
4964}
4965
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004966#if defined(FEAT_MZSCHEME) || defined(PROTO)
4967/*
4968 * "mzeval()" function
4969 */
4970 static void
4971f_mzeval(typval_T *argvars, typval_T *rettv)
4972{
4973 char_u *str;
4974 char_u buf[NUMBUFLEN];
4975
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004976 if (check_restricted() || check_secure())
4977 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004978 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004979 do_mzeval(str, rettv);
4980}
4981
4982 void
4983mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4984{
4985 typval_T argvars[3];
4986
4987 argvars[0].v_type = VAR_STRING;
4988 argvars[0].vval.v_string = name;
4989 copy_tv(args, &argvars[1]);
4990 argvars[2].v_type = VAR_UNKNOWN;
4991 f_call(argvars, rettv);
4992 clear_tv(&argvars[1]);
4993}
4994#endif
4995
4996/*
4997 * "nextnonblank()" function
4998 */
4999 static void
5000f_nextnonblank(typval_T *argvars, typval_T *rettv)
5001{
5002 linenr_T lnum;
5003
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005004 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005005 {
5006 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5007 {
5008 lnum = 0;
5009 break;
5010 }
5011 if (*skipwhite(ml_get(lnum)) != NUL)
5012 break;
5013 }
5014 rettv->vval.v_number = lnum;
5015}
5016
5017/*
5018 * "nr2char()" function
5019 */
5020 static void
5021f_nr2char(typval_T *argvars, typval_T *rettv)
5022{
5023 char_u buf[NUMBUFLEN];
5024
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 if (has_mbyte)
5026 {
5027 int utf8 = 0;
5028
5029 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005030 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005031 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005032 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005033 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005034 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035 }
5036 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005037 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005038 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005039 buf[1] = NUL;
5040 }
5041 rettv->v_type = VAR_STRING;
5042 rettv->vval.v_string = vim_strsave(buf);
5043}
5044
5045/*
5046 * "or(expr, expr)" function
5047 */
5048 static void
5049f_or(typval_T *argvars, typval_T *rettv)
5050{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005051 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5052 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005053}
5054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005055#ifdef FEAT_PERL
5056/*
5057 * "perleval()" function
5058 */
5059 static void
5060f_perleval(typval_T *argvars, typval_T *rettv)
5061{
5062 char_u *str;
5063 char_u buf[NUMBUFLEN];
5064
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005065 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005066 do_perleval(str, rettv);
5067}
5068#endif
5069
5070#ifdef FEAT_FLOAT
5071/*
5072 * "pow()" function
5073 */
5074 static void
5075f_pow(typval_T *argvars, typval_T *rettv)
5076{
5077 float_T fx = 0.0, fy = 0.0;
5078
5079 rettv->v_type = VAR_FLOAT;
5080 if (get_float_arg(argvars, &fx) == OK
5081 && get_float_arg(&argvars[1], &fy) == OK)
5082 rettv->vval.v_float = pow(fx, fy);
5083 else
5084 rettv->vval.v_float = 0.0;
5085}
5086#endif
5087
5088/*
5089 * "prevnonblank()" function
5090 */
5091 static void
5092f_prevnonblank(typval_T *argvars, typval_T *rettv)
5093{
5094 linenr_T lnum;
5095
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005096 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005097 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5098 lnum = 0;
5099 else
5100 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5101 --lnum;
5102 rettv->vval.v_number = lnum;
5103}
5104
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005105// This dummy va_list is here because:
5106// - passing a NULL pointer doesn't work when va_list isn't a pointer
5107// - locally in the function results in a "used before set" warning
5108// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109static va_list ap;
5110
5111/*
5112 * "printf()" function
5113 */
5114 static void
5115f_printf(typval_T *argvars, typval_T *rettv)
5116{
5117 char_u buf[NUMBUFLEN];
5118 int len;
5119 char_u *s;
5120 int saved_did_emsg = did_emsg;
5121 char *fmt;
5122
5123 rettv->v_type = VAR_STRING;
5124 rettv->vval.v_string = NULL;
5125
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005126 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005127 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005128 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005129 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005130 if (!did_emsg)
5131 {
5132 s = alloc(len + 1);
5133 if (s != NULL)
5134 {
5135 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005136 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5137 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005138 }
5139 }
5140 did_emsg |= saved_did_emsg;
5141}
5142
5143/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005144 * "pum_getpos()" function
5145 */
5146 static void
5147f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5148{
5149 if (rettv_dict_alloc(rettv) != OK)
5150 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005151 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005152}
5153
5154/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005155 * "pumvisible()" function
5156 */
5157 static void
5158f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5159{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005160 if (pum_visible())
5161 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005162}
5163
5164#ifdef FEAT_PYTHON3
5165/*
5166 * "py3eval()" function
5167 */
5168 static void
5169f_py3eval(typval_T *argvars, typval_T *rettv)
5170{
5171 char_u *str;
5172 char_u buf[NUMBUFLEN];
5173
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005174 if (check_restricted() || check_secure())
5175 return;
5176
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005177 if (p_pyx == 0)
5178 p_pyx = 3;
5179
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005180 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005181 do_py3eval(str, rettv);
5182}
5183#endif
5184
5185#ifdef FEAT_PYTHON
5186/*
5187 * "pyeval()" function
5188 */
5189 static void
5190f_pyeval(typval_T *argvars, typval_T *rettv)
5191{
5192 char_u *str;
5193 char_u buf[NUMBUFLEN];
5194
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005195 if (check_restricted() || check_secure())
5196 return;
5197
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005198 if (p_pyx == 0)
5199 p_pyx = 2;
5200
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005201 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005202 do_pyeval(str, rettv);
5203}
5204#endif
5205
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005206#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5207/*
5208 * "pyxeval()" function
5209 */
5210 static void
5211f_pyxeval(typval_T *argvars, typval_T *rettv)
5212{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005213 if (check_restricted() || check_secure())
5214 return;
5215
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005216# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5217 init_pyxversion();
5218 if (p_pyx == 2)
5219 f_pyeval(argvars, rettv);
5220 else
5221 f_py3eval(argvars, rettv);
5222# elif defined(FEAT_PYTHON)
5223 f_pyeval(argvars, rettv);
5224# elif defined(FEAT_PYTHON3)
5225 f_py3eval(argvars, rettv);
5226# endif
5227}
5228#endif
5229
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005230static UINT32_T srand_seed_for_testing = 0;
5231static int srand_seed_for_testing_is_used = FALSE;
5232
5233 static void
5234f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5235{
5236 if (argvars[0].v_type == VAR_UNKNOWN)
5237 srand_seed_for_testing_is_used = FALSE;
5238 else
5239 {
5240 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5241 srand_seed_for_testing_is_used = TRUE;
5242 }
5243}
5244
5245 static void
5246init_srand(UINT32_T *x)
5247{
5248#ifndef MSWIN
5249 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
5250#endif
5251
5252 if (srand_seed_for_testing_is_used)
5253 {
5254 *x = srand_seed_for_testing;
5255 return;
5256 }
5257#ifndef MSWIN
5258 if (dev_urandom_state != FAIL)
5259 {
5260 int fd = open("/dev/urandom", O_RDONLY);
5261 struct {
5262 union {
5263 UINT32_T number;
5264 char bytes[sizeof(UINT32_T)];
5265 } contents;
5266 } buf;
5267
5268 // Attempt reading /dev/urandom.
5269 if (fd == -1)
5270 dev_urandom_state = FAIL;
5271 else
5272 {
5273 buf.contents.number = 0;
5274 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
5275 != sizeof(UINT32_T))
5276 dev_urandom_state = FAIL;
5277 else
5278 {
5279 dev_urandom_state = OK;
5280 *x = buf.contents.number;
5281 }
5282 close(fd);
5283 }
5284 }
5285 if (dev_urandom_state != OK)
5286 // Reading /dev/urandom doesn't work, fall back to time().
5287#endif
5288 *x = vim_time();
5289}
5290
5291#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5292#define SPLITMIX32(x, z) ( \
5293 z = (x += 0x9e3779b9), \
5294 z = (z ^ (z >> 16)) * 0x85ebca6b, \
5295 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
5296 z ^ (z >> 16) \
5297 )
5298#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
5299 result = ROTL(y * 5, 7) * 9; \
5300 t = y << 9; \
5301 z ^= x; \
5302 w ^= y; \
5303 y ^= z, x ^= w; \
5304 z ^= t; \
5305 w = ROTL(w, 11);
5306
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005307/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005308 * "rand()" function
5309 */
5310 static void
5311f_rand(typval_T *argvars, typval_T *rettv)
5312{
5313 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005314 static UINT32_T gx, gy, gz, gw;
5315 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005316 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005317 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005318
5319 if (argvars[0].v_type == VAR_UNKNOWN)
5320 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005321 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005322 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005323 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005324 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005325 init_srand(&x);
5326
5327 gx = SPLITMIX32(x, z);
5328 gy = SPLITMIX32(x, z);
5329 gz = SPLITMIX32(x, z);
5330 gw = SPLITMIX32(x, z);
5331 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005332 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005333
5334 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005335 }
5336 else if (argvars[0].v_type == VAR_LIST)
5337 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005338 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005339 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005340 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005341
5342 lx = list_find(l, 0L);
5343 ly = list_find(l, 1L);
5344 lz = list_find(l, 2L);
5345 lw = list_find(l, 3L);
5346 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5347 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5348 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5349 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5350 x = (UINT32_T)lx->li_tv.vval.v_number;
5351 y = (UINT32_T)ly->li_tv.vval.v_number;
5352 z = (UINT32_T)lz->li_tv.vval.v_number;
5353 w = (UINT32_T)lw->li_tv.vval.v_number;
5354
5355 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
5356
5357 lx->li_tv.vval.v_number = (varnumber_T)x;
5358 ly->li_tv.vval.v_number = (varnumber_T)y;
5359 lz->li_tv.vval.v_number = (varnumber_T)z;
5360 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005361 }
5362 else
5363 goto theend;
5364
5365 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005366 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005367 return;
5368
5369theend:
5370 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005371 rettv->v_type = VAR_NUMBER;
5372 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005373}
5374
5375/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005376 * "srand()" function
5377 */
5378 static void
5379f_srand(typval_T *argvars, typval_T *rettv)
5380{
5381 UINT32_T x = 0, z;
5382
5383 if (rettv_list_alloc(rettv) == FAIL)
5384 return;
5385 if (argvars[0].v_type == VAR_UNKNOWN)
5386 {
5387 init_srand(&x);
5388 }
5389 else
5390 {
5391 int error = FALSE;
5392
5393 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
5394 if (error)
5395 return;
5396 }
5397
5398 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5399 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5400 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5401 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
5402}
5403
5404#undef ROTL
5405#undef SPLITMIX32
5406#undef SHUFFLE_XOSHIRO128STARSTAR
5407
5408/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005409 * "range()" function
5410 */
5411 static void
5412f_range(typval_T *argvars, typval_T *rettv)
5413{
5414 varnumber_T start;
5415 varnumber_T end;
5416 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 int error = FALSE;
5418
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005419 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005420 if (argvars[1].v_type == VAR_UNKNOWN)
5421 {
5422 end = start - 1;
5423 start = 0;
5424 }
5425 else
5426 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005427 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005428 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005429 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005430 }
5431
5432 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005433 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005434 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005435 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005436 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005437 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005438 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005439 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005440 list_T *list = rettv->vval.v_list;
5441
5442 // Create a non-materialized list. This is much more efficient and
5443 // works with ":for". If used otherwise range_list_materialize() must
5444 // be called.
5445 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005446 list->lv_u.nonmat.lv_start = start;
5447 list->lv_u.nonmat.lv_end = end;
5448 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005449 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005450 }
5451}
5452
5453/*
5454 * If "list" is a non-materialized list then materialize it now.
5455 */
5456 void
5457range_list_materialize(list_T *list)
5458{
5459 if (list->lv_first == &range_list_item)
5460 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005461 varnumber_T start = list->lv_u.nonmat.lv_start;
5462 varnumber_T end = list->lv_u.nonmat.lv_end;
5463 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005464 varnumber_T i;
5465
5466 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005467 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005468 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005469 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005470 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5471 if (list_append_number(list, (varnumber_T)i) == FAIL)
5472 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005473 }
5474}
5475
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005476 static void
5477return_register(int regname, typval_T *rettv)
5478{
5479 char_u buf[2] = {0, 0};
5480
5481 buf[0] = (char_u)regname;
5482 rettv->v_type = VAR_STRING;
5483 rettv->vval.v_string = vim_strsave(buf);
5484}
5485
5486/*
5487 * "reg_executing()" function
5488 */
5489 static void
5490f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5491{
5492 return_register(reg_executing, rettv);
5493}
5494
5495/*
5496 * "reg_recording()" function
5497 */
5498 static void
5499f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5500{
5501 return_register(reg_recording, rettv);
5502}
5503
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005505/*
5506 * Convert a List to proftime_T.
5507 * Return FAIL when there is something wrong.
5508 */
5509 static int
5510list2proftime(typval_T *arg, proftime_T *tm)
5511{
5512 long n1, n2;
5513 int error = FALSE;
5514
5515 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5516 || arg->vval.v_list->lv_len != 2)
5517 return FAIL;
5518 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5519 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005520# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005521 tm->HighPart = n1;
5522 tm->LowPart = n2;
5523# else
5524 tm->tv_sec = n1;
5525 tm->tv_usec = n2;
5526# endif
5527 return error ? FAIL : OK;
5528}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005529#endif // FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005530
5531/*
5532 * "reltime()" function
5533 */
5534 static void
5535f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5536{
5537#ifdef FEAT_RELTIME
5538 proftime_T res;
5539 proftime_T start;
5540
5541 if (argvars[0].v_type == VAR_UNKNOWN)
5542 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005543 // No arguments: get current time.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544 profile_start(&res);
5545 }
5546 else if (argvars[1].v_type == VAR_UNKNOWN)
5547 {
5548 if (list2proftime(&argvars[0], &res) == FAIL)
5549 return;
5550 profile_end(&res);
5551 }
5552 else
5553 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005554 // Two arguments: compute the difference.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005555 if (list2proftime(&argvars[0], &start) == FAIL
5556 || list2proftime(&argvars[1], &res) == FAIL)
5557 return;
5558 profile_sub(&res, &start);
5559 }
5560
5561 if (rettv_list_alloc(rettv) == OK)
5562 {
5563 long n1, n2;
5564
Bram Moolenaar4f974752019-02-17 17:44:42 +01005565# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005566 n1 = res.HighPart;
5567 n2 = res.LowPart;
5568# else
5569 n1 = res.tv_sec;
5570 n2 = res.tv_usec;
5571# endif
5572 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5573 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5574 }
5575#endif
5576}
5577
5578#ifdef FEAT_FLOAT
5579/*
5580 * "reltimefloat()" function
5581 */
5582 static void
5583f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5584{
5585# ifdef FEAT_RELTIME
5586 proftime_T tm;
5587# endif
5588
5589 rettv->v_type = VAR_FLOAT;
5590 rettv->vval.v_float = 0;
5591# ifdef FEAT_RELTIME
5592 if (list2proftime(&argvars[0], &tm) == OK)
5593 rettv->vval.v_float = profile_float(&tm);
5594# endif
5595}
5596#endif
5597
5598/*
5599 * "reltimestr()" function
5600 */
5601 static void
5602f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5603{
5604#ifdef FEAT_RELTIME
5605 proftime_T tm;
5606#endif
5607
5608 rettv->v_type = VAR_STRING;
5609 rettv->vval.v_string = NULL;
5610#ifdef FEAT_RELTIME
5611 if (list2proftime(&argvars[0], &tm) == OK)
5612 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5613#endif
5614}
5615
5616#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005617 static void
5618make_connection(void)
5619{
5620 if (X_DISPLAY == NULL
5621# ifdef FEAT_GUI
5622 && !gui.in_use
5623# endif
5624 )
5625 {
5626 x_force_connect = TRUE;
5627 setup_term_clip();
5628 x_force_connect = FALSE;
5629 }
5630}
5631
5632 static int
5633check_connection(void)
5634{
5635 make_connection();
5636 if (X_DISPLAY == NULL)
5637 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005638 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005639 return FAIL;
5640 }
5641 return OK;
5642}
5643#endif
5644
5645#ifdef FEAT_CLIENTSERVER
5646 static void
5647remote_common(typval_T *argvars, typval_T *rettv, int expr)
5648{
5649 char_u *server_name;
5650 char_u *keys;
5651 char_u *r = NULL;
5652 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005653 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005654# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005655 HWND w;
5656# else
5657 Window w;
5658# endif
5659
5660 if (check_restricted() || check_secure())
5661 return;
5662
5663# ifdef FEAT_X11
5664 if (check_connection() == FAIL)
5665 return;
5666# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005667 if (argvars[2].v_type != VAR_UNKNOWN
5668 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005669 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005670
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005671 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005672 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005673 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005674 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005675# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005676 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005677# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005678 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5679 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005680# endif
5681 {
5682 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005683 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005684 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005685 vim_free(r);
5686 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005687 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005688 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005689 return;
5690 }
5691
5692 rettv->vval.v_string = r;
5693
5694 if (argvars[2].v_type != VAR_UNKNOWN)
5695 {
5696 dictitem_T v;
5697 char_u str[30];
5698 char_u *idvar;
5699
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005700 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005701 if (idvar != NULL && *idvar != NUL)
5702 {
5703 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5704 v.di_tv.v_type = VAR_STRING;
5705 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005706 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005707 vim_free(v.di_tv.vval.v_string);
5708 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005709 }
5710}
5711#endif
5712
5713/*
5714 * "remote_expr()" function
5715 */
5716 static void
5717f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5718{
5719 rettv->v_type = VAR_STRING;
5720 rettv->vval.v_string = NULL;
5721#ifdef FEAT_CLIENTSERVER
5722 remote_common(argvars, rettv, TRUE);
5723#endif
5724}
5725
5726/*
5727 * "remote_foreground()" function
5728 */
5729 static void
5730f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5731{
5732#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005733# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005734 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005735 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005736 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005737
5738 if (server_name != NULL)
5739 serverForeground(server_name);
5740 }
5741# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005742 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005743 argvars[1].v_type = VAR_STRING;
5744 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5745 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005746 rettv->v_type = VAR_STRING;
5747 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005748 remote_common(argvars, rettv, TRUE);
5749 vim_free(argvars[1].vval.v_string);
5750# endif
5751#endif
5752}
5753
5754 static void
5755f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5756{
5757#ifdef FEAT_CLIENTSERVER
5758 dictitem_T v;
5759 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005760# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005761 long_u n = 0;
5762# endif
5763 char_u *serverid;
5764
5765 if (check_restricted() || check_secure())
5766 {
5767 rettv->vval.v_number = -1;
5768 return;
5769 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005770 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005771 if (serverid == NULL)
5772 {
5773 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005774 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005775 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005776# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005777 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5778 if (n == 0)
5779 rettv->vval.v_number = -1;
5780 else
5781 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005782 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005783 rettv->vval.v_number = (s != NULL);
5784 }
5785# else
5786 if (check_connection() == FAIL)
5787 return;
5788
5789 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5790 serverStrToWin(serverid), &s);
5791# endif
5792
5793 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5794 {
5795 char_u *retvar;
5796
5797 v.di_tv.v_type = VAR_STRING;
5798 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005799 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005800 if (retvar != NULL)
5801 set_var(retvar, &v.di_tv, FALSE);
5802 vim_free(v.di_tv.vval.v_string);
5803 }
5804#else
5805 rettv->vval.v_number = -1;
5806#endif
5807}
5808
5809 static void
5810f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5811{
5812 char_u *r = NULL;
5813
5814#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005815 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005816
5817 if (serverid != NULL && !check_restricted() && !check_secure())
5818 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005819 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005820# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005821 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005822 long_u n = 0;
5823# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005824
5825 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005826 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005827
Bram Moolenaar4f974752019-02-17 17:44:42 +01005828# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5830 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005831 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005832 if (r == NULL)
5833# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005834 if (check_connection() == FAIL
5835 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5836 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005837# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005838 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005839 }
5840#endif
5841 rettv->v_type = VAR_STRING;
5842 rettv->vval.v_string = r;
5843}
5844
5845/*
5846 * "remote_send()" function
5847 */
5848 static void
5849f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5850{
5851 rettv->v_type = VAR_STRING;
5852 rettv->vval.v_string = NULL;
5853#ifdef FEAT_CLIENTSERVER
5854 remote_common(argvars, rettv, FALSE);
5855#endif
5856}
5857
5858/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005859 * "remote_startserver()" function
5860 */
5861 static void
5862f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5863{
5864#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005865 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005866
5867 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005868 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005869 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005870 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005871 else
5872 {
5873# ifdef FEAT_X11
5874 if (check_connection() == OK)
5875 serverRegisterName(X_DISPLAY, server);
5876# else
5877 serverSetName(server);
5878# endif
5879 }
5880#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005881 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005882#endif
5883}
5884
5885/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005886 * "rename({from}, {to})" function
5887 */
5888 static void
5889f_rename(typval_T *argvars, typval_T *rettv)
5890{
5891 char_u buf[NUMBUFLEN];
5892
5893 if (check_restricted() || check_secure())
5894 rettv->vval.v_number = -1;
5895 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005896 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5897 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005898}
5899
5900/*
5901 * "repeat()" function
5902 */
5903 static void
5904f_repeat(typval_T *argvars, typval_T *rettv)
5905{
5906 char_u *p;
5907 int n;
5908 int slen;
5909 int len;
5910 char_u *r;
5911 int i;
5912
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005913 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005914 if (argvars[0].v_type == VAR_LIST)
5915 {
5916 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5917 while (n-- > 0)
5918 if (list_extend(rettv->vval.v_list,
5919 argvars[0].vval.v_list, NULL) == FAIL)
5920 break;
5921 }
5922 else
5923 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005924 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005925 rettv->v_type = VAR_STRING;
5926 rettv->vval.v_string = NULL;
5927
5928 slen = (int)STRLEN(p);
5929 len = slen * n;
5930 if (len <= 0)
5931 return;
5932
5933 r = alloc(len + 1);
5934 if (r != NULL)
5935 {
5936 for (i = 0; i < n; i++)
5937 mch_memmove(r + i * slen, p, (size_t)slen);
5938 r[len] = NUL;
5939 }
5940
5941 rettv->vval.v_string = r;
5942 }
5943}
5944
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005945#define SP_NOMOVE 0x01 // don't move cursor
5946#define SP_REPEAT 0x02 // repeat to find outer pair
5947#define SP_RETCOUNT 0x04 // return matchcount
5948#define SP_SETPCMARK 0x08 // set previous context mark
5949#define SP_START 0x10 // accept match at start position
5950#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5951#define SP_END 0x40 // leave cursor at end of match
5952#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005953
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005954/*
5955 * Get flags for a search function.
5956 * Possibly sets "p_ws".
5957 * Returns BACKWARD, FORWARD or zero (for an error).
5958 */
5959 static int
5960get_search_arg(typval_T *varp, int *flagsp)
5961{
5962 int dir = FORWARD;
5963 char_u *flags;
5964 char_u nbuf[NUMBUFLEN];
5965 int mask;
5966
5967 if (varp->v_type != VAR_UNKNOWN)
5968 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005969 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005970 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005971 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972 while (*flags != NUL)
5973 {
5974 switch (*flags)
5975 {
5976 case 'b': dir = BACKWARD; break;
5977 case 'w': p_ws = TRUE; break;
5978 case 'W': p_ws = FALSE; break;
5979 default: mask = 0;
5980 if (flagsp != NULL)
5981 switch (*flags)
5982 {
5983 case 'c': mask = SP_START; break;
5984 case 'e': mask = SP_END; break;
5985 case 'm': mask = SP_RETCOUNT; break;
5986 case 'n': mask = SP_NOMOVE; break;
5987 case 'p': mask = SP_SUBPAT; break;
5988 case 'r': mask = SP_REPEAT; break;
5989 case 's': mask = SP_SETPCMARK; break;
5990 case 'z': mask = SP_COLUMN; break;
5991 }
5992 if (mask == 0)
5993 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005994 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005995 dir = 0;
5996 }
5997 else
5998 *flagsp |= mask;
5999 }
6000 if (dir == 0)
6001 break;
6002 ++flags;
6003 }
6004 }
6005 return dir;
6006}
6007
6008/*
6009 * Shared by search() and searchpos() functions.
6010 */
6011 static int
6012search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6013{
6014 int flags;
6015 char_u *pat;
6016 pos_T pos;
6017 pos_T save_cursor;
6018 int save_p_ws = p_ws;
6019 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006020 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006021 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006022#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006023 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006024 long time_limit = 0;
6025#endif
6026 int options = SEARCH_KEEP;
6027 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006028 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006029
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006030 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006031 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006032 if (dir == 0)
6033 goto theend;
6034 flags = *flagsp;
6035 if (flags & SP_START)
6036 options |= SEARCH_START;
6037 if (flags & SP_END)
6038 options |= SEARCH_END;
6039 if (flags & SP_COLUMN)
6040 options |= SEARCH_COL;
6041
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006042 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006043 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6044 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006045 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006046 if (lnum_stop < 0)
6047 goto theend;
6048#ifdef FEAT_RELTIME
6049 if (argvars[3].v_type != VAR_UNKNOWN)
6050 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006051 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006052 if (time_limit < 0)
6053 goto theend;
6054 }
6055#endif
6056 }
6057
6058#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006059 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006060 profile_setlimit(time_limit, &tm);
6061#endif
6062
6063 /*
6064 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6065 * Check to make sure only those flags are set.
6066 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6067 * flags cannot be set. Check for that condition also.
6068 */
6069 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6070 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6071 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006072 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006073 goto theend;
6074 }
6075
6076 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006077 vim_memset(&sia, 0, sizeof(sia));
6078 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6079#ifdef FEAT_RELTIME
6080 sia.sa_tm = &tm;
6081#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006082 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006083 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006084 if (subpatnum != FAIL)
6085 {
6086 if (flags & SP_SUBPAT)
6087 retval = subpatnum;
6088 else
6089 retval = pos.lnum;
6090 if (flags & SP_SETPCMARK)
6091 setpcmark();
6092 curwin->w_cursor = pos;
6093 if (match_pos != NULL)
6094 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006095 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006096 match_pos->lnum = pos.lnum;
6097 match_pos->col = pos.col + 1;
6098 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006099 // "/$" will put the cursor after the end of the line, may need to
6100 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006101 check_cursor();
6102 }
6103
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006104 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006105 if (flags & SP_NOMOVE)
6106 curwin->w_cursor = save_cursor;
6107 else
6108 curwin->w_set_curswant = TRUE;
6109theend:
6110 p_ws = save_p_ws;
6111
6112 return retval;
6113}
6114
6115#ifdef FEAT_FLOAT
6116
6117/*
6118 * round() is not in C90, use ceil() or floor() instead.
6119 */
6120 float_T
6121vim_round(float_T f)
6122{
6123 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6124}
6125
6126/*
6127 * "round({float})" function
6128 */
6129 static void
6130f_round(typval_T *argvars, typval_T *rettv)
6131{
6132 float_T f = 0.0;
6133
6134 rettv->v_type = VAR_FLOAT;
6135 if (get_float_arg(argvars, &f) == OK)
6136 rettv->vval.v_float = vim_round(f);
6137 else
6138 rettv->vval.v_float = 0.0;
6139}
6140#endif
6141
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006142#ifdef FEAT_RUBY
6143/*
6144 * "rubyeval()" function
6145 */
6146 static void
6147f_rubyeval(typval_T *argvars, typval_T *rettv)
6148{
6149 char_u *str;
6150 char_u buf[NUMBUFLEN];
6151
6152 str = tv_get_string_buf(&argvars[0], buf);
6153 do_rubyeval(str, rettv);
6154}
6155#endif
6156
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006157/*
6158 * "screenattr()" function
6159 */
6160 static void
6161f_screenattr(typval_T *argvars, typval_T *rettv)
6162{
6163 int row;
6164 int col;
6165 int c;
6166
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006167 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6168 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006169 if (row < 0 || row >= screen_Rows
6170 || col < 0 || col >= screen_Columns)
6171 c = -1;
6172 else
6173 c = ScreenAttrs[LineOffset[row] + col];
6174 rettv->vval.v_number = c;
6175}
6176
6177/*
6178 * "screenchar()" function
6179 */
6180 static void
6181f_screenchar(typval_T *argvars, typval_T *rettv)
6182{
6183 int row;
6184 int col;
6185 int off;
6186 int c;
6187
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006188 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6189 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006190 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006191 c = -1;
6192 else
6193 {
6194 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006195 if (enc_utf8 && ScreenLinesUC[off] != 0)
6196 c = ScreenLinesUC[off];
6197 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006198 c = ScreenLines[off];
6199 }
6200 rettv->vval.v_number = c;
6201}
6202
6203/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006204 * "screenchars()" function
6205 */
6206 static void
6207f_screenchars(typval_T *argvars, typval_T *rettv)
6208{
6209 int row;
6210 int col;
6211 int off;
6212 int c;
6213 int i;
6214
6215 if (rettv_list_alloc(rettv) == FAIL)
6216 return;
6217 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6218 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6219 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6220 return;
6221
6222 off = LineOffset[row] + col;
6223 if (enc_utf8 && ScreenLinesUC[off] != 0)
6224 c = ScreenLinesUC[off];
6225 else
6226 c = ScreenLines[off];
6227 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6228
6229 if (enc_utf8)
6230
6231 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6232 list_append_number(rettv->vval.v_list,
6233 (varnumber_T)ScreenLinesC[i][off]);
6234}
6235
6236/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006237 * "screencol()" function
6238 *
6239 * First column is 1 to be consistent with virtcol().
6240 */
6241 static void
6242f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6243{
6244 rettv->vval.v_number = screen_screencol() + 1;
6245}
6246
6247/*
6248 * "screenrow()" function
6249 */
6250 static void
6251f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6252{
6253 rettv->vval.v_number = screen_screenrow() + 1;
6254}
6255
6256/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006257 * "screenstring()" function
6258 */
6259 static void
6260f_screenstring(typval_T *argvars, typval_T *rettv)
6261{
6262 int row;
6263 int col;
6264 int off;
6265 int c;
6266 int i;
6267 char_u buf[MB_MAXBYTES + 1];
6268 int buflen = 0;
6269
6270 rettv->vval.v_string = NULL;
6271 rettv->v_type = VAR_STRING;
6272
6273 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6274 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6275 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6276 return;
6277
6278 off = LineOffset[row] + col;
6279 if (enc_utf8 && ScreenLinesUC[off] != 0)
6280 c = ScreenLinesUC[off];
6281 else
6282 c = ScreenLines[off];
6283 buflen += mb_char2bytes(c, buf);
6284
6285 if (enc_utf8)
6286 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6287 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6288
6289 buf[buflen] = NUL;
6290 rettv->vval.v_string = vim_strsave(buf);
6291}
6292
6293/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006294 * "search()" function
6295 */
6296 static void
6297f_search(typval_T *argvars, typval_T *rettv)
6298{
6299 int flags = 0;
6300
6301 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6302}
6303
6304/*
6305 * "searchdecl()" function
6306 */
6307 static void
6308f_searchdecl(typval_T *argvars, typval_T *rettv)
6309{
6310 int locally = 1;
6311 int thisblock = 0;
6312 int error = FALSE;
6313 char_u *name;
6314
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006315 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006316
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006317 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006318 if (argvars[1].v_type != VAR_UNKNOWN)
6319 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006320 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006321 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006322 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006323 }
6324 if (!error && name != NULL)
6325 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6326 locally, thisblock, SEARCH_KEEP) == FAIL;
6327}
6328
6329/*
6330 * Used by searchpair() and searchpairpos()
6331 */
6332 static int
6333searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6334{
6335 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006336 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006337 int save_p_ws = p_ws;
6338 int dir;
6339 int flags = 0;
6340 char_u nbuf1[NUMBUFLEN];
6341 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006342 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343 long lnum_stop = 0;
6344 long time_limit = 0;
6345
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006346 // Get the three pattern arguments: start, middle, end. Will result in an
6347 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006348 spat = tv_get_string_chk(&argvars[0]);
6349 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6350 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006351 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006352 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006353
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006354 // Handle the optional fourth argument: flags
6355 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006356 if (dir == 0)
6357 goto theend;
6358
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006359 // Don't accept SP_END or SP_SUBPAT.
6360 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006361 if ((flags & (SP_END | SP_SUBPAT)) != 0
6362 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6363 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006364 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006365 goto theend;
6366 }
6367
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006368 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006369 if (flags & SP_REPEAT)
6370 p_ws = FALSE;
6371
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006372 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373 if (argvars[3].v_type == VAR_UNKNOWN
6374 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006375 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376 else
6377 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006378 skip = &argvars[4];
6379 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6380 && skip->v_type != VAR_STRING)
6381 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006382 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006383 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006384 goto theend;
6385 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006386 if (argvars[5].v_type != VAR_UNKNOWN)
6387 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006388 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006389 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006390 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006391 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006392 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006393 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394#ifdef FEAT_RELTIME
6395 if (argvars[6].v_type != VAR_UNKNOWN)
6396 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006397 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006398 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006399 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006400 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006401 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006402 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006403 }
6404#endif
6405 }
6406 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006407
6408 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6409 match_pos, lnum_stop, time_limit);
6410
6411theend:
6412 p_ws = save_p_ws;
6413
6414 return retval;
6415}
6416
6417/*
6418 * "searchpair()" function
6419 */
6420 static void
6421f_searchpair(typval_T *argvars, typval_T *rettv)
6422{
6423 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6424}
6425
6426/*
6427 * "searchpairpos()" function
6428 */
6429 static void
6430f_searchpairpos(typval_T *argvars, typval_T *rettv)
6431{
6432 pos_T match_pos;
6433 int lnum = 0;
6434 int col = 0;
6435
6436 if (rettv_list_alloc(rettv) == FAIL)
6437 return;
6438
6439 if (searchpair_cmn(argvars, &match_pos) > 0)
6440 {
6441 lnum = match_pos.lnum;
6442 col = match_pos.col;
6443 }
6444
6445 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6446 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6447}
6448
6449/*
6450 * Search for a start/middle/end thing.
6451 * Used by searchpair(), see its documentation for the details.
6452 * Returns 0 or -1 for no match,
6453 */
6454 long
6455do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006456 char_u *spat, // start pattern
6457 char_u *mpat, // middle pattern
6458 char_u *epat, // end pattern
6459 int dir, // BACKWARD or FORWARD
6460 typval_T *skip, // skip expression
6461 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006462 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006463 linenr_T lnum_stop, // stop at this line if not zero
6464 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465{
6466 char_u *save_cpo;
6467 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6468 long retval = 0;
6469 pos_T pos;
6470 pos_T firstpos;
6471 pos_T foundpos;
6472 pos_T save_cursor;
6473 pos_T save_pos;
6474 int n;
6475 int r;
6476 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006477 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006478 int err;
6479 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006480#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006481 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006482#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006483
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006484 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006485 save_cpo = p_cpo;
6486 p_cpo = empty_option;
6487
6488#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006489 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006490 profile_setlimit(time_limit, &tm);
6491#endif
6492
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006493 // Make two search patterns: start/end (pat2, for in nested pairs) and
6494 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006495 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6496 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006497 if (pat2 == NULL || pat3 == NULL)
6498 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006499 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006500 if (*mpat == NUL)
6501 STRCPY(pat3, pat2);
6502 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006503 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504 spat, epat, mpat);
6505 if (flags & SP_START)
6506 options |= SEARCH_START;
6507
Bram Moolenaar48570482017-10-30 21:48:41 +01006508 if (skip != NULL)
6509 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006510 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006511 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6512 use_skip = skip->vval.v_string != NULL
6513 && *skip->vval.v_string != NUL;
6514 }
6515
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006516 save_cursor = curwin->w_cursor;
6517 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006518 CLEAR_POS(&firstpos);
6519 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006520 pat = pat3;
6521 for (;;)
6522 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006523 searchit_arg_T sia;
6524
6525 vim_memset(&sia, 0, sizeof(sia));
6526 sia.sa_stop_lnum = lnum_stop;
6527#ifdef FEAT_RELTIME
6528 sia.sa_tm = &tm;
6529#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006530 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006531 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006532 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006533 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006534 break;
6535
6536 if (firstpos.lnum == 0)
6537 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006538 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006540 // Found the same position again. Can happen with a pattern that
6541 // has "\zs" at the end and searching backwards. Advance one
6542 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006543 if (dir == BACKWARD)
6544 decl(&pos);
6545 else
6546 incl(&pos);
6547 }
6548 foundpos = pos;
6549
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006550 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006551 options &= ~SEARCH_START;
6552
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006553 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006554 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006555 {
6556 save_pos = curwin->w_cursor;
6557 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006558 err = FALSE;
6559 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560 curwin->w_cursor = save_pos;
6561 if (err)
6562 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006563 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006564 curwin->w_cursor = save_cursor;
6565 retval = -1;
6566 break;
6567 }
6568 if (r)
6569 continue;
6570 }
6571
6572 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6573 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006574 // Found end when searching backwards or start when searching
6575 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006576 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006577 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006578 }
6579 else
6580 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006581 // Found end when searching forward or start when searching
6582 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006583 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006584 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006585 }
6586
6587 if (nest == 0)
6588 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006589 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006590 if (flags & SP_RETCOUNT)
6591 ++retval;
6592 else
6593 retval = pos.lnum;
6594 if (flags & SP_SETPCMARK)
6595 setpcmark();
6596 curwin->w_cursor = pos;
6597 if (!(flags & SP_REPEAT))
6598 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006599 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600 }
6601 }
6602
6603 if (match_pos != NULL)
6604 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006605 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006606 match_pos->lnum = curwin->w_cursor.lnum;
6607 match_pos->col = curwin->w_cursor.col + 1;
6608 }
6609
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006610 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006611 if ((flags & SP_NOMOVE) || retval == 0)
6612 curwin->w_cursor = save_cursor;
6613
6614theend:
6615 vim_free(pat2);
6616 vim_free(pat3);
6617 if (p_cpo == empty_option)
6618 p_cpo = save_cpo;
6619 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006620 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006621 free_string_option(save_cpo);
6622
6623 return retval;
6624}
6625
6626/*
6627 * "searchpos()" function
6628 */
6629 static void
6630f_searchpos(typval_T *argvars, typval_T *rettv)
6631{
6632 pos_T match_pos;
6633 int lnum = 0;
6634 int col = 0;
6635 int n;
6636 int flags = 0;
6637
6638 if (rettv_list_alloc(rettv) == FAIL)
6639 return;
6640
6641 n = search_cmn(argvars, &match_pos, &flags);
6642 if (n > 0)
6643 {
6644 lnum = match_pos.lnum;
6645 col = match_pos.col;
6646 }
6647
6648 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6649 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6650 if (flags & SP_SUBPAT)
6651 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6652}
6653
6654 static void
6655f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6656{
6657#ifdef FEAT_CLIENTSERVER
6658 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006659 char_u *server = tv_get_string_chk(&argvars[0]);
6660 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006661
6662 rettv->vval.v_number = -1;
6663 if (server == NULL || reply == NULL)
6664 return;
6665 if (check_restricted() || check_secure())
6666 return;
6667# ifdef FEAT_X11
6668 if (check_connection() == FAIL)
6669 return;
6670# endif
6671
6672 if (serverSendReply(server, reply) < 0)
6673 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006674 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006675 return;
6676 }
6677 rettv->vval.v_number = 0;
6678#else
6679 rettv->vval.v_number = -1;
6680#endif
6681}
6682
6683 static void
6684f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6685{
6686 char_u *r = NULL;
6687
6688#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006689# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006690 r = serverGetVimNames();
6691# else
6692 make_connection();
6693 if (X_DISPLAY != NULL)
6694 r = serverGetVimNames(X_DISPLAY);
6695# endif
6696#endif
6697 rettv->v_type = VAR_STRING;
6698 rettv->vval.v_string = r;
6699}
6700
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 static void
6702f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6703{
6704 dict_T *d;
6705 dictitem_T *di;
6706 char_u *csearch;
6707
6708 if (argvars[0].v_type != VAR_DICT)
6709 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006710 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006711 return;
6712 }
6713
6714 if ((d = argvars[0].vval.v_dict) != NULL)
6715 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006716 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006717 if (csearch != NULL)
6718 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006719 if (enc_utf8)
6720 {
6721 int pcc[MAX_MCO];
6722 int c = utfc_ptr2char(csearch, pcc);
6723
6724 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6725 }
6726 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006727 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006728 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006729 }
6730
6731 di = dict_find(d, (char_u *)"forward", -1);
6732 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006733 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006734 ? FORWARD : BACKWARD);
6735
6736 di = dict_find(d, (char_u *)"until", -1);
6737 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006738 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 }
6740}
6741
6742/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006743 * "setenv()" function
6744 */
6745 static void
6746f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6747{
6748 char_u namebuf[NUMBUFLEN];
6749 char_u valbuf[NUMBUFLEN];
6750 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6751
6752 if (argvars[1].v_type == VAR_SPECIAL
6753 && argvars[1].vval.v_number == VVAL_NULL)
6754 vim_unsetenv(name);
6755 else
6756 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6757}
6758
6759/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006760 * "setfperm({fname}, {mode})" function
6761 */
6762 static void
6763f_setfperm(typval_T *argvars, typval_T *rettv)
6764{
6765 char_u *fname;
6766 char_u modebuf[NUMBUFLEN];
6767 char_u *mode_str;
6768 int i;
6769 int mask;
6770 int mode = 0;
6771
6772 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006773 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006774 if (fname == NULL)
6775 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006776 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006777 if (mode_str == NULL)
6778 return;
6779 if (STRLEN(mode_str) != 9)
6780 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006781 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006782 return;
6783 }
6784
6785 mask = 1;
6786 for (i = 8; i >= 0; --i)
6787 {
6788 if (mode_str[i] != '-')
6789 mode |= mask;
6790 mask = mask << 1;
6791 }
6792 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6793}
6794
6795/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 * "setpos()" function
6797 */
6798 static void
6799f_setpos(typval_T *argvars, typval_T *rettv)
6800{
6801 pos_T pos;
6802 int fnum;
6803 char_u *name;
6804 colnr_T curswant = -1;
6805
6806 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006807 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006808 if (name != NULL)
6809 {
6810 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6811 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006812 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006813 pos.col = 0;
6814 if (name[0] == '.' && name[1] == NUL)
6815 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006816 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006817 curwin->w_cursor = pos;
6818 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006819 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006820 curwin->w_curswant = curswant - 1;
6821 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006822 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006823 check_cursor();
6824 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006825 }
6826 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6827 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006828 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006829 if (setmark_pos(name[1], &pos, fnum) == OK)
6830 rettv->vval.v_number = 0;
6831 }
6832 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006833 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834 }
6835 }
6836}
6837
6838/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006839 * "setreg()" function
6840 */
6841 static void
6842f_setreg(typval_T *argvars, typval_T *rettv)
6843{
6844 int regname;
6845 char_u *strregname;
6846 char_u *stropt;
6847 char_u *strval;
6848 int append;
6849 char_u yank_type;
6850 long block_len;
6851
6852 block_len = -1;
6853 yank_type = MAUTO;
6854 append = FALSE;
6855
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006856 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006857 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006858
6859 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006860 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006861 regname = *strregname;
6862 if (regname == 0 || regname == '@')
6863 regname = '"';
6864
6865 if (argvars[2].v_type != VAR_UNKNOWN)
6866 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006867 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006868 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006869 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006870 for (; *stropt != NUL; ++stropt)
6871 switch (*stropt)
6872 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006873 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006874 append = TRUE;
6875 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006876 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006877 yank_type = MCHAR;
6878 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006879 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 yank_type = MLINE;
6881 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006882 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883 yank_type = MBLOCK;
6884 if (VIM_ISDIGIT(stropt[1]))
6885 {
6886 ++stropt;
6887 block_len = getdigits(&stropt) - 1;
6888 --stropt;
6889 }
6890 break;
6891 }
6892 }
6893
6894 if (argvars[1].v_type == VAR_LIST)
6895 {
6896 char_u **lstval;
6897 char_u **allocval;
6898 char_u buf[NUMBUFLEN];
6899 char_u **curval;
6900 char_u **curallocval;
6901 list_T *ll = argvars[1].vval.v_list;
6902 listitem_T *li;
6903 int len;
6904
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006905 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006906 len = ll == NULL ? 0 : ll->lv_len;
6907
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006908 // First half: use for pointers to result lines; second half: use for
6909 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006910 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006911 if (lstval == NULL)
6912 return;
6913 curval = lstval;
6914 allocval = lstval + len + 2;
6915 curallocval = allocval;
6916
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006917 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006918 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006919 range_list_materialize(ll);
6920 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006921 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006922 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006923 if (strval == NULL)
6924 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006925 if (strval == buf)
6926 {
6927 // Need to make a copy, next tv_get_string_buf_chk() will
6928 // overwrite the string.
6929 strval = vim_strsave(buf);
6930 if (strval == NULL)
6931 goto free_lstval;
6932 *curallocval++ = strval;
6933 }
6934 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006935 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006936 }
6937 *curval++ = NULL;
6938
6939 write_reg_contents_lst(regname, lstval, -1,
6940 append, yank_type, block_len);
6941free_lstval:
6942 while (curallocval > allocval)
6943 vim_free(*--curallocval);
6944 vim_free(lstval);
6945 }
6946 else
6947 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006948 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006949 if (strval == NULL)
6950 return;
6951 write_reg_contents_ex(regname, strval, -1,
6952 append, yank_type, block_len);
6953 }
6954 rettv->vval.v_number = 0;
6955}
6956
6957/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006958 * "settagstack()" function
6959 */
6960 static void
6961f_settagstack(typval_T *argvars, typval_T *rettv)
6962{
6963 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6964 win_T *wp;
6965 dict_T *d;
6966 int action = 'r';
6967
6968 rettv->vval.v_number = -1;
6969
6970 // first argument: window number or id
6971 wp = find_win_by_nr_or_id(&argvars[0]);
6972 if (wp == NULL)
6973 return;
6974
6975 // second argument: dict with items to set in the tag stack
6976 if (argvars[1].v_type != VAR_DICT)
6977 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006978 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006979 return;
6980 }
6981 d = argvars[1].vval.v_dict;
6982 if (d == NULL)
6983 return;
6984
6985 // third argument: action - 'a' for append and 'r' for replace.
6986 // default is to replace the stack.
6987 if (argvars[2].v_type == VAR_UNKNOWN)
6988 action = 'r';
6989 else if (argvars[2].v_type == VAR_STRING)
6990 {
6991 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006992 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006993 if (actstr == NULL)
6994 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006995 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6996 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006997 action = *actstr;
6998 else
6999 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007000 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007001 return;
7002 }
7003 }
7004 else
7005 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007006 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007007 return;
7008 }
7009
7010 if (set_tagstack(wp, d, action) == OK)
7011 rettv->vval.v_number = 0;
7012}
7013
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007014#ifdef FEAT_CRYPT
7015/*
7016 * "sha256({string})" function
7017 */
7018 static void
7019f_sha256(typval_T *argvars, typval_T *rettv)
7020{
7021 char_u *p;
7022
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007023 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024 rettv->vval.v_string = vim_strsave(
7025 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7026 rettv->v_type = VAR_STRING;
7027}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007028#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007029
7030/*
7031 * "shellescape({string})" function
7032 */
7033 static void
7034f_shellescape(typval_T *argvars, typval_T *rettv)
7035{
Bram Moolenaar20615522017-06-05 18:46:26 +02007036 int do_special = non_zero_arg(&argvars[1]);
7037
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007039 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007040 rettv->v_type = VAR_STRING;
7041}
7042
7043/*
7044 * shiftwidth() function
7045 */
7046 static void
7047f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7048{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007049 rettv->vval.v_number = 0;
7050
7051 if (argvars[0].v_type != VAR_UNKNOWN)
7052 {
7053 long col;
7054
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007055 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007056 if (col < 0)
7057 return; // type error; errmsg already given
7058#ifdef FEAT_VARTABS
7059 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7060 return;
7061#endif
7062 }
7063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007064 rettv->vval.v_number = get_sw_value(curbuf);
7065}
7066
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007067#ifdef FEAT_FLOAT
7068/*
7069 * "sin()" function
7070 */
7071 static void
7072f_sin(typval_T *argvars, typval_T *rettv)
7073{
7074 float_T f = 0.0;
7075
7076 rettv->v_type = VAR_FLOAT;
7077 if (get_float_arg(argvars, &f) == OK)
7078 rettv->vval.v_float = sin(f);
7079 else
7080 rettv->vval.v_float = 0.0;
7081}
7082
7083/*
7084 * "sinh()" function
7085 */
7086 static void
7087f_sinh(typval_T *argvars, typval_T *rettv)
7088{
7089 float_T f = 0.0;
7090
7091 rettv->v_type = VAR_FLOAT;
7092 if (get_float_arg(argvars, &f) == OK)
7093 rettv->vval.v_float = sinh(f);
7094 else
7095 rettv->vval.v_float = 0.0;
7096}
7097#endif
7098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007099/*
7100 * "soundfold({word})" function
7101 */
7102 static void
7103f_soundfold(typval_T *argvars, typval_T *rettv)
7104{
7105 char_u *s;
7106
7107 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007108 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007109#ifdef FEAT_SPELL
7110 rettv->vval.v_string = eval_soundfold(s);
7111#else
7112 rettv->vval.v_string = vim_strsave(s);
7113#endif
7114}
7115
7116/*
7117 * "spellbadword()" function
7118 */
7119 static void
7120f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7121{
7122 char_u *word = (char_u *)"";
7123 hlf_T attr = HLF_COUNT;
7124 int len = 0;
7125
7126 if (rettv_list_alloc(rettv) == FAIL)
7127 return;
7128
7129#ifdef FEAT_SPELL
7130 if (argvars[0].v_type == VAR_UNKNOWN)
7131 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007132 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007133 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7134 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007135 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007137 curwin->w_set_curswant = TRUE;
7138 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007139 }
7140 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7141 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007142 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007143 int capcol = -1;
7144
7145 if (str != NULL)
7146 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007147 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 while (*str != NUL)
7149 {
7150 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7151 if (attr != HLF_COUNT)
7152 {
7153 word = str;
7154 break;
7155 }
7156 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007157 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007158 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007159 }
7160 }
7161 }
7162#endif
7163
7164 list_append_string(rettv->vval.v_list, word, len);
7165 list_append_string(rettv->vval.v_list, (char_u *)(
7166 attr == HLF_SPB ? "bad" :
7167 attr == HLF_SPR ? "rare" :
7168 attr == HLF_SPL ? "local" :
7169 attr == HLF_SPC ? "caps" :
7170 ""), -1);
7171}
7172
7173/*
7174 * "spellsuggest()" function
7175 */
7176 static void
7177f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7178{
7179#ifdef FEAT_SPELL
7180 char_u *str;
7181 int typeerr = FALSE;
7182 int maxcount;
7183 garray_T ga;
7184 int i;
7185 listitem_T *li;
7186 int need_capital = FALSE;
7187#endif
7188
7189 if (rettv_list_alloc(rettv) == FAIL)
7190 return;
7191
7192#ifdef FEAT_SPELL
7193 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7194 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007195 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007196 if (argvars[1].v_type != VAR_UNKNOWN)
7197 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007198 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007199 if (maxcount <= 0)
7200 return;
7201 if (argvars[2].v_type != VAR_UNKNOWN)
7202 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007203 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007204 if (typeerr)
7205 return;
7206 }
7207 }
7208 else
7209 maxcount = 25;
7210
7211 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7212
7213 for (i = 0; i < ga.ga_len; ++i)
7214 {
7215 str = ((char_u **)ga.ga_data)[i];
7216
7217 li = listitem_alloc();
7218 if (li == NULL)
7219 vim_free(str);
7220 else
7221 {
7222 li->li_tv.v_type = VAR_STRING;
7223 li->li_tv.v_lock = 0;
7224 li->li_tv.vval.v_string = str;
7225 list_append(rettv->vval.v_list, li);
7226 }
7227 }
7228 ga_clear(&ga);
7229 }
7230#endif
7231}
7232
7233 static void
7234f_split(typval_T *argvars, typval_T *rettv)
7235{
7236 char_u *str;
7237 char_u *end;
7238 char_u *pat = NULL;
7239 regmatch_T regmatch;
7240 char_u patbuf[NUMBUFLEN];
7241 char_u *save_cpo;
7242 int match;
7243 colnr_T col = 0;
7244 int keepempty = FALSE;
7245 int typeerr = FALSE;
7246
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007247 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007248 save_cpo = p_cpo;
7249 p_cpo = (char_u *)"";
7250
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007251 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007252 if (argvars[1].v_type != VAR_UNKNOWN)
7253 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007254 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255 if (pat == NULL)
7256 typeerr = TRUE;
7257 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007258 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007259 }
7260 if (pat == NULL || *pat == NUL)
7261 pat = (char_u *)"[\\x01- ]\\+";
7262
7263 if (rettv_list_alloc(rettv) == FAIL)
7264 return;
7265 if (typeerr)
7266 return;
7267
7268 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7269 if (regmatch.regprog != NULL)
7270 {
7271 regmatch.rm_ic = FALSE;
7272 while (*str != NUL || keepempty)
7273 {
7274 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007275 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007276 else
7277 match = vim_regexec_nl(&regmatch, str, col);
7278 if (match)
7279 end = regmatch.startp[0];
7280 else
7281 end = str + STRLEN(str);
7282 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7283 && *str != NUL && match && end < regmatch.endp[0]))
7284 {
7285 if (list_append_string(rettv->vval.v_list, str,
7286 (int)(end - str)) == FAIL)
7287 break;
7288 }
7289 if (!match)
7290 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007291 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007292 if (regmatch.endp[0] > str)
7293 col = 0;
7294 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007295 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007296 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007297 str = regmatch.endp[0];
7298 }
7299
7300 vim_regfree(regmatch.regprog);
7301 }
7302
7303 p_cpo = save_cpo;
7304}
7305
7306#ifdef FEAT_FLOAT
7307/*
7308 * "sqrt()" function
7309 */
7310 static void
7311f_sqrt(typval_T *argvars, typval_T *rettv)
7312{
7313 float_T f = 0.0;
7314
7315 rettv->v_type = VAR_FLOAT;
7316 if (get_float_arg(argvars, &f) == OK)
7317 rettv->vval.v_float = sqrt(f);
7318 else
7319 rettv->vval.v_float = 0.0;
7320}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007321#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007322
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007323#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007324/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007325 * "str2float()" function
7326 */
7327 static void
7328f_str2float(typval_T *argvars, typval_T *rettv)
7329{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007330 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007331 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007332
Bram Moolenaar08243d22017-01-10 16:12:29 +01007333 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007334 p = skipwhite(p + 1);
7335 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007336 if (isneg)
7337 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007338 rettv->v_type = VAR_FLOAT;
7339}
7340#endif
7341
7342/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007343 * "str2list()" function
7344 */
7345 static void
7346f_str2list(typval_T *argvars, typval_T *rettv)
7347{
7348 char_u *p;
7349 int utf8 = FALSE;
7350
7351 if (rettv_list_alloc(rettv) == FAIL)
7352 return;
7353
7354 if (argvars[1].v_type != VAR_UNKNOWN)
7355 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7356
7357 p = tv_get_string(&argvars[0]);
7358
7359 if (has_mbyte || utf8)
7360 {
7361 int (*ptr2len)(char_u *);
7362 int (*ptr2char)(char_u *);
7363
7364 if (utf8 || enc_utf8)
7365 {
7366 ptr2len = utf_ptr2len;
7367 ptr2char = utf_ptr2char;
7368 }
7369 else
7370 {
7371 ptr2len = mb_ptr2len;
7372 ptr2char = mb_ptr2char;
7373 }
7374
7375 for ( ; *p != NUL; p += (*ptr2len)(p))
7376 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7377 }
7378 else
7379 for ( ; *p != NUL; ++p)
7380 list_append_number(rettv->vval.v_list, *p);
7381}
7382
7383/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007384 * "str2nr()" function
7385 */
7386 static void
7387f_str2nr(typval_T *argvars, typval_T *rettv)
7388{
7389 int base = 10;
7390 char_u *p;
7391 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007392 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007393 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007394
7395 if (argvars[1].v_type != VAR_UNKNOWN)
7396 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007397 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398 if (base != 2 && base != 8 && base != 10 && base != 16)
7399 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007400 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007401 return;
7402 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007403 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7404 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405 }
7406
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007407 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007408 isneg = (*p == '-');
7409 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007410 p = skipwhite(p + 1);
7411 switch (base)
7412 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007413 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7414 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7415 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007416 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007417 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7418 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007419 if (isneg)
7420 rettv->vval.v_number = -n;
7421 else
7422 rettv->vval.v_number = n;
7423
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007424}
7425
7426#ifdef HAVE_STRFTIME
7427/*
7428 * "strftime({format}[, {time}])" function
7429 */
7430 static void
7431f_strftime(typval_T *argvars, typval_T *rettv)
7432{
7433 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007434 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007435 struct tm *curtime;
7436 time_t seconds;
7437 char_u *p;
7438
7439 rettv->v_type = VAR_STRING;
7440
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007441 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007442 if (argvars[1].v_type == VAR_UNKNOWN)
7443 seconds = time(NULL);
7444 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007445 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007446 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007447 // MSVC returns NULL for an invalid value of seconds.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007448 if (curtime == NULL)
7449 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7450 else
7451 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007452 vimconv_T conv;
7453 char_u *enc;
7454
7455 conv.vc_type = CONV_NONE;
7456 enc = enc_locale();
7457 convert_setup(&conv, p_enc, enc);
7458 if (conv.vc_type != CONV_NONE)
7459 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007460 if (p != NULL)
7461 (void)strftime((char *)result_buf, sizeof(result_buf),
7462 (char *)p, curtime);
7463 else
7464 result_buf[0] = NUL;
7465
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007466 if (conv.vc_type != CONV_NONE)
7467 vim_free(p);
7468 convert_setup(&conv, enc, p_enc);
7469 if (conv.vc_type != CONV_NONE)
7470 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7471 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007472 rettv->vval.v_string = vim_strsave(result_buf);
7473
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007474 // Release conversion descriptors
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007475 convert_setup(&conv, NULL, NULL);
7476 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007477 }
7478}
7479#endif
7480
7481/*
7482 * "strgetchar()" function
7483 */
7484 static void
7485f_strgetchar(typval_T *argvars, typval_T *rettv)
7486{
7487 char_u *str;
7488 int len;
7489 int error = FALSE;
7490 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007491 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007492
7493 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007494 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495 if (str == NULL)
7496 return;
7497 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007498 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007499 if (error)
7500 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501
Bram Moolenaar13505972019-01-24 15:04:48 +01007502 while (charidx >= 0 && byteidx < len)
7503 {
7504 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007505 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007506 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7507 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007508 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007509 --charidx;
7510 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007511 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007512}
7513
7514/*
7515 * "stridx()" function
7516 */
7517 static void
7518f_stridx(typval_T *argvars, typval_T *rettv)
7519{
7520 char_u buf[NUMBUFLEN];
7521 char_u *needle;
7522 char_u *haystack;
7523 char_u *save_haystack;
7524 char_u *pos;
7525 int start_idx;
7526
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007527 needle = tv_get_string_chk(&argvars[1]);
7528 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529 rettv->vval.v_number = -1;
7530 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007531 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532
7533 if (argvars[2].v_type != VAR_UNKNOWN)
7534 {
7535 int error = FALSE;
7536
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007537 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007538 if (error || start_idx >= (int)STRLEN(haystack))
7539 return;
7540 if (start_idx >= 0)
7541 haystack += start_idx;
7542 }
7543
7544 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7545 if (pos != NULL)
7546 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7547}
7548
7549/*
7550 * "string()" function
7551 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007552 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007553f_string(typval_T *argvars, typval_T *rettv)
7554{
7555 char_u *tofree;
7556 char_u numbuf[NUMBUFLEN];
7557
7558 rettv->v_type = VAR_STRING;
7559 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7560 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007561 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007562 if (rettv->vval.v_string != NULL && tofree == NULL)
7563 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7564}
7565
7566/*
7567 * "strlen()" function
7568 */
7569 static void
7570f_strlen(typval_T *argvars, typval_T *rettv)
7571{
7572 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007573 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007574}
7575
7576/*
7577 * "strchars()" function
7578 */
7579 static void
7580f_strchars(typval_T *argvars, typval_T *rettv)
7581{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007582 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007583 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007584 varnumber_T len = 0;
7585 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007586
7587 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007588 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007589 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007590 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007591 else
7592 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007593 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7594 while (*s != NUL)
7595 {
7596 func_mb_ptr2char_adv(&s);
7597 ++len;
7598 }
7599 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600 }
7601}
7602
7603/*
7604 * "strdisplaywidth()" function
7605 */
7606 static void
7607f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7608{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007609 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 int col = 0;
7611
7612 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007613 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007614
7615 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7616}
7617
7618/*
7619 * "strwidth()" function
7620 */
7621 static void
7622f_strwidth(typval_T *argvars, typval_T *rettv)
7623{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007624 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007625
Bram Moolenaar13505972019-01-24 15:04:48 +01007626 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627}
7628
7629/*
7630 * "strcharpart()" function
7631 */
7632 static void
7633f_strcharpart(typval_T *argvars, typval_T *rettv)
7634{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007635 char_u *p;
7636 int nchar;
7637 int nbyte = 0;
7638 int charlen;
7639 int len = 0;
7640 int slen;
7641 int error = FALSE;
7642
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007643 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007644 slen = (int)STRLEN(p);
7645
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007646 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 if (!error)
7648 {
7649 if (nchar > 0)
7650 while (nchar > 0 && nbyte < slen)
7651 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007652 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007653 --nchar;
7654 }
7655 else
7656 nbyte = nchar;
7657 if (argvars[2].v_type != VAR_UNKNOWN)
7658 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007659 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007660 while (charlen > 0 && nbyte + len < slen)
7661 {
7662 int off = nbyte + len;
7663
7664 if (off < 0)
7665 len += 1;
7666 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007667 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007668 --charlen;
7669 }
7670 }
7671 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007672 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007673 }
7674
7675 /*
7676 * Only return the overlap between the specified part and the actual
7677 * string.
7678 */
7679 if (nbyte < 0)
7680 {
7681 len += nbyte;
7682 nbyte = 0;
7683 }
7684 else if (nbyte > slen)
7685 nbyte = slen;
7686 if (len < 0)
7687 len = 0;
7688 else if (nbyte + len > slen)
7689 len = slen - nbyte;
7690
7691 rettv->v_type = VAR_STRING;
7692 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007693}
7694
7695/*
7696 * "strpart()" function
7697 */
7698 static void
7699f_strpart(typval_T *argvars, typval_T *rettv)
7700{
7701 char_u *p;
7702 int n;
7703 int len;
7704 int slen;
7705 int error = FALSE;
7706
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007707 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007708 slen = (int)STRLEN(p);
7709
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007710 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007711 if (error)
7712 len = 0;
7713 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007714 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007715 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007716 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717
7718 /*
7719 * Only return the overlap between the specified part and the actual
7720 * string.
7721 */
7722 if (n < 0)
7723 {
7724 len += n;
7725 n = 0;
7726 }
7727 else if (n > slen)
7728 n = slen;
7729 if (len < 0)
7730 len = 0;
7731 else if (n + len > slen)
7732 len = slen - n;
7733
7734 rettv->v_type = VAR_STRING;
7735 rettv->vval.v_string = vim_strnsave(p + n, len);
7736}
7737
Bram Moolenaar10455d42019-11-21 15:36:18 +01007738#ifdef HAVE_STRPTIME
7739/*
7740 * "strptime({format}, {timestring})" function
7741 */
7742 static void
7743f_strptime(typval_T *argvars, typval_T *rettv)
7744{
7745 struct tm tmval;
7746 char_u *fmt;
7747 char_u *str;
7748 vimconv_T conv;
7749 char_u *enc;
7750
7751 vim_memset(&tmval, NUL, sizeof(tmval));
7752 fmt = tv_get_string(&argvars[0]);
7753 str = tv_get_string(&argvars[1]);
7754
7755 conv.vc_type = CONV_NONE;
7756 enc = enc_locale();
7757 convert_setup(&conv, p_enc, enc);
7758 if (conv.vc_type != CONV_NONE)
7759 fmt = string_convert(&conv, fmt, NULL);
7760 if (fmt == NULL
7761 || strptime((char *)str, (char *)fmt, &tmval) == NULL
7762 || (rettv->vval.v_number = mktime(&tmval)) == -1)
7763 rettv->vval.v_number = 0;
7764
7765 if (conv.vc_type != CONV_NONE)
7766 vim_free(fmt);
7767 convert_setup(&conv, NULL, NULL);
7768 vim_free(enc);
7769}
7770#endif
7771
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007772/*
7773 * "strridx()" function
7774 */
7775 static void
7776f_strridx(typval_T *argvars, typval_T *rettv)
7777{
7778 char_u buf[NUMBUFLEN];
7779 char_u *needle;
7780 char_u *haystack;
7781 char_u *rest;
7782 char_u *lastmatch = NULL;
7783 int haystack_len, end_idx;
7784
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007785 needle = tv_get_string_chk(&argvars[1]);
7786 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007787
7788 rettv->vval.v_number = -1;
7789 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007790 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007791
7792 haystack_len = (int)STRLEN(haystack);
7793 if (argvars[2].v_type != VAR_UNKNOWN)
7794 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007795 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007796 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007797 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007798 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007799 }
7800 else
7801 end_idx = haystack_len;
7802
7803 if (*needle == NUL)
7804 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007805 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007806 lastmatch = haystack + end_idx;
7807 }
7808 else
7809 {
7810 for (rest = haystack; *rest != '\0'; ++rest)
7811 {
7812 rest = (char_u *)strstr((char *)rest, (char *)needle);
7813 if (rest == NULL || rest > haystack + end_idx)
7814 break;
7815 lastmatch = rest;
7816 }
7817 }
7818
7819 if (lastmatch == NULL)
7820 rettv->vval.v_number = -1;
7821 else
7822 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7823}
7824
7825/*
7826 * "strtrans()" function
7827 */
7828 static void
7829f_strtrans(typval_T *argvars, typval_T *rettv)
7830{
7831 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007832 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007833}
7834
7835/*
7836 * "submatch()" function
7837 */
7838 static void
7839f_submatch(typval_T *argvars, typval_T *rettv)
7840{
7841 int error = FALSE;
7842 int no;
7843 int retList = 0;
7844
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007845 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846 if (error)
7847 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007848 if (no < 0 || no >= NSUBEXP)
7849 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007850 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007851 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007852 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007853 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007854 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007855 if (error)
7856 return;
7857
7858 if (retList == 0)
7859 {
7860 rettv->v_type = VAR_STRING;
7861 rettv->vval.v_string = reg_submatch(no);
7862 }
7863 else
7864 {
7865 rettv->v_type = VAR_LIST;
7866 rettv->vval.v_list = reg_submatch_list(no);
7867 }
7868}
7869
7870/*
7871 * "substitute()" function
7872 */
7873 static void
7874f_substitute(typval_T *argvars, typval_T *rettv)
7875{
7876 char_u patbuf[NUMBUFLEN];
7877 char_u subbuf[NUMBUFLEN];
7878 char_u flagsbuf[NUMBUFLEN];
7879
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007880 char_u *str = tv_get_string_chk(&argvars[0]);
7881 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007882 char_u *sub = NULL;
7883 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007884 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007886 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7887 expr = &argvars[2];
7888 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007889 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007890
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007891 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007892 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7893 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007894 rettv->vval.v_string = NULL;
7895 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007896 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007897}
7898
7899/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007900 * "swapinfo(swap_filename)" function
7901 */
7902 static void
7903f_swapinfo(typval_T *argvars, typval_T *rettv)
7904{
7905 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007906 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007907}
7908
7909/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007910 * "swapname(expr)" function
7911 */
7912 static void
7913f_swapname(typval_T *argvars, typval_T *rettv)
7914{
7915 buf_T *buf;
7916
7917 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007918 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007919 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7920 || buf->b_ml.ml_mfp->mf_fname == NULL)
7921 rettv->vval.v_string = NULL;
7922 else
7923 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7924}
7925
7926/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007927 * "synID(lnum, col, trans)" function
7928 */
7929 static void
7930f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7931{
7932 int id = 0;
7933#ifdef FEAT_SYN_HL
7934 linenr_T lnum;
7935 colnr_T col;
7936 int trans;
7937 int transerr = FALSE;
7938
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007939 lnum = tv_get_lnum(argvars); // -1 on type error
7940 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007941 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942
7943 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7944 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7945 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7946#endif
7947
7948 rettv->vval.v_number = id;
7949}
7950
7951/*
7952 * "synIDattr(id, what [, mode])" function
7953 */
7954 static void
7955f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7956{
7957 char_u *p = NULL;
7958#ifdef FEAT_SYN_HL
7959 int id;
7960 char_u *what;
7961 char_u *mode;
7962 char_u modebuf[NUMBUFLEN];
7963 int modec;
7964
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007965 id = (int)tv_get_number(&argvars[0]);
7966 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007967 if (argvars[2].v_type != VAR_UNKNOWN)
7968 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007969 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007970 modec = TOLOWER_ASC(mode[0]);
7971 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007972 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007973 }
7974 else
7975 {
7976#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7977 if (USE_24BIT)
7978 modec = 'g';
7979 else
7980#endif
7981 if (t_colors > 1)
7982 modec = 'c';
7983 else
7984 modec = 't';
7985 }
7986
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987 switch (TOLOWER_ASC(what[0]))
7988 {
7989 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007990 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007991 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007992 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 p = highlight_has_attr(id, HL_BOLD, modec);
7994 break;
7995
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007996 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997 p = highlight_color(id, what, modec);
7998 break;
7999
8000 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008001 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008002 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008003 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004 p = highlight_has_attr(id, HL_ITALIC, modec);
8005 break;
8006
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008007 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008008 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009 break;
8010
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008011 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008012 p = highlight_has_attr(id, HL_INVERSE, modec);
8013 break;
8014
8015 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008016 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008017 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008018 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008019 else if (TOLOWER_ASC(what[1]) == 't' &&
8020 TOLOWER_ASC(what[2]) == 'r')
8021 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008022 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023 p = highlight_has_attr(id, HL_STANDOUT, modec);
8024 break;
8025
8026 case 'u':
8027 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008028 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008029 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8030 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008031 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008032 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8033 break;
8034 }
8035
8036 if (p != NULL)
8037 p = vim_strsave(p);
8038#endif
8039 rettv->v_type = VAR_STRING;
8040 rettv->vval.v_string = p;
8041}
8042
8043/*
8044 * "synIDtrans(id)" function
8045 */
8046 static void
8047f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8048{
8049 int id;
8050
8051#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008052 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053
8054 if (id > 0)
8055 id = syn_get_final_id(id);
8056 else
8057#endif
8058 id = 0;
8059
8060 rettv->vval.v_number = id;
8061}
8062
8063/*
8064 * "synconcealed(lnum, col)" function
8065 */
8066 static void
8067f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8068{
8069#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8070 linenr_T lnum;
8071 colnr_T col;
8072 int syntax_flags = 0;
8073 int cchar;
8074 int matchid = 0;
8075 char_u str[NUMBUFLEN];
8076#endif
8077
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008078 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008079
8080#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008081 lnum = tv_get_lnum(argvars); // -1 on type error
8082 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083
8084 vim_memset(str, NUL, sizeof(str));
8085
8086 if (rettv_list_alloc(rettv) != FAIL)
8087 {
8088 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8089 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8090 && curwin->w_p_cole > 0)
8091 {
8092 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8093 syntax_flags = get_syntax_info(&matchid);
8094
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008095 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008096 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8097 {
8098 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008099 if (cchar == NUL && curwin->w_p_cole == 1)
8100 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008101 if (cchar != NUL)
8102 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008103 if (has_mbyte)
8104 (*mb_char2bytes)(cchar, str);
8105 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106 str[0] = cchar;
8107 }
8108 }
8109 }
8110
8111 list_append_number(rettv->vval.v_list,
8112 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008113 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008114 list_append_string(rettv->vval.v_list, str, -1);
8115 list_append_number(rettv->vval.v_list, matchid);
8116 }
8117#endif
8118}
8119
8120/*
8121 * "synstack(lnum, col)" function
8122 */
8123 static void
8124f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8125{
8126#ifdef FEAT_SYN_HL
8127 linenr_T lnum;
8128 colnr_T col;
8129 int i;
8130 int id;
8131#endif
8132
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008133 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008134
8135#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008136 lnum = tv_get_lnum(argvars); // -1 on type error
8137 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008138
8139 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8140 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8141 && rettv_list_alloc(rettv) != FAIL)
8142 {
8143 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8144 for (i = 0; ; ++i)
8145 {
8146 id = syn_get_stack_item(i);
8147 if (id < 0)
8148 break;
8149 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8150 break;
8151 }
8152 }
8153#endif
8154}
8155
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008156/*
8157 * "tabpagebuflist()" function
8158 */
8159 static void
8160f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8161{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008162 tabpage_T *tp;
8163 win_T *wp = NULL;
8164
8165 if (argvars[0].v_type == VAR_UNKNOWN)
8166 wp = firstwin;
8167 else
8168 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008169 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008170 if (tp != NULL)
8171 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8172 }
8173 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8174 {
8175 for (; wp != NULL; wp = wp->w_next)
8176 if (list_append_number(rettv->vval.v_list,
8177 wp->w_buffer->b_fnum) == FAIL)
8178 break;
8179 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008180}
8181
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008183 * "tagfiles()" function
8184 */
8185 static void
8186f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8187{
8188 char_u *fname;
8189 tagname_T tn;
8190 int first;
8191
8192 if (rettv_list_alloc(rettv) == FAIL)
8193 return;
8194 fname = alloc(MAXPATHL);
8195 if (fname == NULL)
8196 return;
8197
8198 for (first = TRUE; ; first = FALSE)
8199 if (get_tagfname(&tn, first, fname) == FAIL
8200 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8201 break;
8202 tagname_free(&tn);
8203 vim_free(fname);
8204}
8205
8206/*
8207 * "taglist()" function
8208 */
8209 static void
8210f_taglist(typval_T *argvars, typval_T *rettv)
8211{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008212 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213 char_u *tag_pattern;
8214
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008215 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008216
8217 rettv->vval.v_number = FALSE;
8218 if (*tag_pattern == NUL)
8219 return;
8220
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008221 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008222 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008223 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008224 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225}
8226
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008227#ifdef FEAT_FLOAT
8228/*
8229 * "tan()" function
8230 */
8231 static void
8232f_tan(typval_T *argvars, typval_T *rettv)
8233{
8234 float_T f = 0.0;
8235
8236 rettv->v_type = VAR_FLOAT;
8237 if (get_float_arg(argvars, &f) == OK)
8238 rettv->vval.v_float = tan(f);
8239 else
8240 rettv->vval.v_float = 0.0;
8241}
8242
8243/*
8244 * "tanh()" function
8245 */
8246 static void
8247f_tanh(typval_T *argvars, typval_T *rettv)
8248{
8249 float_T f = 0.0;
8250
8251 rettv->v_type = VAR_FLOAT;
8252 if (get_float_arg(argvars, &f) == OK)
8253 rettv->vval.v_float = tanh(f);
8254 else
8255 rettv->vval.v_float = 0.0;
8256}
8257#endif
8258
8259/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008260 * "tolower(string)" function
8261 */
8262 static void
8263f_tolower(typval_T *argvars, typval_T *rettv)
8264{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008265 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008266 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008267}
8268
8269/*
8270 * "toupper(string)" function
8271 */
8272 static void
8273f_toupper(typval_T *argvars, typval_T *rettv)
8274{
8275 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008276 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008277}
8278
8279/*
8280 * "tr(string, fromstr, tostr)" function
8281 */
8282 static void
8283f_tr(typval_T *argvars, typval_T *rettv)
8284{
8285 char_u *in_str;
8286 char_u *fromstr;
8287 char_u *tostr;
8288 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008289 int inlen;
8290 int fromlen;
8291 int tolen;
8292 int idx;
8293 char_u *cpstr;
8294 int cplen;
8295 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008296 char_u buf[NUMBUFLEN];
8297 char_u buf2[NUMBUFLEN];
8298 garray_T ga;
8299
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008300 in_str = tv_get_string(&argvars[0]);
8301 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8302 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008303
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008304 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008305 rettv->v_type = VAR_STRING;
8306 rettv->vval.v_string = NULL;
8307 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008308 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008309 ga_init2(&ga, (int)sizeof(char), 80);
8310
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008311 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008312 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008313 if (STRLEN(fromstr) != STRLEN(tostr))
8314 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008315error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008316 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008317 ga_clear(&ga);
8318 return;
8319 }
8320
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008321 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008322 while (*in_str != NUL)
8323 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008324 if (has_mbyte)
8325 {
8326 inlen = (*mb_ptr2len)(in_str);
8327 cpstr = in_str;
8328 cplen = inlen;
8329 idx = 0;
8330 for (p = fromstr; *p != NUL; p += fromlen)
8331 {
8332 fromlen = (*mb_ptr2len)(p);
8333 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8334 {
8335 for (p = tostr; *p != NUL; p += tolen)
8336 {
8337 tolen = (*mb_ptr2len)(p);
8338 if (idx-- == 0)
8339 {
8340 cplen = tolen;
8341 cpstr = p;
8342 break;
8343 }
8344 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008345 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008346 goto error;
8347 break;
8348 }
8349 ++idx;
8350 }
8351
8352 if (first && cpstr == in_str)
8353 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008354 // Check that fromstr and tostr have the same number of
8355 // (multi-byte) characters. Done only once when a character
8356 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008357 first = FALSE;
8358 for (p = tostr; *p != NUL; p += tolen)
8359 {
8360 tolen = (*mb_ptr2len)(p);
8361 --idx;
8362 }
8363 if (idx != 0)
8364 goto error;
8365 }
8366
8367 (void)ga_grow(&ga, cplen);
8368 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8369 ga.ga_len += cplen;
8370
8371 in_str += inlen;
8372 }
8373 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008374 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008375 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376 p = vim_strchr(fromstr, *in_str);
8377 if (p != NULL)
8378 ga_append(&ga, tostr[p - fromstr]);
8379 else
8380 ga_append(&ga, *in_str);
8381 ++in_str;
8382 }
8383 }
8384
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008385 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008386 (void)ga_grow(&ga, 1);
8387 ga_append(&ga, NUL);
8388
8389 rettv->vval.v_string = ga.ga_data;
8390}
8391
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008392/*
8393 * "trim({expr})" function
8394 */
8395 static void
8396f_trim(typval_T *argvars, typval_T *rettv)
8397{
8398 char_u buf1[NUMBUFLEN];
8399 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008400 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008401 char_u *mask = NULL;
8402 char_u *tail;
8403 char_u *prev;
8404 char_u *p;
8405 int c1;
8406
8407 rettv->v_type = VAR_STRING;
8408 if (head == NULL)
8409 {
8410 rettv->vval.v_string = NULL;
8411 return;
8412 }
8413
8414 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008415 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008416
8417 while (*head != NUL)
8418 {
8419 c1 = PTR2CHAR(head);
8420 if (mask == NULL)
8421 {
8422 if (c1 > ' ' && c1 != 0xa0)
8423 break;
8424 }
8425 else
8426 {
8427 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8428 if (c1 == PTR2CHAR(p))
8429 break;
8430 if (*p == NUL)
8431 break;
8432 }
8433 MB_PTR_ADV(head);
8434 }
8435
8436 for (tail = head + STRLEN(head); tail > head; tail = prev)
8437 {
8438 prev = tail;
8439 MB_PTR_BACK(head, prev);
8440 c1 = PTR2CHAR(prev);
8441 if (mask == NULL)
8442 {
8443 if (c1 > ' ' && c1 != 0xa0)
8444 break;
8445 }
8446 else
8447 {
8448 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8449 if (c1 == PTR2CHAR(p))
8450 break;
8451 if (*p == NUL)
8452 break;
8453 }
8454 }
8455 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8456}
8457
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008458#ifdef FEAT_FLOAT
8459/*
8460 * "trunc({float})" function
8461 */
8462 static void
8463f_trunc(typval_T *argvars, typval_T *rettv)
8464{
8465 float_T f = 0.0;
8466
8467 rettv->v_type = VAR_FLOAT;
8468 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008469 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008470 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8471 else
8472 rettv->vval.v_float = 0.0;
8473}
8474#endif
8475
8476/*
8477 * "type(expr)" function
8478 */
8479 static void
8480f_type(typval_T *argvars, typval_T *rettv)
8481{
8482 int n = -1;
8483
8484 switch (argvars[0].v_type)
8485 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008486 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8487 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008488 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008489 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8490 case VAR_LIST: n = VAR_TYPE_LIST; break;
8491 case VAR_DICT: n = VAR_TYPE_DICT; break;
8492 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8493 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8494 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008495 case VAR_JOB: n = VAR_TYPE_JOB; break;
8496 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008497 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008498 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008499 case VAR_VOID:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008500 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008501 n = -1;
8502 break;
8503 }
8504 rettv->vval.v_number = n;
8505}
8506
8507/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008508 * "virtcol(string)" function
8509 */
8510 static void
8511f_virtcol(typval_T *argvars, typval_T *rettv)
8512{
8513 colnr_T vcol = 0;
8514 pos_T *fp;
8515 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008516 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008517
8518 fp = var2fpos(&argvars[0], FALSE, &fnum);
8519 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8520 && fnum == curbuf->b_fnum)
8521 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008522 // Limit the column to a valid value, getvvcol() doesn't check.
8523 if (fp->col < 0)
8524 fp->col = 0;
8525 else
8526 {
8527 len = (int)STRLEN(ml_get(fp->lnum));
8528 if (fp->col > len)
8529 fp->col = len;
8530 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008531 getvvcol(curwin, fp, NULL, NULL, &vcol);
8532 ++vcol;
8533 }
8534
8535 rettv->vval.v_number = vcol;
8536}
8537
8538/*
8539 * "visualmode()" function
8540 */
8541 static void
8542f_visualmode(typval_T *argvars, typval_T *rettv)
8543{
8544 char_u str[2];
8545
8546 rettv->v_type = VAR_STRING;
8547 str[0] = curbuf->b_visual_mode_eval;
8548 str[1] = NUL;
8549 rettv->vval.v_string = vim_strsave(str);
8550
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008551 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008552 if (non_zero_arg(&argvars[0]))
8553 curbuf->b_visual_mode_eval = NUL;
8554}
8555
8556/*
8557 * "wildmenumode()" function
8558 */
8559 static void
8560f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8561{
8562#ifdef FEAT_WILDMENU
8563 if (wild_menu_showing)
8564 rettv->vval.v_number = 1;
8565#endif
8566}
8567
8568/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008569 * "windowsversion()" function
8570 */
8571 static void
8572f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8573{
8574 rettv->v_type = VAR_STRING;
8575 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8576}
8577
8578/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008579 * "wordcount()" function
8580 */
8581 static void
8582f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8583{
8584 if (rettv_dict_alloc(rettv) == FAIL)
8585 return;
8586 cursor_pos_info(rettv->vval.v_dict);
8587}
8588
8589/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008590 * "xor(expr, expr)" function
8591 */
8592 static void
8593f_xor(typval_T *argvars, typval_T *rettv)
8594{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008595 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8596 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008597}
8598
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008599#endif // FEAT_EVAL