blob: 58f1218f21b1fdfd03295fb28e169e4711ff9ccd [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},
814 {"test_feedinput", 1, 1, FEARG_1, &t_void, f_test_feedinput},
815 {"test_garbagecollect_now", 0, 0, 0, &t_void, f_test_garbagecollect_now},
816 {"test_garbagecollect_soon", 0, 0, 0, &t_void, f_test_garbagecollect_soon},
817 {"test_getvalue", 1, 1, FEARG_1, &t_number, f_test_getvalue},
818 {"test_ignore_error", 1, 1, FEARG_1, &t_void, f_test_ignore_error},
819 {"test_null_blob", 0, 0, 0, &t_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100821 {"test_null_channel", 0, 0, 0, &t_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100823 {"test_null_dict", 0, 0, 0, &t_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100825 {"test_null_job", 0, 0, 0, &t_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200826#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100827 {"test_null_list", 0, 0, 0, &t_list_any, f_test_null_list},
828 {"test_null_partial", 0, 0, 0, &t_partial_void, f_test_null_partial},
829 {"test_null_string", 0, 0, 0, &t_string, f_test_null_string},
830 {"test_option_not_set", 1, 1, FEARG_1,&t_void, f_test_option_not_set},
831 {"test_override", 2, 2, FEARG_2, &t_void, f_test_override},
832 {"test_refcount", 1, 1, FEARG_1, &t_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200833#ifdef FEAT_GUI
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100834 {"test_scrollbar", 3, 3, FEARG_2, &t_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200835#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100836 {"test_setmouse", 2, 2, 0, &t_void, f_test_setmouse},
837 {"test_settime", 1, 1, FEARG_1, &t_void, f_test_settime},
Bram Moolenaar4f645c52020-02-08 16:40:39 +0100838 {"test_srand_seed", 0, 1, FEARG_1, &t_void, f_test_srand_seed},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839#ifdef FEAT_TIMERS
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100840 {"timer_info", 0, 1, FEARG_1, &t_list_dict_any, f_timer_info},
841 {"timer_pause", 2, 2, FEARG_1, &t_void, f_timer_pause},
842 {"timer_start", 2, 3, FEARG_1, &t_number, f_timer_start},
843 {"timer_stop", 1, 1, FEARG_1, &t_void, f_timer_stop},
844 {"timer_stopall", 0, 0, 0, &t_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200845#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100846 {"tolower", 1, 1, FEARG_1, &t_string, f_tolower},
847 {"toupper", 1, 1, FEARG_1, &t_string, f_toupper},
848 {"tr", 3, 3, FEARG_1, &t_string, f_tr},
849 {"trim", 1, 2, FEARG_1, &t_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100851 {"trunc", 1, 1, FEARG_1, &t_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200852#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100853 {"type", 1, 1, FEARG_1, &t_number, f_type},
854 {"undofile", 1, 1, FEARG_1, &t_string, f_undofile},
855 {"undotree", 0, 0, 0, &t_dict_any, f_undotree},
856 {"uniq", 1, 3, FEARG_1, &t_list_any, f_uniq},
857 {"values", 1, 1, FEARG_1, &t_list_any, f_values},
858 {"virtcol", 1, 1, FEARG_1, &t_number, f_virtcol},
859 {"visualmode", 0, 1, 0, &t_string, f_visualmode},
860 {"wildmenumode", 0, 0, 0, &t_number, f_wildmenumode},
861 {"win_execute", 2, 3, FEARG_2, &t_string, f_win_execute},
862 {"win_findbuf", 1, 1, FEARG_1, &t_list_number, f_win_findbuf},
863 {"win_getid", 0, 2, FEARG_1, &t_number, f_win_getid},
864 {"win_gotoid", 1, 1, FEARG_1, &t_number, f_win_gotoid},
865 {"win_id2tabwin", 1, 1, FEARG_1, &t_list_number, f_win_id2tabwin},
866 {"win_id2win", 1, 1, FEARG_1, &t_number, f_win_id2win},
867 {"win_screenpos", 1, 1, FEARG_1, &t_list_number, f_win_screenpos},
868 {"win_splitmove", 2, 3, FEARG_1, &t_number, f_win_splitmove},
869 {"winbufnr", 1, 1, FEARG_1, &t_number, f_winbufnr},
870 {"wincol", 0, 0, 0, &t_number, f_wincol},
871 {"windowsversion", 0, 0, 0, &t_string, f_windowsversion},
872 {"winheight", 1, 1, FEARG_1, &t_number, f_winheight},
873 {"winlayout", 0, 1, FEARG_1, &t_list_any, f_winlayout},
874 {"winline", 0, 0, 0, &t_number, f_winline},
875 {"winnr", 0, 1, FEARG_1, &t_number, f_winnr},
876 {"winrestcmd", 0, 0, 0, &t_string, f_winrestcmd},
877 {"winrestview", 1, 1, FEARG_1, &t_void, f_winrestview},
878 {"winsaveview", 0, 0, 0, &t_dict_any, f_winsaveview},
879 {"winwidth", 1, 1, FEARG_1, &t_number, f_winwidth},
880 {"wordcount", 0, 0, 0, &t_dict_number, f_wordcount},
881 {"writefile", 2, 3, FEARG_1, &t_number, f_writefile},
882 {"xor", 2, 2, FEARG_1, &t_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200883};
884
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200885/*
886 * Function given to ExpandGeneric() to obtain the list of internal
887 * or user defined function names.
888 */
889 char_u *
890get_function_name(expand_T *xp, int idx)
891{
892 static int intidx = -1;
893 char_u *name;
894
895 if (idx == 0)
896 intidx = -1;
897 if (intidx < 0)
898 {
899 name = get_user_func_name(xp, idx);
900 if (name != NULL)
901 return name;
902 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200903 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200904 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200905 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200906 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200907 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200908 STRCAT(IObuff, ")");
909 return IObuff;
910 }
911
912 return NULL;
913}
914
915/*
916 * Function given to ExpandGeneric() to obtain the list of internal or
917 * user defined variable or function names.
918 */
919 char_u *
920get_expr_name(expand_T *xp, int idx)
921{
922 static int intidx = -1;
923 char_u *name;
924
925 if (idx == 0)
926 intidx = -1;
927 if (intidx < 0)
928 {
929 name = get_function_name(xp, idx);
930 if (name != NULL)
931 return name;
932 }
933 return get_user_var_name(xp, ++intidx);
934}
935
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200936/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200937 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200938 * Return index, or -1 if not found
939 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100940 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200941find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200942{
943 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200944 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200945 int cmp;
946 int x;
947
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200948 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200949
950 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200951 while (first <= last)
952 {
953 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200954 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200955 if (cmp < 0)
956 last = x - 1;
957 else if (cmp > 0)
958 first = x + 1;
959 else
960 return x;
961 }
962 return -1;
963}
964
965 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200966has_internal_func(char_u *name)
967{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200968 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200969}
970
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100971 char *
972internal_func_name(int idx)
973{
974 return global_functions[idx].f_name;
975}
976
977 type_T *
978internal_func_ret_type(int idx, int argcount)
979{
980 funcentry_T *fe = &global_functions[idx];
981
982 if (fe->f_func == f_getline)
983 return argcount == 1 ? &t_string : &t_list_string;
984 return fe->f_rettype;
985}
986
987/*
988 * Check the argument count to use for internal function "idx".
989 * Returns OK or FAIL;
990 */
991 int
992check_internal_func(int idx, int argcount)
993{
994 int res;
995 char *name;
996
997 if (argcount < global_functions[idx].f_min_argc)
998 res = FCERR_TOOFEW;
999 else if (argcount > global_functions[idx].f_max_argc)
1000 res = FCERR_TOOMANY;
1001 else
1002 return OK;
1003
1004 name = internal_func_name(idx);
1005 if (res == FCERR_TOOMANY)
1006 semsg(_(e_toomanyarg), name);
1007 else
1008 semsg(_(e_toofewarg), name);
1009 return FAIL;
1010}
1011
Bram Moolenaarac92e252019-08-03 21:58:38 +02001012 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001013call_internal_func(
1014 char_u *name,
1015 int argcount,
1016 typval_T *argvars,
1017 typval_T *rettv)
1018{
1019 int i;
1020
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001021 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001022 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001023 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001024 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001025 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001026 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001027 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001028 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001029 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001030 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001031}
1032
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001033 void
1034call_internal_func_by_idx(
1035 int idx,
1036 typval_T *argvars,
1037 typval_T *rettv)
1038{
1039 global_functions[idx].f_func(argvars, rettv);
1040}
1041
Bram Moolenaarac92e252019-08-03 21:58:38 +02001042/*
1043 * Invoke a method for base->method().
1044 */
1045 int
1046call_internal_method(
1047 char_u *name,
1048 int argcount,
1049 typval_T *argvars,
1050 typval_T *rettv,
1051 typval_T *basetv)
1052{
1053 int i;
1054 int fi;
1055 typval_T argv[MAX_FUNC_ARGS + 1];
1056
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001057 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001058 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001059 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001060 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001061 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001062 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001063 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001064 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001065 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001066
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001067 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001068 {
1069 // base value goes last
1070 for (i = 0; i < argcount; ++i)
1071 argv[i] = argvars[i];
1072 argv[argcount] = *basetv;
1073 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001074 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001075 {
1076 // base value goes second
1077 argv[0] = argvars[0];
1078 argv[1] = *basetv;
1079 for (i = 1; i < argcount; ++i)
1080 argv[i + 1] = argvars[i];
1081 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001082 else if (global_functions[fi].f_argtype == FEARG_3)
1083 {
1084 // base value goes third
1085 argv[0] = argvars[0];
1086 argv[1] = argvars[1];
1087 argv[2] = *basetv;
1088 for (i = 2; i < argcount; ++i)
1089 argv[i + 1] = argvars[i];
1090 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001091 else if (global_functions[fi].f_argtype == FEARG_4)
1092 {
1093 // base value goes fourth
1094 argv[0] = argvars[0];
1095 argv[1] = argvars[1];
1096 argv[2] = argvars[2];
1097 argv[3] = *basetv;
1098 for (i = 3; i < argcount; ++i)
1099 argv[i + 1] = argvars[i];
1100 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001101 else
1102 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001103 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001104 argv[0] = *basetv;
1105 for (i = 0; i < argcount; ++i)
1106 argv[i + 1] = argvars[i];
1107 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001108 argv[argcount + 1].v_type = VAR_UNKNOWN;
1109
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001110 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001111 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001112}
1113
1114/*
1115 * Return TRUE for a non-zero Number and a non-empty String.
1116 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001117 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001118non_zero_arg(typval_T *argvars)
1119{
1120 return ((argvars[0].v_type == VAR_NUMBER
1121 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001122 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001123 && argvars[0].vval.v_number == VVAL_TRUE)
1124 || (argvars[0].v_type == VAR_STRING
1125 && argvars[0].vval.v_string != NULL
1126 && *argvars[0].vval.v_string != NUL));
1127}
1128
1129/*
1130 * Get the lnum from the first argument.
1131 * Also accepts ".", "$", etc., but that only works for the current buffer.
1132 * Returns -1 on error.
1133 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001134 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001135tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001136{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001137 linenr_T lnum;
1138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001139 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001140 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001141 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001142 int fnum;
1143 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1144
1145 if (fp != NULL)
1146 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001147 }
1148 return lnum;
1149}
1150
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001151/*
1152 * Get the lnum from the first argument.
1153 * Also accepts "$", then "buf" is used.
1154 * Returns 0 on error.
1155 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001156 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001157tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1158{
1159 if (argvars[0].v_type == VAR_STRING
1160 && argvars[0].vval.v_string != NULL
1161 && argvars[0].vval.v_string[0] == '$'
1162 && buf != NULL)
1163 return buf->b_ml.ml_line_count;
1164 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1165}
1166
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001167#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001168/*
1169 * Get the float value of "argvars[0]" into "f".
1170 * Returns FAIL when the argument is not a Number or Float.
1171 */
1172 static int
1173get_float_arg(typval_T *argvars, float_T *f)
1174{
1175 if (argvars[0].v_type == VAR_FLOAT)
1176 {
1177 *f = argvars[0].vval.v_float;
1178 return OK;
1179 }
1180 if (argvars[0].v_type == VAR_NUMBER)
1181 {
1182 *f = (float_T)argvars[0].vval.v_number;
1183 return OK;
1184 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001185 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001186 return FAIL;
1187}
1188
1189/*
1190 * "abs(expr)" function
1191 */
1192 static void
1193f_abs(typval_T *argvars, typval_T *rettv)
1194{
1195 if (argvars[0].v_type == VAR_FLOAT)
1196 {
1197 rettv->v_type = VAR_FLOAT;
1198 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1199 }
1200 else
1201 {
1202 varnumber_T n;
1203 int error = FALSE;
1204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001205 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001206 if (error)
1207 rettv->vval.v_number = -1;
1208 else if (n > 0)
1209 rettv->vval.v_number = n;
1210 else
1211 rettv->vval.v_number = -n;
1212 }
1213}
1214
1215/*
1216 * "acos()" function
1217 */
1218 static void
1219f_acos(typval_T *argvars, typval_T *rettv)
1220{
1221 float_T f = 0.0;
1222
1223 rettv->v_type = VAR_FLOAT;
1224 if (get_float_arg(argvars, &f) == OK)
1225 rettv->vval.v_float = acos(f);
1226 else
1227 rettv->vval.v_float = 0.0;
1228}
1229#endif
1230
1231/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001232 * "and(expr, expr)" function
1233 */
1234 static void
1235f_and(typval_T *argvars, typval_T *rettv)
1236{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001237 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1238 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001239}
1240
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001241#ifdef FEAT_FLOAT
1242/*
1243 * "asin()" function
1244 */
1245 static void
1246f_asin(typval_T *argvars, typval_T *rettv)
1247{
1248 float_T f = 0.0;
1249
1250 rettv->v_type = VAR_FLOAT;
1251 if (get_float_arg(argvars, &f) == OK)
1252 rettv->vval.v_float = asin(f);
1253 else
1254 rettv->vval.v_float = 0.0;
1255}
1256
1257/*
1258 * "atan()" function
1259 */
1260 static void
1261f_atan(typval_T *argvars, typval_T *rettv)
1262{
1263 float_T f = 0.0;
1264
1265 rettv->v_type = VAR_FLOAT;
1266 if (get_float_arg(argvars, &f) == OK)
1267 rettv->vval.v_float = atan(f);
1268 else
1269 rettv->vval.v_float = 0.0;
1270}
1271
1272/*
1273 * "atan2()" function
1274 */
1275 static void
1276f_atan2(typval_T *argvars, typval_T *rettv)
1277{
1278 float_T fx = 0.0, fy = 0.0;
1279
1280 rettv->v_type = VAR_FLOAT;
1281 if (get_float_arg(argvars, &fx) == OK
1282 && get_float_arg(&argvars[1], &fy) == OK)
1283 rettv->vval.v_float = atan2(fx, fy);
1284 else
1285 rettv->vval.v_float = 0.0;
1286}
1287#endif
1288
1289/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001290 * "balloon_show()" function
1291 */
1292#ifdef FEAT_BEVAL
1293 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001294f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1295{
1296 rettv->v_type = VAR_STRING;
1297 if (balloonEval != NULL)
1298 {
1299 if (balloonEval->msg == NULL)
1300 rettv->vval.v_string = NULL;
1301 else
1302 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1303 }
1304}
1305
1306 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001307f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1308{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001309 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001310 {
1311 if (argvars[0].v_type == VAR_LIST
1312# ifdef FEAT_GUI
1313 && !gui.in_use
1314# endif
1315 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001316 {
1317 list_T *l = argvars[0].vval.v_list;
1318
1319 // empty list removes the balloon
1320 post_balloon(balloonEval, NULL,
1321 l == NULL || l->lv_len == 0 ? NULL : l);
1322 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001323 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001324 {
1325 char_u *mesg = tv_get_string_chk(&argvars[0]);
1326
1327 if (mesg != NULL)
1328 // empty string removes the balloon
1329 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1330 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001331 }
1332}
1333
Bram Moolenaar669a8282017-11-19 20:13:05 +01001334# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001335 static void
1336f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1337{
1338 if (rettv_list_alloc(rettv) == OK)
1339 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001340 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001341
1342 if (msg != NULL)
1343 {
1344 pumitem_T *array;
1345 int size = split_message(msg, &array);
1346 int i;
1347
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001348 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001349 for (i = 1; i < size - 1; ++i)
1350 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001351 while (size > 0)
1352 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001353 vim_free(array);
1354 }
1355 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001356}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001357# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001358#endif
1359
1360/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001361 * Get buffer by number or pattern.
1362 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001363 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001364tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001365{
1366 char_u *name = tv->vval.v_string;
1367 buf_T *buf;
1368
1369 if (tv->v_type == VAR_NUMBER)
1370 return buflist_findnr((int)tv->vval.v_number);
1371 if (tv->v_type != VAR_STRING)
1372 return NULL;
1373 if (name == NULL || *name == NUL)
1374 return curbuf;
1375 if (name[0] == '$' && name[1] == NUL)
1376 return lastbuf;
1377
1378 buf = buflist_find_by_name(name, curtab_only);
1379
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001380 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001381 if (buf == NULL)
1382 buf = find_buffer(tv);
1383
1384 return buf;
1385}
1386
1387/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001388 * Get the buffer from "arg" and give an error and return NULL if it is not
1389 * valid.
1390 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001391 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001392get_buf_arg(typval_T *arg)
1393{
1394 buf_T *buf;
1395
1396 ++emsg_off;
1397 buf = tv_get_buf(arg, FALSE);
1398 --emsg_off;
1399 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001400 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001401 return buf;
1402}
1403
1404/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001405 * "byte2line(byte)" function
1406 */
1407 static void
1408f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1409{
1410#ifndef FEAT_BYTEOFF
1411 rettv->vval.v_number = -1;
1412#else
1413 long boff = 0;
1414
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001415 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001416 if (boff < 0)
1417 rettv->vval.v_number = -1;
1418 else
1419 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1420 (linenr_T)0, &boff);
1421#endif
1422}
1423
1424 static void
1425byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1426{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001427 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001428 char_u *str;
1429 varnumber_T idx;
1430
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001431 str = tv_get_string_chk(&argvars[0]);
1432 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001433 rettv->vval.v_number = -1;
1434 if (str == NULL || idx < 0)
1435 return;
1436
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001437 t = str;
1438 for ( ; idx > 0; idx--)
1439 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001440 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001441 return;
1442 if (enc_utf8 && comp)
1443 t += utf_ptr2len(t);
1444 else
1445 t += (*mb_ptr2len)(t);
1446 }
1447 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001448}
1449
1450/*
1451 * "byteidx()" function
1452 */
1453 static void
1454f_byteidx(typval_T *argvars, typval_T *rettv)
1455{
1456 byteidx(argvars, rettv, FALSE);
1457}
1458
1459/*
1460 * "byteidxcomp()" function
1461 */
1462 static void
1463f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1464{
1465 byteidx(argvars, rettv, TRUE);
1466}
1467
1468/*
1469 * "call(func, arglist [, dict])" function
1470 */
1471 static void
1472f_call(typval_T *argvars, typval_T *rettv)
1473{
1474 char_u *func;
1475 partial_T *partial = NULL;
1476 dict_T *selfdict = NULL;
1477
1478 if (argvars[1].v_type != VAR_LIST)
1479 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001480 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001481 return;
1482 }
1483 if (argvars[1].vval.v_list == NULL)
1484 return;
1485
1486 if (argvars[0].v_type == VAR_FUNC)
1487 func = argvars[0].vval.v_string;
1488 else if (argvars[0].v_type == VAR_PARTIAL)
1489 {
1490 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001491 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001492 }
1493 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001494 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001495 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001496 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497
1498 if (argvars[2].v_type != VAR_UNKNOWN)
1499 {
1500 if (argvars[2].v_type != VAR_DICT)
1501 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001502 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001503 return;
1504 }
1505 selfdict = argvars[2].vval.v_dict;
1506 }
1507
1508 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1509}
1510
1511#ifdef FEAT_FLOAT
1512/*
1513 * "ceil({float})" function
1514 */
1515 static void
1516f_ceil(typval_T *argvars, typval_T *rettv)
1517{
1518 float_T f = 0.0;
1519
1520 rettv->v_type = VAR_FLOAT;
1521 if (get_float_arg(argvars, &f) == OK)
1522 rettv->vval.v_float = ceil(f);
1523 else
1524 rettv->vval.v_float = 0.0;
1525}
1526#endif
1527
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001528/*
1529 * "changenr()" function
1530 */
1531 static void
1532f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1533{
1534 rettv->vval.v_number = curbuf->b_u_seq_cur;
1535}
1536
1537/*
1538 * "char2nr(string)" function
1539 */
1540 static void
1541f_char2nr(typval_T *argvars, typval_T *rettv)
1542{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001543 if (has_mbyte)
1544 {
1545 int utf8 = 0;
1546
1547 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001548 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001549
1550 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001551 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001552 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001553 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001554 }
1555 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001556 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001557}
1558
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001559 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001560get_optional_window(typval_T *argvars, int idx)
1561{
1562 win_T *win = curwin;
1563
1564 if (argvars[idx].v_type != VAR_UNKNOWN)
1565 {
1566 win = find_win_by_nr_or_id(&argvars[idx]);
1567 if (win == NULL)
1568 {
1569 emsg(_(e_invalwindow));
1570 return NULL;
1571 }
1572 }
1573 return win;
1574}
1575
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001577 * "col(string)" function
1578 */
1579 static void
1580f_col(typval_T *argvars, typval_T *rettv)
1581{
1582 colnr_T col = 0;
1583 pos_T *fp;
1584 int fnum = curbuf->b_fnum;
1585
1586 fp = var2fpos(&argvars[0], FALSE, &fnum);
1587 if (fp != NULL && fnum == curbuf->b_fnum)
1588 {
1589 if (fp->col == MAXCOL)
1590 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001591 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001592 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1593 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1594 else
1595 col = MAXCOL;
1596 }
1597 else
1598 {
1599 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001600 // col(".") when the cursor is on the NUL at the end of the line
1601 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001602 if (virtual_active() && fp == &curwin->w_cursor)
1603 {
1604 char_u *p = ml_get_cursor();
1605
1606 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1607 curwin->w_virtcol - curwin->w_cursor.coladd))
1608 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001609 int l;
1610
1611 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1612 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001613 }
1614 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001615 }
1616 }
1617 rettv->vval.v_number = col;
1618}
1619
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001620/*
1621 * "confirm(message, buttons[, default [, type]])" function
1622 */
1623 static void
1624f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1625{
1626#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1627 char_u *message;
1628 char_u *buttons = NULL;
1629 char_u buf[NUMBUFLEN];
1630 char_u buf2[NUMBUFLEN];
1631 int def = 1;
1632 int type = VIM_GENERIC;
1633 char_u *typestr;
1634 int error = FALSE;
1635
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001636 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001637 if (message == NULL)
1638 error = TRUE;
1639 if (argvars[1].v_type != VAR_UNKNOWN)
1640 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001641 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001642 if (buttons == NULL)
1643 error = TRUE;
1644 if (argvars[2].v_type != VAR_UNKNOWN)
1645 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001646 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001647 if (argvars[3].v_type != VAR_UNKNOWN)
1648 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001649 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001650 if (typestr == NULL)
1651 error = TRUE;
1652 else
1653 {
1654 switch (TOUPPER_ASC(*typestr))
1655 {
1656 case 'E': type = VIM_ERROR; break;
1657 case 'Q': type = VIM_QUESTION; break;
1658 case 'I': type = VIM_INFO; break;
1659 case 'W': type = VIM_WARNING; break;
1660 case 'G': type = VIM_GENERIC; break;
1661 }
1662 }
1663 }
1664 }
1665 }
1666
1667 if (buttons == NULL || *buttons == NUL)
1668 buttons = (char_u *)_("&Ok");
1669
1670 if (!error)
1671 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1672 def, NULL, FALSE);
1673#endif
1674}
1675
1676/*
1677 * "copy()" function
1678 */
1679 static void
1680f_copy(typval_T *argvars, typval_T *rettv)
1681{
1682 item_copy(&argvars[0], rettv, FALSE, 0);
1683}
1684
1685#ifdef FEAT_FLOAT
1686/*
1687 * "cos()" function
1688 */
1689 static void
1690f_cos(typval_T *argvars, typval_T *rettv)
1691{
1692 float_T f = 0.0;
1693
1694 rettv->v_type = VAR_FLOAT;
1695 if (get_float_arg(argvars, &f) == OK)
1696 rettv->vval.v_float = cos(f);
1697 else
1698 rettv->vval.v_float = 0.0;
1699}
1700
1701/*
1702 * "cosh()" function
1703 */
1704 static void
1705f_cosh(typval_T *argvars, typval_T *rettv)
1706{
1707 float_T f = 0.0;
1708
1709 rettv->v_type = VAR_FLOAT;
1710 if (get_float_arg(argvars, &f) == OK)
1711 rettv->vval.v_float = cosh(f);
1712 else
1713 rettv->vval.v_float = 0.0;
1714}
1715#endif
1716
1717/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001718 * "cursor(lnum, col)" function, or
1719 * "cursor(list)"
1720 *
1721 * Moves the cursor to the specified line and column.
1722 * Returns 0 when the position could be set, -1 otherwise.
1723 */
1724 static void
1725f_cursor(typval_T *argvars, typval_T *rettv)
1726{
1727 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001729 int set_curswant = TRUE;
1730
1731 rettv->vval.v_number = -1;
1732 if (argvars[1].v_type == VAR_UNKNOWN)
1733 {
1734 pos_T pos;
1735 colnr_T curswant = -1;
1736
1737 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1738 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001739 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001740 return;
1741 }
1742 line = pos.lnum;
1743 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001744 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001745 if (curswant >= 0)
1746 {
1747 curwin->w_curswant = curswant - 1;
1748 set_curswant = FALSE;
1749 }
1750 }
1751 else
1752 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001753 line = tv_get_lnum(argvars);
1754 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001755 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001756 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001757 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001758 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001759 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001760 if (line > 0)
1761 curwin->w_cursor.lnum = line;
1762 if (col > 0)
1763 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001764 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001765
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001766 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001767 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001768 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001769 if (has_mbyte)
1770 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001771
1772 curwin->w_set_curswant = set_curswant;
1773 rettv->vval.v_number = 0;
1774}
1775
Bram Moolenaar4f974752019-02-17 17:44:42 +01001776#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001777/*
1778 * "debugbreak()" function
1779 */
1780 static void
1781f_debugbreak(typval_T *argvars, typval_T *rettv)
1782{
1783 int pid;
1784
1785 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001786 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001787 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001788 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001789 else
1790 {
1791 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1792
1793 if (hProcess != NULL)
1794 {
1795 DebugBreakProcess(hProcess);
1796 CloseHandle(hProcess);
1797 rettv->vval.v_number = OK;
1798 }
1799 }
1800}
1801#endif
1802
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001803/*
1804 * "deepcopy()" function
1805 */
1806 static void
1807f_deepcopy(typval_T *argvars, typval_T *rettv)
1808{
1809 int noref = 0;
1810 int copyID;
1811
1812 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001813 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001814 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001815 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001816 else
1817 {
1818 copyID = get_copyID();
1819 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1820 }
1821}
1822
1823/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001824 * "did_filetype()" function
1825 */
1826 static void
1827f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1828{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001829 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830}
1831
1832/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001833 * "empty({expr})" function
1834 */
1835 static void
1836f_empty(typval_T *argvars, typval_T *rettv)
1837{
1838 int n = FALSE;
1839
1840 switch (argvars[0].v_type)
1841 {
1842 case VAR_STRING:
1843 case VAR_FUNC:
1844 n = argvars[0].vval.v_string == NULL
1845 || *argvars[0].vval.v_string == NUL;
1846 break;
1847 case VAR_PARTIAL:
1848 n = FALSE;
1849 break;
1850 case VAR_NUMBER:
1851 n = argvars[0].vval.v_number == 0;
1852 break;
1853 case VAR_FLOAT:
1854#ifdef FEAT_FLOAT
1855 n = argvars[0].vval.v_float == 0.0;
1856 break;
1857#endif
1858 case VAR_LIST:
1859 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001860 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001861 break;
1862 case VAR_DICT:
1863 n = argvars[0].vval.v_dict == NULL
1864 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1865 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001866 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001867 case VAR_SPECIAL:
1868 n = argvars[0].vval.v_number != VVAL_TRUE;
1869 break;
1870
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001871 case VAR_BLOB:
1872 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001873 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1874 break;
1875
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001876 case VAR_JOB:
1877#ifdef FEAT_JOB_CHANNEL
1878 n = argvars[0].vval.v_job == NULL
1879 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1880 break;
1881#endif
1882 case VAR_CHANNEL:
1883#ifdef FEAT_JOB_CHANNEL
1884 n = argvars[0].vval.v_channel == NULL
1885 || !channel_is_open(argvars[0].vval.v_channel);
1886 break;
1887#endif
1888 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001889 case VAR_VOID:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001890 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001891 n = TRUE;
1892 break;
1893 }
1894
1895 rettv->vval.v_number = n;
1896}
1897
1898/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001899 * "environ()" function
1900 */
1901 static void
1902f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1903{
1904#if !defined(AMIGA)
1905 int i = 0;
1906 char_u *entry, *value;
1907# ifdef MSWIN
1908 extern wchar_t **_wenviron;
1909# else
1910 extern char **environ;
1911# endif
1912
1913 if (rettv_dict_alloc(rettv) != OK)
1914 return;
1915
1916# ifdef MSWIN
1917 if (*_wenviron == NULL)
1918 return;
1919# else
1920 if (*environ == NULL)
1921 return;
1922# endif
1923
1924 for (i = 0; ; ++i)
1925 {
1926# ifdef MSWIN
1927 short_u *p;
1928
1929 if ((p = (short_u *)_wenviron[i]) == NULL)
1930 return;
1931 entry = utf16_to_enc(p, NULL);
1932# else
1933 if ((entry = (char_u *)environ[i]) == NULL)
1934 return;
1935 entry = vim_strsave(entry);
1936# endif
1937 if (entry == NULL) // out of memory
1938 return;
1939 if ((value = vim_strchr(entry, '=')) == NULL)
1940 {
1941 vim_free(entry);
1942 continue;
1943 }
1944 *value++ = NUL;
1945 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1946 vim_free(entry);
1947 }
1948#endif
1949}
1950
1951/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001952 * "escape({string}, {chars})" function
1953 */
1954 static void
1955f_escape(typval_T *argvars, typval_T *rettv)
1956{
1957 char_u buf[NUMBUFLEN];
1958
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001959 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1960 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001961 rettv->v_type = VAR_STRING;
1962}
1963
1964/*
1965 * "eval()" function
1966 */
1967 static void
1968f_eval(typval_T *argvars, typval_T *rettv)
1969{
1970 char_u *s, *p;
1971
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001972 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001973 if (s != NULL)
1974 s = skipwhite(s);
1975
1976 p = s;
1977 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1978 {
1979 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001980 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001981 need_clr_eos = FALSE;
1982 rettv->v_type = VAR_NUMBER;
1983 rettv->vval.v_number = 0;
1984 }
1985 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001986 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987}
1988
1989/*
1990 * "eventhandler()" function
1991 */
1992 static void
1993f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1994{
1995 rettv->vval.v_number = vgetc_busy;
1996}
1997
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001998static garray_T redir_execute_ga;
1999
2000/*
2001 * Append "value[value_len]" to the execute() output.
2002 */
2003 void
2004execute_redir_str(char_u *value, int value_len)
2005{
2006 int len;
2007
2008 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002009 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002011 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012 if (ga_grow(&redir_execute_ga, len) == OK)
2013 {
2014 mch_memmove((char *)redir_execute_ga.ga_data
2015 + redir_execute_ga.ga_len, value, len);
2016 redir_execute_ga.ga_len += len;
2017 }
2018}
2019
2020/*
2021 * Get next line from a list.
2022 * Called by do_cmdline() to get the next line.
2023 * Returns allocated string, or NULL for end of function.
2024 */
2025
2026 static char_u *
2027get_list_line(
2028 int c UNUSED,
2029 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002030 int indent UNUSED,
2031 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002032{
2033 listitem_T **p = (listitem_T **)cookie;
2034 listitem_T *item = *p;
2035 char_u buf[NUMBUFLEN];
2036 char_u *s;
2037
2038 if (item == NULL)
2039 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002040 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002041 *p = item->li_next;
2042 return s == NULL ? NULL : vim_strsave(s);
2043}
2044
2045/*
2046 * "execute()" function
2047 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002048 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002049execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002050{
2051 char_u *cmd = NULL;
2052 list_T *list = NULL;
2053 int save_msg_silent = msg_silent;
2054 int save_emsg_silent = emsg_silent;
2055 int save_emsg_noredir = emsg_noredir;
2056 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002057 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002059 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002060 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002061
2062 rettv->vval.v_string = NULL;
2063 rettv->v_type = VAR_STRING;
2064
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002065 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002066 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002067 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002068 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002069 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002070 return;
2071 ++list->lv_refcount;
2072 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002073 else if (argvars[arg_off].v_type == VAR_JOB
2074 || argvars[arg_off].v_type == VAR_CHANNEL)
2075 {
2076 emsg(_(e_inval_string));
2077 return;
2078 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002079 else
2080 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002081 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082 if (cmd == NULL)
2083 return;
2084 }
2085
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002086 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002087 {
2088 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002089 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002090
2091 if (s == NULL)
2092 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002093 if (*s == NUL)
2094 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095 if (STRNCMP(s, "silent", 6) == 0)
2096 ++msg_silent;
2097 if (STRCMP(s, "silent!") == 0)
2098 {
2099 emsg_silent = TRUE;
2100 emsg_noredir = TRUE;
2101 }
2102 }
2103 else
2104 ++msg_silent;
2105
2106 if (redir_execute)
2107 save_ga = redir_execute_ga;
2108 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2109 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002110 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002111 if (!echo_output)
2112 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002113
2114 if (cmd != NULL)
2115 do_cmdline_cmd(cmd);
2116 else
2117 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002118 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002119
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002120 range_list_materialize(list);
2121 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122 do_cmdline(NULL, get_list_line, (void *)&item,
2123 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2124 --list->lv_refcount;
2125 }
2126
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002127 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002128 if (ga_grow(&redir_execute_ga, 1) == OK)
2129 {
2130 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2131 rettv->vval.v_string = redir_execute_ga.ga_data;
2132 }
2133 else
2134 {
2135 ga_clear(&redir_execute_ga);
2136 rettv->vval.v_string = NULL;
2137 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138 msg_silent = save_msg_silent;
2139 emsg_silent = save_emsg_silent;
2140 emsg_noredir = save_emsg_noredir;
2141
2142 redir_execute = save_redir_execute;
2143 if (redir_execute)
2144 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002145 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002146
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002147 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002148 if (echo_output)
2149 // When not working silently: put it in column zero. A following
2150 // "echon" will overwrite the message, unavoidably.
2151 msg_col = 0;
2152 else
2153 // When working silently: Put it back where it was, since nothing
2154 // should have been written.
2155 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002156}
2157
2158/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002159 * "execute()" function
2160 */
2161 static void
2162f_execute(typval_T *argvars, typval_T *rettv)
2163{
2164 execute_common(argvars, rettv, 0);
2165}
2166
2167/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002168 * "exists()" function
2169 */
2170 static void
2171f_exists(typval_T *argvars, typval_T *rettv)
2172{
2173 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002174 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002176 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002177 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002179 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180 if (mch_getenv(p + 1) != NULL)
2181 n = TRUE;
2182 else
2183 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002184 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002185 p = expand_env_save(p);
2186 if (p != NULL && *p != '$')
2187 n = TRUE;
2188 vim_free(p);
2189 }
2190 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002191 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 {
2193 n = (get_option_tv(&p, NULL, TRUE) == OK);
2194 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002195 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002196 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002197 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002198 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002199 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002200 }
2201 else if (*p == ':')
2202 {
2203 n = cmd_exists(p + 1);
2204 }
2205 else if (*p == '#')
2206 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207 if (p[1] == '#')
2208 n = autocmd_supported(p + 2);
2209 else
2210 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002211 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002212 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002213 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002214 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002215 }
2216
2217 rettv->vval.v_number = n;
2218}
2219
2220#ifdef FEAT_FLOAT
2221/*
2222 * "exp()" function
2223 */
2224 static void
2225f_exp(typval_T *argvars, typval_T *rettv)
2226{
2227 float_T f = 0.0;
2228
2229 rettv->v_type = VAR_FLOAT;
2230 if (get_float_arg(argvars, &f) == OK)
2231 rettv->vval.v_float = exp(f);
2232 else
2233 rettv->vval.v_float = 0.0;
2234}
2235#endif
2236
2237/*
2238 * "expand()" function
2239 */
2240 static void
2241f_expand(typval_T *argvars, typval_T *rettv)
2242{
2243 char_u *s;
2244 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002245 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002246 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2247 expand_T xpc;
2248 int error = FALSE;
2249 char_u *result;
2250
2251 rettv->v_type = VAR_STRING;
2252 if (argvars[1].v_type != VAR_UNKNOWN
2253 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002254 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002255 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002256 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002257
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002258 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002259 if (*s == '%' || *s == '#' || *s == '<')
2260 {
2261 ++emsg_off;
2262 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2263 --emsg_off;
2264 if (rettv->v_type == VAR_LIST)
2265 {
2266 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2267 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002268 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269 }
2270 else
2271 rettv->vval.v_string = result;
2272 }
2273 else
2274 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002275 // When the optional second argument is non-zero, don't remove matches
2276 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002277 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002278 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002279 options |= WILD_KEEP_ALL;
2280 if (!error)
2281 {
2282 ExpandInit(&xpc);
2283 xpc.xp_context = EXPAND_FILES;
2284 if (p_wic)
2285 options += WILD_ICASE;
2286 if (rettv->v_type == VAR_STRING)
2287 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2288 options, WILD_ALL);
2289 else if (rettv_list_alloc(rettv) != FAIL)
2290 {
2291 int i;
2292
2293 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2294 for (i = 0; i < xpc.xp_numfiles; i++)
2295 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2296 ExpandCleanup(&xpc);
2297 }
2298 }
2299 else
2300 rettv->vval.v_string = NULL;
2301 }
2302}
2303
2304/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002305 * "expandcmd()" function
2306 * Expand all the special characters in a command string.
2307 */
2308 static void
2309f_expandcmd(typval_T *argvars, typval_T *rettv)
2310{
2311 exarg_T eap;
2312 char_u *cmdstr;
2313 char *errormsg = NULL;
2314
2315 rettv->v_type = VAR_STRING;
2316 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2317
2318 memset(&eap, 0, sizeof(eap));
2319 eap.cmd = cmdstr;
2320 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002321 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002322 eap.usefilter = FALSE;
2323 eap.nextcmd = NULL;
2324 eap.cmdidx = CMD_USER;
2325
2326 expand_filename(&eap, &cmdstr, &errormsg);
2327 if (errormsg != NULL && *errormsg != NUL)
2328 emsg(errormsg);
2329
2330 rettv->vval.v_string = cmdstr;
2331}
2332
2333/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002334 * "feedkeys()" function
2335 */
2336 static void
2337f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2338{
2339 int remap = TRUE;
2340 int insert = FALSE;
2341 char_u *keys, *flags;
2342 char_u nbuf[NUMBUFLEN];
2343 int typed = FALSE;
2344 int execute = FALSE;
2345 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002346 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347 char_u *keys_esc;
2348
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002349 // This is not allowed in the sandbox. If the commands would still be
2350 // executed in the sandbox it would be OK, but it probably happens later,
2351 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002352 if (check_secure())
2353 return;
2354
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002355 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002356
2357 if (argvars[1].v_type != VAR_UNKNOWN)
2358 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002359 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002360 for ( ; *flags != NUL; ++flags)
2361 {
2362 switch (*flags)
2363 {
2364 case 'n': remap = FALSE; break;
2365 case 'm': remap = TRUE; break;
2366 case 't': typed = TRUE; break;
2367 case 'i': insert = TRUE; break;
2368 case 'x': execute = TRUE; break;
2369 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002370 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002371 }
2372 }
2373 }
2374
2375 if (*keys != NUL || execute)
2376 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002377 // Need to escape K_SPECIAL and CSI before putting the string in the
2378 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002379 keys_esc = vim_strsave_escape_csi(keys);
2380 if (keys_esc != NULL)
2381 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002382 if (lowlevel)
2383 {
2384#ifdef USE_INPUT_BUF
2385 add_to_input_buf(keys, (int)STRLEN(keys));
2386#else
2387 emsg(_("E980: lowlevel input not supported"));
2388#endif
2389 }
2390 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002391 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002392 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002393 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002394 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002395#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002396 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002397#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002398 )
2399 typebuf_was_filled = TRUE;
2400 }
2401 vim_free(keys_esc);
2402
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002403 if (execute)
2404 {
2405 int save_msg_scroll = msg_scroll;
2406
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002407 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002408 msg_scroll = FALSE;
2409
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002410 if (!dangerous)
2411 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002412 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002413 if (!dangerous)
2414 --ex_normal_busy;
2415
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002416 msg_scroll |= save_msg_scroll;
2417 }
2418 }
2419 }
2420}
2421
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002422#ifdef FEAT_FLOAT
2423/*
2424 * "float2nr({float})" function
2425 */
2426 static void
2427f_float2nr(typval_T *argvars, typval_T *rettv)
2428{
2429 float_T f = 0.0;
2430
2431 if (get_float_arg(argvars, &f) == OK)
2432 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002433 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002434 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002435 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002436 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002437 else
2438 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002439 }
2440}
2441
2442/*
2443 * "floor({float})" function
2444 */
2445 static void
2446f_floor(typval_T *argvars, typval_T *rettv)
2447{
2448 float_T f = 0.0;
2449
2450 rettv->v_type = VAR_FLOAT;
2451 if (get_float_arg(argvars, &f) == OK)
2452 rettv->vval.v_float = floor(f);
2453 else
2454 rettv->vval.v_float = 0.0;
2455}
2456
2457/*
2458 * "fmod()" function
2459 */
2460 static void
2461f_fmod(typval_T *argvars, typval_T *rettv)
2462{
2463 float_T fx = 0.0, fy = 0.0;
2464
2465 rettv->v_type = VAR_FLOAT;
2466 if (get_float_arg(argvars, &fx) == OK
2467 && get_float_arg(&argvars[1], &fy) == OK)
2468 rettv->vval.v_float = fmod(fx, fy);
2469 else
2470 rettv->vval.v_float = 0.0;
2471}
2472#endif
2473
2474/*
2475 * "fnameescape({string})" function
2476 */
2477 static void
2478f_fnameescape(typval_T *argvars, typval_T *rettv)
2479{
2480 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002481 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002482 rettv->v_type = VAR_STRING;
2483}
2484
2485/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002486 * "foreground()" function
2487 */
2488 static void
2489f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2490{
2491#ifdef FEAT_GUI
2492 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002493 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002494 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002495 return;
2496 }
2497#endif
2498#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002499 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002500#endif
2501}
2502
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002503 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002504common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002505{
2506 char_u *s;
2507 char_u *name;
2508 int use_string = FALSE;
2509 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002510 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002511
2512 if (argvars[0].v_type == VAR_FUNC)
2513 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002514 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002515 s = argvars[0].vval.v_string;
2516 }
2517 else if (argvars[0].v_type == VAR_PARTIAL
2518 && argvars[0].vval.v_partial != NULL)
2519 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002520 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002521 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002522 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002523 }
2524 else
2525 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002526 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002527 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528 use_string = TRUE;
2529 }
2530
Bram Moolenaar843b8842016-08-21 14:36:15 +02002531 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002532 {
2533 name = s;
2534 trans_name = trans_function_name(&name, FALSE,
2535 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2536 if (*name != NUL)
2537 s = NULL;
2538 }
2539
Bram Moolenaar843b8842016-08-21 14:36:15 +02002540 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2541 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002542 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002543 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002544 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002545 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002546 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002547 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002548 else
2549 {
2550 int dict_idx = 0;
2551 int arg_idx = 0;
2552 list_T *list = NULL;
2553
2554 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2555 {
2556 char sid_buf[25];
2557 int off = *s == 's' ? 2 : 5;
2558
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002559 // Expand s: and <SID> into <SNR>nr_, so that the function can
2560 // also be called from another script. Using trans_function_name()
2561 // would also work, but some plugins depend on the name being
2562 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002563 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002564 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002565 if (name != NULL)
2566 {
2567 STRCPY(name, sid_buf);
2568 STRCAT(name, s + off);
2569 }
2570 }
2571 else
2572 name = vim_strsave(s);
2573
2574 if (argvars[1].v_type != VAR_UNKNOWN)
2575 {
2576 if (argvars[2].v_type != VAR_UNKNOWN)
2577 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002578 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002579 arg_idx = 1;
2580 dict_idx = 2;
2581 }
2582 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002583 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002584 dict_idx = 1;
2585 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002586 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587 arg_idx = 1;
2588 if (dict_idx > 0)
2589 {
2590 if (argvars[dict_idx].v_type != VAR_DICT)
2591 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002592 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002594 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002595 }
2596 if (argvars[dict_idx].vval.v_dict == NULL)
2597 dict_idx = 0;
2598 }
2599 if (arg_idx > 0)
2600 {
2601 if (argvars[arg_idx].v_type != VAR_LIST)
2602 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002603 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002604 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002605 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002606 }
2607 list = argvars[arg_idx].vval.v_list;
2608 if (list == NULL || list->lv_len == 0)
2609 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002610 else if (list->lv_len > MAX_FUNC_ARGS)
2611 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002612 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002613 vim_free(name);
2614 goto theend;
2615 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002616 }
2617 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002618 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002619 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002620 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002622 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002623 if (pt == NULL)
2624 vim_free(name);
2625 else
2626 {
2627 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2628 {
2629 listitem_T *li;
2630 int i = 0;
2631 int arg_len = 0;
2632 int lv_len = 0;
2633
2634 if (arg_pt != NULL)
2635 arg_len = arg_pt->pt_argc;
2636 if (list != NULL)
2637 lv_len = list->lv_len;
2638 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002639 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002640 if (pt->pt_argv == NULL)
2641 {
2642 vim_free(pt);
2643 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002645 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002646 for (i = 0; i < arg_len; i++)
2647 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2648 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002649 {
2650 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002651 for (li = list->lv_first; li != NULL;
2652 li = li->li_next)
2653 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002654 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002655 }
2656
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002657 // For "function(dict.func, [], dict)" and "func" is a partial
2658 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002659 if (dict_idx > 0)
2660 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002661 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002662 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2663 ++pt->pt_dict->dv_refcount;
2664 }
2665 else if (arg_pt != NULL)
2666 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002667 // If the dict was bound automatically the result is also
2668 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002669 pt->pt_dict = arg_pt->pt_dict;
2670 pt->pt_auto = arg_pt->pt_auto;
2671 if (pt->pt_dict != NULL)
2672 ++pt->pt_dict->dv_refcount;
2673 }
2674
2675 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002676 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2677 {
2678 pt->pt_func = arg_pt->pt_func;
2679 func_ptr_ref(pt->pt_func);
2680 vim_free(name);
2681 }
2682 else if (is_funcref)
2683 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002684 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002685 func_ptr_ref(pt->pt_func);
2686 vim_free(name);
2687 }
2688 else
2689 {
2690 pt->pt_name = name;
2691 func_ref(name);
2692 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 }
2694 rettv->v_type = VAR_PARTIAL;
2695 rettv->vval.v_partial = pt;
2696 }
2697 else
2698 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002699 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002700 rettv->v_type = VAR_FUNC;
2701 rettv->vval.v_string = name;
2702 func_ref(name);
2703 }
2704 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002705theend:
2706 vim_free(trans_name);
2707}
2708
2709/*
2710 * "funcref()" function
2711 */
2712 static void
2713f_funcref(typval_T *argvars, typval_T *rettv)
2714{
2715 common_function(argvars, rettv, TRUE);
2716}
2717
2718/*
2719 * "function()" function
2720 */
2721 static void
2722f_function(typval_T *argvars, typval_T *rettv)
2723{
2724 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002725}
2726
2727/*
2728 * "garbagecollect()" function
2729 */
2730 static void
2731f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2732{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002733 // This is postponed until we are back at the toplevel, because we may be
2734 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002735 want_garbage_collect = TRUE;
2736
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002737 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002738 garbage_collect_at_exit = TRUE;
2739}
2740
2741/*
2742 * "get()" function
2743 */
2744 static void
2745f_get(typval_T *argvars, typval_T *rettv)
2746{
2747 listitem_T *li;
2748 list_T *l;
2749 dictitem_T *di;
2750 dict_T *d;
2751 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002752 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002753
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002754 if (argvars[0].v_type == VAR_BLOB)
2755 {
2756 int error = FALSE;
2757 int idx = tv_get_number_chk(&argvars[1], &error);
2758
2759 if (!error)
2760 {
2761 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002762 if (idx < 0)
2763 idx = blob_len(argvars[0].vval.v_blob) + idx;
2764 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2765 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002766 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002767 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002768 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002769 tv = rettv;
2770 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002771 }
2772 }
2773 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002774 {
2775 if ((l = argvars[0].vval.v_list) != NULL)
2776 {
2777 int error = FALSE;
2778
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002779 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002780 if (!error && li != NULL)
2781 tv = &li->li_tv;
2782 }
2783 }
2784 else if (argvars[0].v_type == VAR_DICT)
2785 {
2786 if ((d = argvars[0].vval.v_dict) != NULL)
2787 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002788 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002789 if (di != NULL)
2790 tv = &di->di_tv;
2791 }
2792 }
2793 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2794 {
2795 partial_T *pt;
2796 partial_T fref_pt;
2797
2798 if (argvars[0].v_type == VAR_PARTIAL)
2799 pt = argvars[0].vval.v_partial;
2800 else
2801 {
2802 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2803 fref_pt.pt_name = argvars[0].vval.v_string;
2804 pt = &fref_pt;
2805 }
2806
2807 if (pt != NULL)
2808 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002809 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002810 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002811
2812 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2813 {
2814 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002815 n = partial_name(pt);
2816 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002817 rettv->vval.v_string = NULL;
2818 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002819 {
2820 rettv->vval.v_string = vim_strsave(n);
2821 if (rettv->v_type == VAR_FUNC)
2822 func_ref(rettv->vval.v_string);
2823 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002824 }
2825 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002826 {
2827 what_is_dict = TRUE;
2828 if (pt->pt_dict != NULL)
2829 rettv_dict_set(rettv, pt->pt_dict);
2830 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002831 else if (STRCMP(what, "args") == 0)
2832 {
2833 rettv->v_type = VAR_LIST;
2834 if (rettv_list_alloc(rettv) == OK)
2835 {
2836 int i;
2837
2838 for (i = 0; i < pt->pt_argc; ++i)
2839 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2840 }
2841 }
2842 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002843 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002844
2845 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2846 // third argument
2847 if (!what_is_dict)
2848 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002849 }
2850 }
2851 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002852 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002853
2854 if (tv == NULL)
2855 {
2856 if (argvars[2].v_type != VAR_UNKNOWN)
2857 copy_tv(&argvars[2], rettv);
2858 }
2859 else
2860 copy_tv(tv, rettv);
2861}
2862
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002863/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002864 * "getchangelist()" function
2865 */
2866 static void
2867f_getchangelist(typval_T *argvars, typval_T *rettv)
2868{
2869#ifdef FEAT_JUMPLIST
2870 buf_T *buf;
2871 int i;
2872 list_T *l;
2873 dict_T *d;
2874#endif
2875
2876 if (rettv_list_alloc(rettv) != OK)
2877 return;
2878
2879#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002880 if (argvars[0].v_type == VAR_UNKNOWN)
2881 buf = curbuf;
2882 else
2883 {
2884 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2885 ++emsg_off;
2886 buf = tv_get_buf(&argvars[0], FALSE);
2887 --emsg_off;
2888 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002889 if (buf == NULL)
2890 return;
2891
2892 l = list_alloc();
2893 if (l == NULL)
2894 return;
2895
2896 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2897 return;
2898 /*
2899 * The current window change list index tracks only the position in the
2900 * current buffer change list. For other buffers, use the change list
2901 * length as the current index.
2902 */
2903 list_append_number(rettv->vval.v_list,
2904 (varnumber_T)((buf == curwin->w_buffer)
2905 ? curwin->w_changelistidx : buf->b_changelistlen));
2906
2907 for (i = 0; i < buf->b_changelistlen; ++i)
2908 {
2909 if (buf->b_changelist[i].lnum == 0)
2910 continue;
2911 if ((d = dict_alloc()) == NULL)
2912 return;
2913 if (list_append_dict(l, d) == FAIL)
2914 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002915 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2916 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002917 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002918 }
2919#endif
2920}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002921
2922/*
2923 * "getcharsearch()" function
2924 */
2925 static void
2926f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2927{
2928 if (rettv_dict_alloc(rettv) != FAIL)
2929 {
2930 dict_T *dict = rettv->vval.v_dict;
2931
Bram Moolenaare0be1672018-07-08 16:50:37 +02002932 dict_add_string(dict, "char", last_csearch());
2933 dict_add_number(dict, "forward", last_csearch_forward());
2934 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002935 }
2936}
2937
2938/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002939 * "getcmdwintype()" function
2940 */
2941 static void
2942f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2943{
2944 rettv->v_type = VAR_STRING;
2945 rettv->vval.v_string = NULL;
2946#ifdef FEAT_CMDWIN
2947 rettv->vval.v_string = alloc(2);
2948 if (rettv->vval.v_string != NULL)
2949 {
2950 rettv->vval.v_string[0] = cmdwin_type;
2951 rettv->vval.v_string[1] = NUL;
2952 }
2953#endif
2954}
2955
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002956/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002957 * "getenv()" function
2958 */
2959 static void
2960f_getenv(typval_T *argvars, typval_T *rettv)
2961{
2962 int mustfree = FALSE;
2963 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2964
2965 if (p == NULL)
2966 {
2967 rettv->v_type = VAR_SPECIAL;
2968 rettv->vval.v_number = VVAL_NULL;
2969 return;
2970 }
2971 if (!mustfree)
2972 p = vim_strsave(p);
2973 rettv->vval.v_string = p;
2974 rettv->v_type = VAR_STRING;
2975}
2976
2977/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002978 * "getfontname()" function
2979 */
2980 static void
2981f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2982{
2983 rettv->v_type = VAR_STRING;
2984 rettv->vval.v_string = NULL;
2985#ifdef FEAT_GUI
2986 if (gui.in_use)
2987 {
2988 GuiFont font;
2989 char_u *name = NULL;
2990
2991 if (argvars[0].v_type == VAR_UNKNOWN)
2992 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002993 // Get the "Normal" font. Either the name saved by
2994 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002995 font = gui.norm_font;
2996 name = hl_get_font_name();
2997 }
2998 else
2999 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003000 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003001 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003002 return;
3003 font = gui_mch_get_font(name, FALSE);
3004 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003005 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003006 }
3007 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3008 if (argvars[0].v_type != VAR_UNKNOWN)
3009 gui_mch_free_font(font);
3010 }
3011#endif
3012}
3013
3014/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003015 * "getjumplist()" function
3016 */
3017 static void
3018f_getjumplist(typval_T *argvars, typval_T *rettv)
3019{
3020#ifdef FEAT_JUMPLIST
3021 win_T *wp;
3022 int i;
3023 list_T *l;
3024 dict_T *d;
3025#endif
3026
3027 if (rettv_list_alloc(rettv) != OK)
3028 return;
3029
3030#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003031 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003032 if (wp == NULL)
3033 return;
3034
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003035 cleanup_jumplist(wp, TRUE);
3036
Bram Moolenaar4f505882018-02-10 21:06:32 +01003037 l = list_alloc();
3038 if (l == NULL)
3039 return;
3040
3041 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3042 return;
3043 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3044
3045 for (i = 0; i < wp->w_jumplistlen; ++i)
3046 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003047 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3048 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003049 if ((d = dict_alloc()) == NULL)
3050 return;
3051 if (list_append_dict(l, d) == FAIL)
3052 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003053 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3054 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003055 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003056 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003057 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003058 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003059 }
3060#endif
3061}
3062
3063/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003064 * "getpid()" function
3065 */
3066 static void
3067f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3068{
3069 rettv->vval.v_number = mch_get_pid();
3070}
3071
3072 static void
3073getpos_both(
3074 typval_T *argvars,
3075 typval_T *rettv,
3076 int getcurpos)
3077{
3078 pos_T *fp;
3079 list_T *l;
3080 int fnum = -1;
3081
3082 if (rettv_list_alloc(rettv) == OK)
3083 {
3084 l = rettv->vval.v_list;
3085 if (getcurpos)
3086 fp = &curwin->w_cursor;
3087 else
3088 fp = var2fpos(&argvars[0], TRUE, &fnum);
3089 if (fnum != -1)
3090 list_append_number(l, (varnumber_T)fnum);
3091 else
3092 list_append_number(l, (varnumber_T)0);
3093 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3094 : (varnumber_T)0);
3095 list_append_number(l, (fp != NULL)
3096 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3097 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003098 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003099 (varnumber_T)0);
3100 if (getcurpos)
3101 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003102 int save_set_curswant = curwin->w_set_curswant;
3103 colnr_T save_curswant = curwin->w_curswant;
3104 colnr_T save_virtcol = curwin->w_virtcol;
3105
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003106 update_curswant();
3107 list_append_number(l, curwin->w_curswant == MAXCOL ?
3108 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003109
3110 // Do not change "curswant", as it is unexpected that a get
3111 // function has a side effect.
3112 if (save_set_curswant)
3113 {
3114 curwin->w_set_curswant = save_set_curswant;
3115 curwin->w_curswant = save_curswant;
3116 curwin->w_virtcol = save_virtcol;
3117 curwin->w_valid &= ~VALID_VIRTCOL;
3118 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003119 }
3120 }
3121 else
3122 rettv->vval.v_number = FALSE;
3123}
3124
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003125/*
3126 * "getcurpos()" function
3127 */
3128 static void
3129f_getcurpos(typval_T *argvars, typval_T *rettv)
3130{
3131 getpos_both(argvars, rettv, TRUE);
3132}
3133
3134/*
3135 * "getpos(string)" function
3136 */
3137 static void
3138f_getpos(typval_T *argvars, typval_T *rettv)
3139{
3140 getpos_both(argvars, rettv, FALSE);
3141}
3142
3143/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003144 * "getreg()" function
3145 */
3146 static void
3147f_getreg(typval_T *argvars, typval_T *rettv)
3148{
3149 char_u *strregname;
3150 int regname;
3151 int arg2 = FALSE;
3152 int return_list = FALSE;
3153 int error = FALSE;
3154
3155 if (argvars[0].v_type != VAR_UNKNOWN)
3156 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003157 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003158 error = strregname == NULL;
3159 if (argvars[1].v_type != VAR_UNKNOWN)
3160 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003161 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003162 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003163 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003164 }
3165 }
3166 else
3167 strregname = get_vim_var_str(VV_REG);
3168
3169 if (error)
3170 return;
3171
3172 regname = (strregname == NULL ? '"' : *strregname);
3173 if (regname == 0)
3174 regname = '"';
3175
3176 if (return_list)
3177 {
3178 rettv->v_type = VAR_LIST;
3179 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3180 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3181 if (rettv->vval.v_list == NULL)
3182 (void)rettv_list_alloc(rettv);
3183 else
3184 ++rettv->vval.v_list->lv_refcount;
3185 }
3186 else
3187 {
3188 rettv->v_type = VAR_STRING;
3189 rettv->vval.v_string = get_reg_contents(regname,
3190 arg2 ? GREG_EXPR_SRC : 0);
3191 }
3192}
3193
3194/*
3195 * "getregtype()" function
3196 */
3197 static void
3198f_getregtype(typval_T *argvars, typval_T *rettv)
3199{
3200 char_u *strregname;
3201 int regname;
3202 char_u buf[NUMBUFLEN + 2];
3203 long reglen = 0;
3204
3205 if (argvars[0].v_type != VAR_UNKNOWN)
3206 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003207 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003208 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003209 {
3210 rettv->v_type = VAR_STRING;
3211 rettv->vval.v_string = NULL;
3212 return;
3213 }
3214 }
3215 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003216 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003217 strregname = get_vim_var_str(VV_REG);
3218
3219 regname = (strregname == NULL ? '"' : *strregname);
3220 if (regname == 0)
3221 regname = '"';
3222
3223 buf[0] = NUL;
3224 buf[1] = NUL;
3225 switch (get_reg_type(regname, &reglen))
3226 {
3227 case MLINE: buf[0] = 'V'; break;
3228 case MCHAR: buf[0] = 'v'; break;
3229 case MBLOCK:
3230 buf[0] = Ctrl_V;
3231 sprintf((char *)buf + 1, "%ld", reglen + 1);
3232 break;
3233 }
3234 rettv->v_type = VAR_STRING;
3235 rettv->vval.v_string = vim_strsave(buf);
3236}
3237
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003238/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003239 * "gettagstack()" function
3240 */
3241 static void
3242f_gettagstack(typval_T *argvars, typval_T *rettv)
3243{
3244 win_T *wp = curwin; // default is current window
3245
3246 if (rettv_dict_alloc(rettv) != OK)
3247 return;
3248
3249 if (argvars[0].v_type != VAR_UNKNOWN)
3250 {
3251 wp = find_win_by_nr_or_id(&argvars[0]);
3252 if (wp == NULL)
3253 return;
3254 }
3255
3256 get_tagstack(wp, rettv->vval.v_dict);
3257}
3258
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003259// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003260#include "version.h"
3261
3262/*
3263 * "has()" function
3264 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003265 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003266f_has(typval_T *argvars, typval_T *rettv)
3267{
3268 int i;
3269 char_u *name;
3270 int n = FALSE;
3271 static char *(has_list[]) =
3272 {
3273#ifdef AMIGA
3274 "amiga",
3275# ifdef FEAT_ARP
3276 "arp",
3277# endif
3278#endif
3279#ifdef __BEOS__
3280 "beos",
3281#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003282#if defined(BSD) && !defined(MACOS_X)
3283 "bsd",
3284#endif
3285#ifdef hpux
3286 "hpux",
3287#endif
3288#ifdef __linux__
3289 "linux",
3290#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003291#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003292 "mac", // Mac OS X (and, once, Mac OS Classic)
3293 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003294# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003295 "macunix", // Mac OS X, with the darwin feature
3296 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003297# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003298#endif
3299#ifdef __QNX__
3300 "qnx",
3301#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003302#ifdef SUN_SYSTEM
3303 "sun",
3304#else
3305 "moon",
3306#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003307#ifdef UNIX
3308 "unix",
3309#endif
3310#ifdef VMS
3311 "vms",
3312#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003313#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003314 "win32",
3315#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003316#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317 "win32unix",
3318#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003319#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003320 "win64",
3321#endif
3322#ifdef EBCDIC
3323 "ebcdic",
3324#endif
3325#ifndef CASE_INSENSITIVE_FILENAME
3326 "fname_case",
3327#endif
3328#ifdef HAVE_ACL
3329 "acl",
3330#endif
3331#ifdef FEAT_ARABIC
3332 "arabic",
3333#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003334 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003335#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003336 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003337#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003338#ifdef FEAT_AUTOSERVERNAME
3339 "autoservername",
3340#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003341#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003342 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003343# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003344 "balloon_multiline",
3345# endif
3346#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003347#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003348 "balloon_eval_term",
3349#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003350#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3351 "builtin_terms",
3352# ifdef ALL_BUILTIN_TCAPS
3353 "all_builtin_terms",
3354# endif
3355#endif
3356#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003357 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003358 || defined(FEAT_GUI_MOTIF))
3359 "browsefilter",
3360#endif
3361#ifdef FEAT_BYTEOFF
3362 "byte_offset",
3363#endif
3364#ifdef FEAT_JOB_CHANNEL
3365 "channel",
3366#endif
3367#ifdef FEAT_CINDENT
3368 "cindent",
3369#endif
3370#ifdef FEAT_CLIENTSERVER
3371 "clientserver",
3372#endif
3373#ifdef FEAT_CLIPBOARD
3374 "clipboard",
3375#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003376 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003378 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003379#ifdef FEAT_CONCEAL
3380 "conceal",
3381#endif
3382#ifdef FEAT_CRYPT
3383 "cryptv",
3384 "crypt-blowfish",
3385 "crypt-blowfish2",
3386#endif
3387#ifdef FEAT_CSCOPE
3388 "cscope",
3389#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003390 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391#ifdef CURSOR_SHAPE
3392 "cursorshape",
3393#endif
3394#ifdef DEBUG
3395 "debug",
3396#endif
3397#ifdef FEAT_CON_DIALOG
3398 "dialog_con",
3399#endif
3400#ifdef FEAT_GUI_DIALOG
3401 "dialog_gui",
3402#endif
3403#ifdef FEAT_DIFF
3404 "diff",
3405#endif
3406#ifdef FEAT_DIGRAPHS
3407 "digraphs",
3408#endif
3409#ifdef FEAT_DIRECTX
3410 "directx",
3411#endif
3412#ifdef FEAT_DND
3413 "dnd",
3414#endif
3415#ifdef FEAT_EMACS_TAGS
3416 "emacs_tags",
3417#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003418 "eval", // always present, of course!
3419 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003420#ifdef FEAT_SEARCH_EXTRA
3421 "extra_search",
3422#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003423#ifdef FEAT_SEARCHPATH
3424 "file_in_path",
3425#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003426#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003427 "filterpipe",
3428#endif
3429#ifdef FEAT_FIND_ID
3430 "find_in_path",
3431#endif
3432#ifdef FEAT_FLOAT
3433 "float",
3434#endif
3435#ifdef FEAT_FOLDING
3436 "folding",
3437#endif
3438#ifdef FEAT_FOOTER
3439 "footer",
3440#endif
3441#if !defined(USE_SYSTEM) && defined(UNIX)
3442 "fork",
3443#endif
3444#ifdef FEAT_GETTEXT
3445 "gettext",
3446#endif
3447#ifdef FEAT_GUI
3448 "gui",
3449#endif
3450#ifdef FEAT_GUI_ATHENA
3451# ifdef FEAT_GUI_NEXTAW
3452 "gui_neXtaw",
3453# else
3454 "gui_athena",
3455# endif
3456#endif
3457#ifdef FEAT_GUI_GTK
3458 "gui_gtk",
3459# ifdef USE_GTK3
3460 "gui_gtk3",
3461# else
3462 "gui_gtk2",
3463# endif
3464#endif
3465#ifdef FEAT_GUI_GNOME
3466 "gui_gnome",
3467#endif
3468#ifdef FEAT_GUI_MAC
3469 "gui_mac",
3470#endif
3471#ifdef FEAT_GUI_MOTIF
3472 "gui_motif",
3473#endif
3474#ifdef FEAT_GUI_PHOTON
3475 "gui_photon",
3476#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003477#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003478 "gui_win32",
3479#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003480#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3481 "iconv",
3482#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003484#ifdef FEAT_JOB_CHANNEL
3485 "job",
3486#endif
3487#ifdef FEAT_JUMPLIST
3488 "jumplist",
3489#endif
3490#ifdef FEAT_KEYMAP
3491 "keymap",
3492#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003493 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003494#ifdef FEAT_LANGMAP
3495 "langmap",
3496#endif
3497#ifdef FEAT_LIBCALL
3498 "libcall",
3499#endif
3500#ifdef FEAT_LINEBREAK
3501 "linebreak",
3502#endif
3503#ifdef FEAT_LISP
3504 "lispindent",
3505#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003507 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003508#ifdef FEAT_LUA
3509# ifndef DYNAMIC_LUA
3510 "lua",
3511# endif
3512#endif
3513#ifdef FEAT_MENU
3514 "menu",
3515#endif
3516#ifdef FEAT_SESSION
3517 "mksession",
3518#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003519 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003521#ifdef FEAT_MOUSESHAPE
3522 "mouseshape",
3523#endif
3524#if defined(UNIX) || defined(VMS)
3525# ifdef FEAT_MOUSE_DEC
3526 "mouse_dec",
3527# endif
3528# ifdef FEAT_MOUSE_GPM
3529 "mouse_gpm",
3530# endif
3531# ifdef FEAT_MOUSE_JSB
3532 "mouse_jsbterm",
3533# endif
3534# ifdef FEAT_MOUSE_NET
3535 "mouse_netterm",
3536# endif
3537# ifdef FEAT_MOUSE_PTERM
3538 "mouse_pterm",
3539# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003540# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003541 "mouse_sgr",
3542# endif
3543# ifdef FEAT_SYSMOUSE
3544 "mouse_sysmouse",
3545# endif
3546# ifdef FEAT_MOUSE_URXVT
3547 "mouse_urxvt",
3548# endif
3549# ifdef FEAT_MOUSE_XTERM
3550 "mouse_xterm",
3551# endif
3552#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003553 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003554#ifdef FEAT_MBYTE_IME
3555 "multi_byte_ime",
3556#endif
3557#ifdef FEAT_MULTI_LANG
3558 "multi_lang",
3559#endif
3560#ifdef FEAT_MZSCHEME
3561#ifndef DYNAMIC_MZSCHEME
3562 "mzscheme",
3563#endif
3564#endif
3565#ifdef FEAT_NUM64
3566 "num64",
3567#endif
3568#ifdef FEAT_OLE
3569 "ole",
3570#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003571#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003573#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003574#ifdef FEAT_PATH_EXTRA
3575 "path_extra",
3576#endif
3577#ifdef FEAT_PERL
3578#ifndef DYNAMIC_PERL
3579 "perl",
3580#endif
3581#endif
3582#ifdef FEAT_PERSISTENT_UNDO
3583 "persistent_undo",
3584#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003585#if defined(FEAT_PYTHON)
3586 "python_compiled",
3587# if defined(DYNAMIC_PYTHON)
3588 "python_dynamic",
3589# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003590 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003591 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003592# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003593#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003594#if defined(FEAT_PYTHON3)
3595 "python3_compiled",
3596# if defined(DYNAMIC_PYTHON3)
3597 "python3_dynamic",
3598# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003599 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003600 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003601# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003603#ifdef FEAT_PROP_POPUP
3604 "popupwin",
3605#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003606#ifdef FEAT_POSTSCRIPT
3607 "postscript",
3608#endif
3609#ifdef FEAT_PRINTER
3610 "printer",
3611#endif
3612#ifdef FEAT_PROFILE
3613 "profile",
3614#endif
3615#ifdef FEAT_RELTIME
3616 "reltime",
3617#endif
3618#ifdef FEAT_QUICKFIX
3619 "quickfix",
3620#endif
3621#ifdef FEAT_RIGHTLEFT
3622 "rightleft",
3623#endif
3624#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3625 "ruby",
3626#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003627 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003628#ifdef FEAT_CMDL_INFO
3629 "showcmd",
3630 "cmdline_info",
3631#endif
3632#ifdef FEAT_SIGNS
3633 "signs",
3634#endif
3635#ifdef FEAT_SMARTINDENT
3636 "smartindent",
3637#endif
3638#ifdef STARTUPTIME
3639 "startuptime",
3640#endif
3641#ifdef FEAT_STL_OPT
3642 "statusline",
3643#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644#ifdef FEAT_NETBEANS_INTG
3645 "netbeans_intg",
3646#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003647#ifdef FEAT_SOUND
3648 "sound",
3649#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003650#ifdef FEAT_SPELL
3651 "spell",
3652#endif
3653#ifdef FEAT_SYN_HL
3654 "syntax",
3655#endif
3656#if defined(USE_SYSTEM) || !defined(UNIX)
3657 "system",
3658#endif
3659#ifdef FEAT_TAG_BINS
3660 "tag_binary",
3661#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003662#ifdef FEAT_TCL
3663# ifndef DYNAMIC_TCL
3664 "tcl",
3665# endif
3666#endif
3667#ifdef FEAT_TERMGUICOLORS
3668 "termguicolors",
3669#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003670#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003671 "terminal",
3672#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003673#ifdef TERMINFO
3674 "terminfo",
3675#endif
3676#ifdef FEAT_TERMRESPONSE
3677 "termresponse",
3678#endif
3679#ifdef FEAT_TEXTOBJ
3680 "textobjects",
3681#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003682#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003683 "textprop",
3684#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003685#ifdef HAVE_TGETENT
3686 "tgetent",
3687#endif
3688#ifdef FEAT_TIMERS
3689 "timers",
3690#endif
3691#ifdef FEAT_TITLE
3692 "title",
3693#endif
3694#ifdef FEAT_TOOLBAR
3695 "toolbar",
3696#endif
3697#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3698 "unnamedplus",
3699#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003700 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003701 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003702#ifdef FEAT_VARTABS
3703 "vartabs",
3704#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003705 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003706#ifdef FEAT_VIMINFO
3707 "viminfo",
3708#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003709 "vimscript-1",
3710 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003711 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003712 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003713 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003715 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003716 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003717#ifdef FEAT_VTP
3718 "vtp",
3719#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720#ifdef FEAT_WILDIGN
3721 "wildignore",
3722#endif
3723#ifdef FEAT_WILDMENU
3724 "wildmenu",
3725#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003726 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003727#ifdef FEAT_WAK
3728 "winaltkeys",
3729#endif
3730#ifdef FEAT_WRITEBACKUP
3731 "writebackup",
3732#endif
3733#ifdef FEAT_XIM
3734 "xim",
3735#endif
3736#ifdef FEAT_XFONTSET
3737 "xfontset",
3738#endif
3739#ifdef FEAT_XPM_W32
3740 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003741 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003742#else
3743# if defined(HAVE_XPM)
3744 "xpm",
3745# endif
3746#endif
3747#ifdef USE_XSMP
3748 "xsmp",
3749#endif
3750#ifdef USE_XSMP_INTERACT
3751 "xsmp_interact",
3752#endif
3753#ifdef FEAT_XCLIPBOARD
3754 "xterm_clipboard",
3755#endif
3756#ifdef FEAT_XTERM_SAVE
3757 "xterm_save",
3758#endif
3759#if defined(UNIX) && defined(FEAT_X11)
3760 "X11",
3761#endif
3762 NULL
3763 };
3764
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003765 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003766 for (i = 0; has_list[i] != NULL; ++i)
3767 if (STRICMP(name, has_list[i]) == 0)
3768 {
3769 n = TRUE;
3770 break;
3771 }
3772
3773 if (n == FALSE)
3774 {
3775 if (STRNICMP(name, "patch", 5) == 0)
3776 {
3777 if (name[5] == '-'
3778 && STRLEN(name) >= 11
3779 && vim_isdigit(name[6])
3780 && vim_isdigit(name[8])
3781 && vim_isdigit(name[10]))
3782 {
3783 int major = atoi((char *)name + 6);
3784 int minor = atoi((char *)name + 8);
3785
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003786 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003787 n = (major < VIM_VERSION_MAJOR
3788 || (major == VIM_VERSION_MAJOR
3789 && (minor < VIM_VERSION_MINOR
3790 || (minor == VIM_VERSION_MINOR
3791 && has_patch(atoi((char *)name + 10))))));
3792 }
3793 else
3794 n = has_patch(atoi((char *)name + 5));
3795 }
3796 else if (STRICMP(name, "vim_starting") == 0)
3797 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003798 else if (STRICMP(name, "ttyin") == 0)
3799 n = mch_input_isatty();
3800 else if (STRICMP(name, "ttyout") == 0)
3801 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003802 else if (STRICMP(name, "multi_byte_encoding") == 0)
3803 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003804#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003805 else if (STRICMP(name, "balloon_multiline") == 0)
3806 n = multiline_balloon_available();
3807#endif
3808#ifdef DYNAMIC_TCL
3809 else if (STRICMP(name, "tcl") == 0)
3810 n = tcl_enabled(FALSE);
3811#endif
3812#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3813 else if (STRICMP(name, "iconv") == 0)
3814 n = iconv_enabled(FALSE);
3815#endif
3816#ifdef DYNAMIC_LUA
3817 else if (STRICMP(name, "lua") == 0)
3818 n = lua_enabled(FALSE);
3819#endif
3820#ifdef DYNAMIC_MZSCHEME
3821 else if (STRICMP(name, "mzscheme") == 0)
3822 n = mzscheme_enabled(FALSE);
3823#endif
3824#ifdef DYNAMIC_RUBY
3825 else if (STRICMP(name, "ruby") == 0)
3826 n = ruby_enabled(FALSE);
3827#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003828#ifdef DYNAMIC_PYTHON
3829 else if (STRICMP(name, "python") == 0)
3830 n = python_enabled(FALSE);
3831#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003832#ifdef DYNAMIC_PYTHON3
3833 else if (STRICMP(name, "python3") == 0)
3834 n = python3_enabled(FALSE);
3835#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003836#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3837 else if (STRICMP(name, "pythonx") == 0)
3838 {
3839# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3840 if (p_pyx == 0)
3841 n = python3_enabled(FALSE) || python_enabled(FALSE);
3842 else if (p_pyx == 3)
3843 n = python3_enabled(FALSE);
3844 else if (p_pyx == 2)
3845 n = python_enabled(FALSE);
3846# elif defined(DYNAMIC_PYTHON)
3847 n = python_enabled(FALSE);
3848# elif defined(DYNAMIC_PYTHON3)
3849 n = python3_enabled(FALSE);
3850# endif
3851 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003852#endif
3853#ifdef DYNAMIC_PERL
3854 else if (STRICMP(name, "perl") == 0)
3855 n = perl_enabled(FALSE);
3856#endif
3857#ifdef FEAT_GUI
3858 else if (STRICMP(name, "gui_running") == 0)
3859 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003860# ifdef FEAT_BROWSE
3861 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003862 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003863# endif
3864#endif
3865#ifdef FEAT_SYN_HL
3866 else if (STRICMP(name, "syntax_items") == 0)
3867 n = syntax_present(curwin);
3868#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003869#ifdef FEAT_VTP
3870 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003871 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003872#endif
3873#ifdef FEAT_NETBEANS_INTG
3874 else if (STRICMP(name, "netbeans_enabled") == 0)
3875 n = netbeans_active();
3876#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003877#ifdef FEAT_MOUSE_GPM
3878 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3879 n = gpm_enabled();
3880#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003881#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003882 else if (STRICMP(name, "terminal") == 0)
3883 n = terminal_enabled();
3884#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003885#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003886 else if (STRICMP(name, "conpty") == 0)
3887 n = use_conpty();
3888#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003889#ifdef FEAT_CLIPBOARD
3890 else if (STRICMP(name, "clipboard_working") == 0)
3891 n = clip_star.available;
3892#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003893#ifdef VIMDLL
3894 else if (STRICMP(name, "filterpipe") == 0)
3895 n = gui.in_use || gui.starting;
3896#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003897 }
3898
3899 rettv->vval.v_number = n;
3900}
3901
3902/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003903 * "haslocaldir()" function
3904 */
3905 static void
3906f_haslocaldir(typval_T *argvars, typval_T *rettv)
3907{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003908 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909 win_T *wp = NULL;
3910
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003911 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3912
3913 // Check for window-local and tab-local directories
3914 if (wp != NULL && wp->w_localdir != NULL)
3915 rettv->vval.v_number = 1;
3916 else if (tp != NULL && tp->tp_localdir != NULL)
3917 rettv->vval.v_number = 2;
3918 else
3919 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003920}
3921
3922/*
3923 * "hasmapto()" function
3924 */
3925 static void
3926f_hasmapto(typval_T *argvars, typval_T *rettv)
3927{
3928 char_u *name;
3929 char_u *mode;
3930 char_u buf[NUMBUFLEN];
3931 int abbr = FALSE;
3932
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003933 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934 if (argvars[1].v_type == VAR_UNKNOWN)
3935 mode = (char_u *)"nvo";
3936 else
3937 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003938 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003939 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003940 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003941 }
3942
3943 if (map_to_exists(name, mode, abbr))
3944 rettv->vval.v_number = TRUE;
3945 else
3946 rettv->vval.v_number = FALSE;
3947}
3948
3949/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003950 * "highlightID(name)" function
3951 */
3952 static void
3953f_hlID(typval_T *argvars, typval_T *rettv)
3954{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003955 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003956}
3957
3958/*
3959 * "highlight_exists()" function
3960 */
3961 static void
3962f_hlexists(typval_T *argvars, typval_T *rettv)
3963{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003964 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003965}
3966
3967/*
3968 * "hostname()" function
3969 */
3970 static void
3971f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3972{
3973 char_u hostname[256];
3974
3975 mch_get_host_name(hostname, 256);
3976 rettv->v_type = VAR_STRING;
3977 rettv->vval.v_string = vim_strsave(hostname);
3978}
3979
3980/*
3981 * iconv() function
3982 */
3983 static void
3984f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3985{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003986 char_u buf1[NUMBUFLEN];
3987 char_u buf2[NUMBUFLEN];
3988 char_u *from, *to, *str;
3989 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003990
3991 rettv->v_type = VAR_STRING;
3992 rettv->vval.v_string = NULL;
3993
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003994 str = tv_get_string(&argvars[0]);
3995 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3996 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003997 vimconv.vc_type = CONV_NONE;
3998 convert_setup(&vimconv, from, to);
3999
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004000 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004001 if (vimconv.vc_type == CONV_NONE)
4002 rettv->vval.v_string = vim_strsave(str);
4003 else
4004 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4005
4006 convert_setup(&vimconv, NULL, NULL);
4007 vim_free(from);
4008 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004009}
4010
4011/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004012 * "index()" function
4013 */
4014 static void
4015f_index(typval_T *argvars, typval_T *rettv)
4016{
4017 list_T *l;
4018 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004019 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020 long idx = 0;
4021 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004022 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004023
4024 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004025 if (argvars[0].v_type == VAR_BLOB)
4026 {
4027 typval_T tv;
4028 int start = 0;
4029
4030 if (argvars[2].v_type != VAR_UNKNOWN)
4031 {
4032 start = tv_get_number_chk(&argvars[2], &error);
4033 if (error)
4034 return;
4035 }
4036 b = argvars[0].vval.v_blob;
4037 if (b == NULL)
4038 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004039 if (start < 0)
4040 {
4041 start = blob_len(b) + start;
4042 if (start < 0)
4043 start = 0;
4044 }
4045
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004046 for (idx = start; idx < blob_len(b); ++idx)
4047 {
4048 tv.v_type = VAR_NUMBER;
4049 tv.vval.v_number = blob_get(b, idx);
4050 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4051 {
4052 rettv->vval.v_number = idx;
4053 return;
4054 }
4055 }
4056 return;
4057 }
4058 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004059 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004060 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004061 return;
4062 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004064 l = argvars[0].vval.v_list;
4065 if (l != NULL)
4066 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004067 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004068 item = l->lv_first;
4069 if (argvars[2].v_type != VAR_UNKNOWN)
4070 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004071 // Start at specified item. Use the cached index that list_find()
4072 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004073 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004074 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004075 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004076 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004077 if (error)
4078 item = NULL;
4079 }
4080
4081 for ( ; item != NULL; item = item->li_next, ++idx)
4082 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4083 {
4084 rettv->vval.v_number = idx;
4085 break;
4086 }
4087 }
4088}
4089
4090static int inputsecret_flag = 0;
4091
4092/*
4093 * "input()" function
4094 * Also handles inputsecret() when inputsecret is set.
4095 */
4096 static void
4097f_input(typval_T *argvars, typval_T *rettv)
4098{
4099 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4100}
4101
4102/*
4103 * "inputdialog()" function
4104 */
4105 static void
4106f_inputdialog(typval_T *argvars, typval_T *rettv)
4107{
4108#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004109 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004110 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4111 {
4112 char_u *message;
4113 char_u buf[NUMBUFLEN];
4114 char_u *defstr = (char_u *)"";
4115
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004116 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004117 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004118 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004119 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4120 else
4121 IObuff[0] = NUL;
4122 if (message != NULL && defstr != NULL
4123 && do_dialog(VIM_QUESTION, NULL, message,
4124 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4125 rettv->vval.v_string = vim_strsave(IObuff);
4126 else
4127 {
4128 if (message != NULL && defstr != NULL
4129 && argvars[1].v_type != VAR_UNKNOWN
4130 && argvars[2].v_type != VAR_UNKNOWN)
4131 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004132 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004133 else
4134 rettv->vval.v_string = NULL;
4135 }
4136 rettv->v_type = VAR_STRING;
4137 }
4138 else
4139#endif
4140 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4141}
4142
4143/*
4144 * "inputlist()" function
4145 */
4146 static void
4147f_inputlist(typval_T *argvars, typval_T *rettv)
4148{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004149 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004150 listitem_T *li;
4151 int selected;
4152 int mouse_used;
4153
4154#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004155 // While starting up, there is no place to enter text. When running tests
4156 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004157 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004158 return;
4159#endif
4160 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4161 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004162 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004163 return;
4164 }
4165
4166 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004167 msg_row = Rows - 1; // for when 'cmdheight' > 1
4168 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004169 msg_scroll = TRUE;
4170 msg_clr_eos();
4171
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004172 l = argvars[0].vval.v_list;
4173 range_list_materialize(l);
4174 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004175 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004176 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004177 msg_putchar('\n');
4178 }
4179
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004180 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004181 selected = prompt_for_number(&mouse_used);
4182 if (mouse_used)
4183 selected -= lines_left;
4184
4185 rettv->vval.v_number = selected;
4186}
4187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004188static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4189
4190/*
4191 * "inputrestore()" function
4192 */
4193 static void
4194f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4195{
4196 if (ga_userinput.ga_len > 0)
4197 {
4198 --ga_userinput.ga_len;
4199 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4200 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004201 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004202 }
4203 else if (p_verbose > 1)
4204 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004205 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004206 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004207 }
4208}
4209
4210/*
4211 * "inputsave()" function
4212 */
4213 static void
4214f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4215{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004216 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004217 if (ga_grow(&ga_userinput, 1) == OK)
4218 {
4219 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4220 + ga_userinput.ga_len);
4221 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004222 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004223 }
4224 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004225 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004226}
4227
4228/*
4229 * "inputsecret()" function
4230 */
4231 static void
4232f_inputsecret(typval_T *argvars, typval_T *rettv)
4233{
4234 ++cmdline_star;
4235 ++inputsecret_flag;
4236 f_input(argvars, rettv);
4237 --cmdline_star;
4238 --inputsecret_flag;
4239}
4240
4241/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004242 * "interrupt()" function
4243 */
4244 static void
4245f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4246{
4247 got_int = TRUE;
4248}
4249
4250/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004251 * "invert(expr)" function
4252 */
4253 static void
4254f_invert(typval_T *argvars, typval_T *rettv)
4255{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004256 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004257}
4258
4259/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004260 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4261 * or it refers to a List or Dictionary that is locked.
4262 */
4263 static int
4264tv_islocked(typval_T *tv)
4265{
4266 return (tv->v_lock & VAR_LOCKED)
4267 || (tv->v_type == VAR_LIST
4268 && tv->vval.v_list != NULL
4269 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4270 || (tv->v_type == VAR_DICT
4271 && tv->vval.v_dict != NULL
4272 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4273}
4274
4275/*
4276 * "islocked()" function
4277 */
4278 static void
4279f_islocked(typval_T *argvars, typval_T *rettv)
4280{
4281 lval_T lv;
4282 char_u *end;
4283 dictitem_T *di;
4284
4285 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004286 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004287 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004288 if (end != NULL && lv.ll_name != NULL)
4289 {
4290 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004291 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004292 else
4293 {
4294 if (lv.ll_tv == NULL)
4295 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004296 di = find_var(lv.ll_name, NULL, TRUE);
4297 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004298 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004299 // Consider a variable locked when:
4300 // 1. the variable itself is locked
4301 // 2. the value of the variable is locked.
4302 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004303 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4304 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004305 }
4306 }
4307 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004308 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004309 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004310 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004311 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004312 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004313 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4314 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004315 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004316 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4317 }
4318 }
4319
4320 clear_lval(&lv);
4321}
4322
4323#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4324/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004325 * "isinf()" function
4326 */
4327 static void
4328f_isinf(typval_T *argvars, typval_T *rettv)
4329{
4330 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4331 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4332}
4333
4334/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004335 * "isnan()" function
4336 */
4337 static void
4338f_isnan(typval_T *argvars, typval_T *rettv)
4339{
4340 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4341 && isnan(argvars[0].vval.v_float);
4342}
4343#endif
4344
4345/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004346 * "last_buffer_nr()" function.
4347 */
4348 static void
4349f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4350{
4351 int n = 0;
4352 buf_T *buf;
4353
Bram Moolenaar29323592016-07-24 22:04:11 +02004354 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004355 if (n < buf->b_fnum)
4356 n = buf->b_fnum;
4357
4358 rettv->vval.v_number = n;
4359}
4360
4361/*
4362 * "len()" function
4363 */
4364 static void
4365f_len(typval_T *argvars, typval_T *rettv)
4366{
4367 switch (argvars[0].v_type)
4368 {
4369 case VAR_STRING:
4370 case VAR_NUMBER:
4371 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004372 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004373 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004374 case VAR_BLOB:
4375 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4376 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004377 case VAR_LIST:
4378 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4379 break;
4380 case VAR_DICT:
4381 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4382 break;
4383 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004384 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004385 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004386 case VAR_SPECIAL:
4387 case VAR_FLOAT:
4388 case VAR_FUNC:
4389 case VAR_PARTIAL:
4390 case VAR_JOB:
4391 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004392 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004393 break;
4394 }
4395}
4396
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004398libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004399{
4400#ifdef FEAT_LIBCALL
4401 char_u *string_in;
4402 char_u **string_result;
4403 int nr_result;
4404#endif
4405
4406 rettv->v_type = type;
4407 if (type != VAR_NUMBER)
4408 rettv->vval.v_string = NULL;
4409
4410 if (check_restricted() || check_secure())
4411 return;
4412
4413#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004414 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004415 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4416 {
4417 string_in = NULL;
4418 if (argvars[2].v_type == VAR_STRING)
4419 string_in = argvars[2].vval.v_string;
4420 if (type == VAR_NUMBER)
4421 string_result = NULL;
4422 else
4423 string_result = &rettv->vval.v_string;
4424 if (mch_libcall(argvars[0].vval.v_string,
4425 argvars[1].vval.v_string,
4426 string_in,
4427 argvars[2].vval.v_number,
4428 string_result,
4429 &nr_result) == OK
4430 && type == VAR_NUMBER)
4431 rettv->vval.v_number = nr_result;
4432 }
4433#endif
4434}
4435
4436/*
4437 * "libcall()" function
4438 */
4439 static void
4440f_libcall(typval_T *argvars, typval_T *rettv)
4441{
4442 libcall_common(argvars, rettv, VAR_STRING);
4443}
4444
4445/*
4446 * "libcallnr()" function
4447 */
4448 static void
4449f_libcallnr(typval_T *argvars, typval_T *rettv)
4450{
4451 libcall_common(argvars, rettv, VAR_NUMBER);
4452}
4453
4454/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004455 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004456 */
4457 static void
4458f_line(typval_T *argvars, typval_T *rettv)
4459{
4460 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004461 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004462 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004463 int id;
4464 tabpage_T *tp;
4465 win_T *wp;
4466 win_T *save_curwin;
4467 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004468
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004469 if (argvars[1].v_type != VAR_UNKNOWN)
4470 {
4471 // use window specified in the second argument
4472 id = (int)tv_get_number(&argvars[1]);
4473 wp = win_id2wp_tp(id, &tp);
4474 if (wp != NULL && tp != NULL)
4475 {
4476 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4477 == OK)
4478 {
4479 check_cursor();
4480 fp = var2fpos(&argvars[0], TRUE, &fnum);
4481 }
4482 restore_win_noblock(save_curwin, save_curtab, TRUE);
4483 }
4484 }
4485 else
4486 // use current window
4487 fp = var2fpos(&argvars[0], TRUE, &fnum);
4488
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004489 if (fp != NULL)
4490 lnum = fp->lnum;
4491 rettv->vval.v_number = lnum;
4492}
4493
4494/*
4495 * "line2byte(lnum)" function
4496 */
4497 static void
4498f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4499{
4500#ifndef FEAT_BYTEOFF
4501 rettv->vval.v_number = -1;
4502#else
4503 linenr_T lnum;
4504
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004505 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004506 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4507 rettv->vval.v_number = -1;
4508 else
4509 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4510 if (rettv->vval.v_number >= 0)
4511 ++rettv->vval.v_number;
4512#endif
4513}
4514
4515/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004516 * "localtime()" function
4517 */
4518 static void
4519f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4520{
4521 rettv->vval.v_number = (varnumber_T)time(NULL);
4522}
4523
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004524#ifdef FEAT_FLOAT
4525/*
4526 * "log()" function
4527 */
4528 static void
4529f_log(typval_T *argvars, typval_T *rettv)
4530{
4531 float_T f = 0.0;
4532
4533 rettv->v_type = VAR_FLOAT;
4534 if (get_float_arg(argvars, &f) == OK)
4535 rettv->vval.v_float = log(f);
4536 else
4537 rettv->vval.v_float = 0.0;
4538}
4539
4540/*
4541 * "log10()" function
4542 */
4543 static void
4544f_log10(typval_T *argvars, typval_T *rettv)
4545{
4546 float_T f = 0.0;
4547
4548 rettv->v_type = VAR_FLOAT;
4549 if (get_float_arg(argvars, &f) == OK)
4550 rettv->vval.v_float = log10(f);
4551 else
4552 rettv->vval.v_float = 0.0;
4553}
4554#endif
4555
4556#ifdef FEAT_LUA
4557/*
4558 * "luaeval()" function
4559 */
4560 static void
4561f_luaeval(typval_T *argvars, typval_T *rettv)
4562{
4563 char_u *str;
4564 char_u buf[NUMBUFLEN];
4565
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004566 if (check_restricted() || check_secure())
4567 return;
4568
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004569 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004570 do_luaeval(str, argvars + 1, rettv);
4571}
4572#endif
4573
4574/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004575 * "maparg()" function
4576 */
4577 static void
4578f_maparg(typval_T *argvars, typval_T *rettv)
4579{
4580 get_maparg(argvars, rettv, TRUE);
4581}
4582
4583/*
4584 * "mapcheck()" function
4585 */
4586 static void
4587f_mapcheck(typval_T *argvars, typval_T *rettv)
4588{
4589 get_maparg(argvars, rettv, FALSE);
4590}
4591
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004592typedef enum
4593{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004594 MATCH_END, // matchend()
4595 MATCH_MATCH, // match()
4596 MATCH_STR, // matchstr()
4597 MATCH_LIST, // matchlist()
4598 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004599} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004600
4601 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004602find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004603{
4604 char_u *str = NULL;
4605 long len = 0;
4606 char_u *expr = NULL;
4607 char_u *pat;
4608 regmatch_T regmatch;
4609 char_u patbuf[NUMBUFLEN];
4610 char_u strbuf[NUMBUFLEN];
4611 char_u *save_cpo;
4612 long start = 0;
4613 long nth = 1;
4614 colnr_T startcol = 0;
4615 int match = 0;
4616 list_T *l = NULL;
4617 listitem_T *li = NULL;
4618 long idx = 0;
4619 char_u *tofree = NULL;
4620
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004621 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004622 save_cpo = p_cpo;
4623 p_cpo = (char_u *)"";
4624
4625 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004626 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004627 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004628 // type MATCH_LIST: return empty list when there are no matches.
4629 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004630 if (rettv_list_alloc(rettv) == FAIL)
4631 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004632 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004633 && (list_append_string(rettv->vval.v_list,
4634 (char_u *)"", 0) == FAIL
4635 || list_append_number(rettv->vval.v_list,
4636 (varnumber_T)-1) == FAIL
4637 || list_append_number(rettv->vval.v_list,
4638 (varnumber_T)-1) == FAIL
4639 || list_append_number(rettv->vval.v_list,
4640 (varnumber_T)-1) == FAIL))
4641 {
4642 list_free(rettv->vval.v_list);
4643 rettv->vval.v_list = NULL;
4644 goto theend;
4645 }
4646 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004647 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004648 {
4649 rettv->v_type = VAR_STRING;
4650 rettv->vval.v_string = NULL;
4651 }
4652
4653 if (argvars[0].v_type == VAR_LIST)
4654 {
4655 if ((l = argvars[0].vval.v_list) == NULL)
4656 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004657 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004658 li = l->lv_first;
4659 }
4660 else
4661 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004662 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663 len = (long)STRLEN(str);
4664 }
4665
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004666 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004667 if (pat == NULL)
4668 goto theend;
4669
4670 if (argvars[2].v_type != VAR_UNKNOWN)
4671 {
4672 int error = FALSE;
4673
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004674 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675 if (error)
4676 goto theend;
4677 if (l != NULL)
4678 {
4679 li = list_find(l, start);
4680 if (li == NULL)
4681 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004682 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004683 }
4684 else
4685 {
4686 if (start < 0)
4687 start = 0;
4688 if (start > len)
4689 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004690 // When "count" argument is there ignore matches before "start",
4691 // otherwise skip part of the string. Differs when pattern is "^"
4692 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 if (argvars[3].v_type != VAR_UNKNOWN)
4694 startcol = start;
4695 else
4696 {
4697 str += start;
4698 len -= start;
4699 }
4700 }
4701
4702 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004703 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004704 if (error)
4705 goto theend;
4706 }
4707
4708 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4709 if (regmatch.regprog != NULL)
4710 {
4711 regmatch.rm_ic = p_ic;
4712
4713 for (;;)
4714 {
4715 if (l != NULL)
4716 {
4717 if (li == NULL)
4718 {
4719 match = FALSE;
4720 break;
4721 }
4722 vim_free(tofree);
4723 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4724 if (str == NULL)
4725 break;
4726 }
4727
4728 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4729
4730 if (match && --nth <= 0)
4731 break;
4732 if (l == NULL && !match)
4733 break;
4734
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004735 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004736 if (l != NULL)
4737 {
4738 li = li->li_next;
4739 ++idx;
4740 }
4741 else
4742 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004743 startcol = (colnr_T)(regmatch.startp[0]
4744 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004745 if (startcol > (colnr_T)len
4746 || str + startcol <= regmatch.startp[0])
4747 {
4748 match = FALSE;
4749 break;
4750 }
4751 }
4752 }
4753
4754 if (match)
4755 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004756 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004757 {
4758 listitem_T *li1 = rettv->vval.v_list->lv_first;
4759 listitem_T *li2 = li1->li_next;
4760 listitem_T *li3 = li2->li_next;
4761 listitem_T *li4 = li3->li_next;
4762
4763 vim_free(li1->li_tv.vval.v_string);
4764 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4765 (int)(regmatch.endp[0] - regmatch.startp[0]));
4766 li3->li_tv.vval.v_number =
4767 (varnumber_T)(regmatch.startp[0] - expr);
4768 li4->li_tv.vval.v_number =
4769 (varnumber_T)(regmatch.endp[0] - expr);
4770 if (l != NULL)
4771 li2->li_tv.vval.v_number = (varnumber_T)idx;
4772 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004773 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004774 {
4775 int i;
4776
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004777 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004778 for (i = 0; i < NSUBEXP; ++i)
4779 {
4780 if (regmatch.endp[i] == NULL)
4781 {
4782 if (list_append_string(rettv->vval.v_list,
4783 (char_u *)"", 0) == FAIL)
4784 break;
4785 }
4786 else if (list_append_string(rettv->vval.v_list,
4787 regmatch.startp[i],
4788 (int)(regmatch.endp[i] - regmatch.startp[i]))
4789 == FAIL)
4790 break;
4791 }
4792 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004793 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004794 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004795 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796 if (l != NULL)
4797 copy_tv(&li->li_tv, rettv);
4798 else
4799 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4800 (int)(regmatch.endp[0] - regmatch.startp[0]));
4801 }
4802 else if (l != NULL)
4803 rettv->vval.v_number = idx;
4804 else
4805 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004806 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004807 rettv->vval.v_number =
4808 (varnumber_T)(regmatch.startp[0] - str);
4809 else
4810 rettv->vval.v_number =
4811 (varnumber_T)(regmatch.endp[0] - str);
4812 rettv->vval.v_number += (varnumber_T)(str - expr);
4813 }
4814 }
4815 vim_regfree(regmatch.regprog);
4816 }
4817
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004818theend:
4819 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004820 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004821 listitem_remove(rettv->vval.v_list,
4822 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004823 vim_free(tofree);
4824 p_cpo = save_cpo;
4825}
4826
4827/*
4828 * "match()" function
4829 */
4830 static void
4831f_match(typval_T *argvars, typval_T *rettv)
4832{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004833 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004834}
4835
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004836/*
4837 * "matchend()" function
4838 */
4839 static void
4840f_matchend(typval_T *argvars, typval_T *rettv)
4841{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004842 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004843}
4844
4845/*
4846 * "matchlist()" function
4847 */
4848 static void
4849f_matchlist(typval_T *argvars, typval_T *rettv)
4850{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004851 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852}
4853
4854/*
4855 * "matchstr()" function
4856 */
4857 static void
4858f_matchstr(typval_T *argvars, typval_T *rettv)
4859{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004860 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861}
4862
4863/*
4864 * "matchstrpos()" function
4865 */
4866 static void
4867f_matchstrpos(typval_T *argvars, typval_T *rettv)
4868{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004869 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004870}
4871
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004872 static void
4873max_min(typval_T *argvars, typval_T *rettv, int domax)
4874{
4875 varnumber_T n = 0;
4876 varnumber_T i;
4877 int error = FALSE;
4878
4879 if (argvars[0].v_type == VAR_LIST)
4880 {
4881 list_T *l;
4882 listitem_T *li;
4883
4884 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004885 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004886 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004887 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004888 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004889 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4890 n = l->lv_u.nonmat.lv_start;
4891 else
4892 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4893 * l->lv_u.nonmat.lv_stride;
4894 }
4895 else
4896 {
4897 li = l->lv_first;
4898 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004899 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004900 n = tv_get_number_chk(&li->li_tv, &error);
4901 for (;;)
4902 {
4903 li = li->li_next;
4904 if (li == NULL)
4905 break;
4906 i = tv_get_number_chk(&li->li_tv, &error);
4907 if (domax ? i > n : i < n)
4908 n = i;
4909 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910 }
4911 }
4912 }
4913 }
4914 else if (argvars[0].v_type == VAR_DICT)
4915 {
4916 dict_T *d;
4917 int first = TRUE;
4918 hashitem_T *hi;
4919 int todo;
4920
4921 d = argvars[0].vval.v_dict;
4922 if (d != NULL)
4923 {
4924 todo = (int)d->dv_hashtab.ht_used;
4925 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4926 {
4927 if (!HASHITEM_EMPTY(hi))
4928 {
4929 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004930 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931 if (first)
4932 {
4933 n = i;
4934 first = FALSE;
4935 }
4936 else if (domax ? i > n : i < n)
4937 n = i;
4938 }
4939 }
4940 }
4941 }
4942 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004943 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004944 rettv->vval.v_number = error ? 0 : n;
4945}
4946
4947/*
4948 * "max()" function
4949 */
4950 static void
4951f_max(typval_T *argvars, typval_T *rettv)
4952{
4953 max_min(argvars, rettv, TRUE);
4954}
4955
4956/*
4957 * "min()" function
4958 */
4959 static void
4960f_min(typval_T *argvars, typval_T *rettv)
4961{
4962 max_min(argvars, rettv, FALSE);
4963}
4964
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004965#if defined(FEAT_MZSCHEME) || defined(PROTO)
4966/*
4967 * "mzeval()" function
4968 */
4969 static void
4970f_mzeval(typval_T *argvars, typval_T *rettv)
4971{
4972 char_u *str;
4973 char_u buf[NUMBUFLEN];
4974
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004975 if (check_restricted() || check_secure())
4976 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004977 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004978 do_mzeval(str, rettv);
4979}
4980
4981 void
4982mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4983{
4984 typval_T argvars[3];
4985
4986 argvars[0].v_type = VAR_STRING;
4987 argvars[0].vval.v_string = name;
4988 copy_tv(args, &argvars[1]);
4989 argvars[2].v_type = VAR_UNKNOWN;
4990 f_call(argvars, rettv);
4991 clear_tv(&argvars[1]);
4992}
4993#endif
4994
4995/*
4996 * "nextnonblank()" function
4997 */
4998 static void
4999f_nextnonblank(typval_T *argvars, typval_T *rettv)
5000{
5001 linenr_T lnum;
5002
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005003 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005004 {
5005 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5006 {
5007 lnum = 0;
5008 break;
5009 }
5010 if (*skipwhite(ml_get(lnum)) != NUL)
5011 break;
5012 }
5013 rettv->vval.v_number = lnum;
5014}
5015
5016/*
5017 * "nr2char()" function
5018 */
5019 static void
5020f_nr2char(typval_T *argvars, typval_T *rettv)
5021{
5022 char_u buf[NUMBUFLEN];
5023
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005024 if (has_mbyte)
5025 {
5026 int utf8 = 0;
5027
5028 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005029 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005030 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005031 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005032 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005033 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034 }
5035 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005036 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005037 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005038 buf[1] = NUL;
5039 }
5040 rettv->v_type = VAR_STRING;
5041 rettv->vval.v_string = vim_strsave(buf);
5042}
5043
5044/*
5045 * "or(expr, expr)" function
5046 */
5047 static void
5048f_or(typval_T *argvars, typval_T *rettv)
5049{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005050 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5051 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005052}
5053
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005054#ifdef FEAT_PERL
5055/*
5056 * "perleval()" function
5057 */
5058 static void
5059f_perleval(typval_T *argvars, typval_T *rettv)
5060{
5061 char_u *str;
5062 char_u buf[NUMBUFLEN];
5063
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005064 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005065 do_perleval(str, rettv);
5066}
5067#endif
5068
5069#ifdef FEAT_FLOAT
5070/*
5071 * "pow()" function
5072 */
5073 static void
5074f_pow(typval_T *argvars, typval_T *rettv)
5075{
5076 float_T fx = 0.0, fy = 0.0;
5077
5078 rettv->v_type = VAR_FLOAT;
5079 if (get_float_arg(argvars, &fx) == OK
5080 && get_float_arg(&argvars[1], &fy) == OK)
5081 rettv->vval.v_float = pow(fx, fy);
5082 else
5083 rettv->vval.v_float = 0.0;
5084}
5085#endif
5086
5087/*
5088 * "prevnonblank()" function
5089 */
5090 static void
5091f_prevnonblank(typval_T *argvars, typval_T *rettv)
5092{
5093 linenr_T lnum;
5094
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005095 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005096 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5097 lnum = 0;
5098 else
5099 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5100 --lnum;
5101 rettv->vval.v_number = lnum;
5102}
5103
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005104// This dummy va_list is here because:
5105// - passing a NULL pointer doesn't work when va_list isn't a pointer
5106// - locally in the function results in a "used before set" warning
5107// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005108static va_list ap;
5109
5110/*
5111 * "printf()" function
5112 */
5113 static void
5114f_printf(typval_T *argvars, typval_T *rettv)
5115{
5116 char_u buf[NUMBUFLEN];
5117 int len;
5118 char_u *s;
5119 int saved_did_emsg = did_emsg;
5120 char *fmt;
5121
5122 rettv->v_type = VAR_STRING;
5123 rettv->vval.v_string = NULL;
5124
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005125 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005126 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005127 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005128 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005129 if (!did_emsg)
5130 {
5131 s = alloc(len + 1);
5132 if (s != NULL)
5133 {
5134 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005135 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5136 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137 }
5138 }
5139 did_emsg |= saved_did_emsg;
5140}
5141
5142/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005143 * "pum_getpos()" function
5144 */
5145 static void
5146f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5147{
5148 if (rettv_dict_alloc(rettv) != OK)
5149 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005150 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005151}
5152
5153/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005154 * "pumvisible()" function
5155 */
5156 static void
5157f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5158{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005159 if (pum_visible())
5160 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005161}
5162
5163#ifdef FEAT_PYTHON3
5164/*
5165 * "py3eval()" function
5166 */
5167 static void
5168f_py3eval(typval_T *argvars, typval_T *rettv)
5169{
5170 char_u *str;
5171 char_u buf[NUMBUFLEN];
5172
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005173 if (check_restricted() || check_secure())
5174 return;
5175
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005176 if (p_pyx == 0)
5177 p_pyx = 3;
5178
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005179 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005180 do_py3eval(str, rettv);
5181}
5182#endif
5183
5184#ifdef FEAT_PYTHON
5185/*
5186 * "pyeval()" function
5187 */
5188 static void
5189f_pyeval(typval_T *argvars, typval_T *rettv)
5190{
5191 char_u *str;
5192 char_u buf[NUMBUFLEN];
5193
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005194 if (check_restricted() || check_secure())
5195 return;
5196
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005197 if (p_pyx == 0)
5198 p_pyx = 2;
5199
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005200 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 do_pyeval(str, rettv);
5202}
5203#endif
5204
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005205#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5206/*
5207 * "pyxeval()" function
5208 */
5209 static void
5210f_pyxeval(typval_T *argvars, typval_T *rettv)
5211{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005212 if (check_restricted() || check_secure())
5213 return;
5214
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005215# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5216 init_pyxversion();
5217 if (p_pyx == 2)
5218 f_pyeval(argvars, rettv);
5219 else
5220 f_py3eval(argvars, rettv);
5221# elif defined(FEAT_PYTHON)
5222 f_pyeval(argvars, rettv);
5223# elif defined(FEAT_PYTHON3)
5224 f_py3eval(argvars, rettv);
5225# endif
5226}
5227#endif
5228
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005229static UINT32_T srand_seed_for_testing = 0;
5230static int srand_seed_for_testing_is_used = FALSE;
5231
5232 static void
5233f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED)
5234{
5235 if (argvars[0].v_type == VAR_UNKNOWN)
5236 srand_seed_for_testing_is_used = FALSE;
5237 else
5238 {
5239 srand_seed_for_testing = (UINT32_T)tv_get_number(&argvars[0]);
5240 srand_seed_for_testing_is_used = TRUE;
5241 }
5242}
5243
5244 static void
5245init_srand(UINT32_T *x)
5246{
5247#ifndef MSWIN
5248 static int dev_urandom_state = NOTDONE; // FAIL or OK once tried
5249#endif
5250
5251 if (srand_seed_for_testing_is_used)
5252 {
5253 *x = srand_seed_for_testing;
5254 return;
5255 }
5256#ifndef MSWIN
5257 if (dev_urandom_state != FAIL)
5258 {
5259 int fd = open("/dev/urandom", O_RDONLY);
5260 struct {
5261 union {
5262 UINT32_T number;
5263 char bytes[sizeof(UINT32_T)];
5264 } contents;
5265 } buf;
5266
5267 // Attempt reading /dev/urandom.
5268 if (fd == -1)
5269 dev_urandom_state = FAIL;
5270 else
5271 {
5272 buf.contents.number = 0;
5273 if (read(fd, buf.contents.bytes, sizeof(UINT32_T))
5274 != sizeof(UINT32_T))
5275 dev_urandom_state = FAIL;
5276 else
5277 {
5278 dev_urandom_state = OK;
5279 *x = buf.contents.number;
5280 }
5281 close(fd);
5282 }
5283 }
5284 if (dev_urandom_state != OK)
5285 // Reading /dev/urandom doesn't work, fall back to time().
5286#endif
5287 *x = vim_time();
5288}
5289
5290#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5291#define SPLITMIX32(x, z) ( \
5292 z = (x += 0x9e3779b9), \
5293 z = (z ^ (z >> 16)) * 0x85ebca6b, \
5294 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
5295 z ^ (z >> 16) \
5296 )
5297#define SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w) \
5298 result = ROTL(y * 5, 7) * 9; \
5299 t = y << 9; \
5300 z ^= x; \
5301 w ^= y; \
5302 y ^= z, x ^= w; \
5303 z ^= t; \
5304 w = ROTL(w, 11);
5305
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005306/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005307 * "rand()" function
5308 */
5309 static void
5310f_rand(typval_T *argvars, typval_T *rettv)
5311{
5312 list_T *l = NULL;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005313 static UINT32_T gx, gy, gz, gw;
5314 static int initialized = FALSE;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005315 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005316 UINT32_T x, y, z, w, t, result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005317
5318 if (argvars[0].v_type == VAR_UNKNOWN)
5319 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005320 // When no argument is given use the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005321 if (initialized == FALSE)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005322 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005323 // Initialize the global seed list.
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005324 init_srand(&x);
5325
5326 gx = SPLITMIX32(x, z);
5327 gy = SPLITMIX32(x, z);
5328 gz = SPLITMIX32(x, z);
5329 gw = SPLITMIX32(x, z);
5330 initialized = TRUE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005331 }
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005332
5333 SHUFFLE_XOSHIRO128STARSTAR(gx, gy, gz, gw);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005334 }
5335 else if (argvars[0].v_type == VAR_LIST)
5336 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005337 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005338 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005339 goto theend;
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005340
5341 lx = list_find(l, 0L);
5342 ly = list_find(l, 1L);
5343 lz = list_find(l, 2L);
5344 lw = list_find(l, 3L);
5345 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5346 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5347 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5348 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5349 x = (UINT32_T)lx->li_tv.vval.v_number;
5350 y = (UINT32_T)ly->li_tv.vval.v_number;
5351 z = (UINT32_T)lz->li_tv.vval.v_number;
5352 w = (UINT32_T)lw->li_tv.vval.v_number;
5353
5354 SHUFFLE_XOSHIRO128STARSTAR(x, y, z, w);
5355
5356 lx->li_tv.vval.v_number = (varnumber_T)x;
5357 ly->li_tv.vval.v_number = (varnumber_T)y;
5358 lz->li_tv.vval.v_number = (varnumber_T)z;
5359 lw->li_tv.vval.v_number = (varnumber_T)w;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005360 }
5361 else
5362 goto theend;
5363
5364 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005365 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005366 return;
5367
5368theend:
5369 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005370 rettv->v_type = VAR_NUMBER;
5371 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005372}
5373
5374/*
Bram Moolenaar4f645c52020-02-08 16:40:39 +01005375 * "srand()" function
5376 */
5377 static void
5378f_srand(typval_T *argvars, typval_T *rettv)
5379{
5380 UINT32_T x = 0, z;
5381
5382 if (rettv_list_alloc(rettv) == FAIL)
5383 return;
5384 if (argvars[0].v_type == VAR_UNKNOWN)
5385 {
5386 init_srand(&x);
5387 }
5388 else
5389 {
5390 int error = FALSE;
5391
5392 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
5393 if (error)
5394 return;
5395 }
5396
5397 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32(x, z));
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}
5402
5403#undef ROTL
5404#undef SPLITMIX32
5405#undef SHUFFLE_XOSHIRO128STARSTAR
5406
5407/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005408 * "range()" function
5409 */
5410 static void
5411f_range(typval_T *argvars, typval_T *rettv)
5412{
5413 varnumber_T start;
5414 varnumber_T end;
5415 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005416 int error = FALSE;
5417
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005418 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005419 if (argvars[1].v_type == VAR_UNKNOWN)
5420 {
5421 end = start - 1;
5422 start = 0;
5423 }
5424 else
5425 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005426 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005427 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005428 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005429 }
5430
5431 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005432 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005433 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005434 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005435 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005436 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005437 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005438 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005439 list_T *list = rettv->vval.v_list;
5440
5441 // Create a non-materialized list. This is much more efficient and
5442 // works with ":for". If used otherwise range_list_materialize() must
5443 // be called.
5444 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005445 list->lv_u.nonmat.lv_start = start;
5446 list->lv_u.nonmat.lv_end = end;
5447 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005448 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005449 }
5450}
5451
5452/*
5453 * If "list" is a non-materialized list then materialize it now.
5454 */
5455 void
5456range_list_materialize(list_T *list)
5457{
5458 if (list->lv_first == &range_list_item)
5459 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005460 varnumber_T start = list->lv_u.nonmat.lv_start;
5461 varnumber_T end = list->lv_u.nonmat.lv_end;
5462 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005463 varnumber_T i;
5464
5465 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005466 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005467 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005468 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005469 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5470 if (list_append_number(list, (varnumber_T)i) == FAIL)
5471 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005472 }
5473}
5474
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005475 static void
5476return_register(int regname, typval_T *rettv)
5477{
5478 char_u buf[2] = {0, 0};
5479
5480 buf[0] = (char_u)regname;
5481 rettv->v_type = VAR_STRING;
5482 rettv->vval.v_string = vim_strsave(buf);
5483}
5484
5485/*
5486 * "reg_executing()" function
5487 */
5488 static void
5489f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5490{
5491 return_register(reg_executing, rettv);
5492}
5493
5494/*
5495 * "reg_recording()" function
5496 */
5497 static void
5498f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5499{
5500 return_register(reg_recording, rettv);
5501}
5502
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005503#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504/*
5505 * Convert a List to proftime_T.
5506 * Return FAIL when there is something wrong.
5507 */
5508 static int
5509list2proftime(typval_T *arg, proftime_T *tm)
5510{
5511 long n1, n2;
5512 int error = FALSE;
5513
5514 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5515 || arg->vval.v_list->lv_len != 2)
5516 return FAIL;
5517 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5518 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005519# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005520 tm->HighPart = n1;
5521 tm->LowPart = n2;
5522# else
5523 tm->tv_sec = n1;
5524 tm->tv_usec = n2;
5525# endif
5526 return error ? FAIL : OK;
5527}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005528#endif // FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005529
5530/*
5531 * "reltime()" function
5532 */
5533 static void
5534f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5535{
5536#ifdef FEAT_RELTIME
5537 proftime_T res;
5538 proftime_T start;
5539
5540 if (argvars[0].v_type == VAR_UNKNOWN)
5541 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005542 // No arguments: get current time.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005543 profile_start(&res);
5544 }
5545 else if (argvars[1].v_type == VAR_UNKNOWN)
5546 {
5547 if (list2proftime(&argvars[0], &res) == FAIL)
5548 return;
5549 profile_end(&res);
5550 }
5551 else
5552 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005553 // Two arguments: compute the difference.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005554 if (list2proftime(&argvars[0], &start) == FAIL
5555 || list2proftime(&argvars[1], &res) == FAIL)
5556 return;
5557 profile_sub(&res, &start);
5558 }
5559
5560 if (rettv_list_alloc(rettv) == OK)
5561 {
5562 long n1, n2;
5563
Bram Moolenaar4f974752019-02-17 17:44:42 +01005564# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005565 n1 = res.HighPart;
5566 n2 = res.LowPart;
5567# else
5568 n1 = res.tv_sec;
5569 n2 = res.tv_usec;
5570# endif
5571 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5572 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5573 }
5574#endif
5575}
5576
5577#ifdef FEAT_FLOAT
5578/*
5579 * "reltimefloat()" function
5580 */
5581 static void
5582f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5583{
5584# ifdef FEAT_RELTIME
5585 proftime_T tm;
5586# endif
5587
5588 rettv->v_type = VAR_FLOAT;
5589 rettv->vval.v_float = 0;
5590# ifdef FEAT_RELTIME
5591 if (list2proftime(&argvars[0], &tm) == OK)
5592 rettv->vval.v_float = profile_float(&tm);
5593# endif
5594}
5595#endif
5596
5597/*
5598 * "reltimestr()" function
5599 */
5600 static void
5601f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5602{
5603#ifdef FEAT_RELTIME
5604 proftime_T tm;
5605#endif
5606
5607 rettv->v_type = VAR_STRING;
5608 rettv->vval.v_string = NULL;
5609#ifdef FEAT_RELTIME
5610 if (list2proftime(&argvars[0], &tm) == OK)
5611 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5612#endif
5613}
5614
5615#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005616 static void
5617make_connection(void)
5618{
5619 if (X_DISPLAY == NULL
5620# ifdef FEAT_GUI
5621 && !gui.in_use
5622# endif
5623 )
5624 {
5625 x_force_connect = TRUE;
5626 setup_term_clip();
5627 x_force_connect = FALSE;
5628 }
5629}
5630
5631 static int
5632check_connection(void)
5633{
5634 make_connection();
5635 if (X_DISPLAY == NULL)
5636 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005637 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005638 return FAIL;
5639 }
5640 return OK;
5641}
5642#endif
5643
5644#ifdef FEAT_CLIENTSERVER
5645 static void
5646remote_common(typval_T *argvars, typval_T *rettv, int expr)
5647{
5648 char_u *server_name;
5649 char_u *keys;
5650 char_u *r = NULL;
5651 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005652 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005653# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005654 HWND w;
5655# else
5656 Window w;
5657# endif
5658
5659 if (check_restricted() || check_secure())
5660 return;
5661
5662# ifdef FEAT_X11
5663 if (check_connection() == FAIL)
5664 return;
5665# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005666 if (argvars[2].v_type != VAR_UNKNOWN
5667 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005668 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005669
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005670 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005671 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005672 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005673 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005674# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005675 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005676# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005677 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5678 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005679# endif
5680 {
5681 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005682 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005683 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005684 vim_free(r);
5685 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005686 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005687 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005688 return;
5689 }
5690
5691 rettv->vval.v_string = r;
5692
5693 if (argvars[2].v_type != VAR_UNKNOWN)
5694 {
5695 dictitem_T v;
5696 char_u str[30];
5697 char_u *idvar;
5698
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005699 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005700 if (idvar != NULL && *idvar != NUL)
5701 {
5702 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5703 v.di_tv.v_type = VAR_STRING;
5704 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005705 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005706 vim_free(v.di_tv.vval.v_string);
5707 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005708 }
5709}
5710#endif
5711
5712/*
5713 * "remote_expr()" function
5714 */
5715 static void
5716f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5717{
5718 rettv->v_type = VAR_STRING;
5719 rettv->vval.v_string = NULL;
5720#ifdef FEAT_CLIENTSERVER
5721 remote_common(argvars, rettv, TRUE);
5722#endif
5723}
5724
5725/*
5726 * "remote_foreground()" function
5727 */
5728 static void
5729f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5730{
5731#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005732# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005733 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005735 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005736
5737 if (server_name != NULL)
5738 serverForeground(server_name);
5739 }
5740# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005741 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005742 argvars[1].v_type = VAR_STRING;
5743 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5744 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005745 rettv->v_type = VAR_STRING;
5746 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005747 remote_common(argvars, rettv, TRUE);
5748 vim_free(argvars[1].vval.v_string);
5749# endif
5750#endif
5751}
5752
5753 static void
5754f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5755{
5756#ifdef FEAT_CLIENTSERVER
5757 dictitem_T v;
5758 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005759# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005760 long_u n = 0;
5761# endif
5762 char_u *serverid;
5763
5764 if (check_restricted() || check_secure())
5765 {
5766 rettv->vval.v_number = -1;
5767 return;
5768 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005769 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005770 if (serverid == NULL)
5771 {
5772 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005773 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005774 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005775# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005776 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5777 if (n == 0)
5778 rettv->vval.v_number = -1;
5779 else
5780 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005781 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005782 rettv->vval.v_number = (s != NULL);
5783 }
5784# else
5785 if (check_connection() == FAIL)
5786 return;
5787
5788 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5789 serverStrToWin(serverid), &s);
5790# endif
5791
5792 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5793 {
5794 char_u *retvar;
5795
5796 v.di_tv.v_type = VAR_STRING;
5797 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005798 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799 if (retvar != NULL)
5800 set_var(retvar, &v.di_tv, FALSE);
5801 vim_free(v.di_tv.vval.v_string);
5802 }
5803#else
5804 rettv->vval.v_number = -1;
5805#endif
5806}
5807
5808 static void
5809f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5810{
5811 char_u *r = NULL;
5812
5813#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005814 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005815
5816 if (serverid != NULL && !check_restricted() && !check_secure())
5817 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005818 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005819# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005820 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005821 long_u n = 0;
5822# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005823
5824 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005825 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005826
Bram Moolenaar4f974752019-02-17 17:44:42 +01005827# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005828 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5829 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005830 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005831 if (r == NULL)
5832# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005833 if (check_connection() == FAIL
5834 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5835 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005836# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005837 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005838 }
5839#endif
5840 rettv->v_type = VAR_STRING;
5841 rettv->vval.v_string = r;
5842}
5843
5844/*
5845 * "remote_send()" function
5846 */
5847 static void
5848f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5849{
5850 rettv->v_type = VAR_STRING;
5851 rettv->vval.v_string = NULL;
5852#ifdef FEAT_CLIENTSERVER
5853 remote_common(argvars, rettv, FALSE);
5854#endif
5855}
5856
5857/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005858 * "remote_startserver()" function
5859 */
5860 static void
5861f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5862{
5863#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005864 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005865
5866 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005867 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005868 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005869 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005870 else
5871 {
5872# ifdef FEAT_X11
5873 if (check_connection() == OK)
5874 serverRegisterName(X_DISPLAY, server);
5875# else
5876 serverSetName(server);
5877# endif
5878 }
5879#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005880 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005881#endif
5882}
5883
5884/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885 * "rename({from}, {to})" function
5886 */
5887 static void
5888f_rename(typval_T *argvars, typval_T *rettv)
5889{
5890 char_u buf[NUMBUFLEN];
5891
5892 if (check_restricted() || check_secure())
5893 rettv->vval.v_number = -1;
5894 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005895 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5896 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005897}
5898
5899/*
5900 * "repeat()" function
5901 */
5902 static void
5903f_repeat(typval_T *argvars, typval_T *rettv)
5904{
5905 char_u *p;
5906 int n;
5907 int slen;
5908 int len;
5909 char_u *r;
5910 int i;
5911
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005912 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005913 if (argvars[0].v_type == VAR_LIST)
5914 {
5915 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5916 while (n-- > 0)
5917 if (list_extend(rettv->vval.v_list,
5918 argvars[0].vval.v_list, NULL) == FAIL)
5919 break;
5920 }
5921 else
5922 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005923 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005924 rettv->v_type = VAR_STRING;
5925 rettv->vval.v_string = NULL;
5926
5927 slen = (int)STRLEN(p);
5928 len = slen * n;
5929 if (len <= 0)
5930 return;
5931
5932 r = alloc(len + 1);
5933 if (r != NULL)
5934 {
5935 for (i = 0; i < n; i++)
5936 mch_memmove(r + i * slen, p, (size_t)slen);
5937 r[len] = NUL;
5938 }
5939
5940 rettv->vval.v_string = r;
5941 }
5942}
5943
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005944#define SP_NOMOVE 0x01 // don't move cursor
5945#define SP_REPEAT 0x02 // repeat to find outer pair
5946#define SP_RETCOUNT 0x04 // return matchcount
5947#define SP_SETPCMARK 0x08 // set previous context mark
5948#define SP_START 0x10 // accept match at start position
5949#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5950#define SP_END 0x40 // leave cursor at end of match
5951#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005952
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005953/*
5954 * Get flags for a search function.
5955 * Possibly sets "p_ws".
5956 * Returns BACKWARD, FORWARD or zero (for an error).
5957 */
5958 static int
5959get_search_arg(typval_T *varp, int *flagsp)
5960{
5961 int dir = FORWARD;
5962 char_u *flags;
5963 char_u nbuf[NUMBUFLEN];
5964 int mask;
5965
5966 if (varp->v_type != VAR_UNKNOWN)
5967 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005968 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005969 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005970 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005971 while (*flags != NUL)
5972 {
5973 switch (*flags)
5974 {
5975 case 'b': dir = BACKWARD; break;
5976 case 'w': p_ws = TRUE; break;
5977 case 'W': p_ws = FALSE; break;
5978 default: mask = 0;
5979 if (flagsp != NULL)
5980 switch (*flags)
5981 {
5982 case 'c': mask = SP_START; break;
5983 case 'e': mask = SP_END; break;
5984 case 'm': mask = SP_RETCOUNT; break;
5985 case 'n': mask = SP_NOMOVE; break;
5986 case 'p': mask = SP_SUBPAT; break;
5987 case 'r': mask = SP_REPEAT; break;
5988 case 's': mask = SP_SETPCMARK; break;
5989 case 'z': mask = SP_COLUMN; break;
5990 }
5991 if (mask == 0)
5992 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005993 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005994 dir = 0;
5995 }
5996 else
5997 *flagsp |= mask;
5998 }
5999 if (dir == 0)
6000 break;
6001 ++flags;
6002 }
6003 }
6004 return dir;
6005}
6006
6007/*
6008 * Shared by search() and searchpos() functions.
6009 */
6010 static int
6011search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
6012{
6013 int flags;
6014 char_u *pat;
6015 pos_T pos;
6016 pos_T save_cursor;
6017 int save_p_ws = p_ws;
6018 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006019 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006020 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006021#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006022 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 long time_limit = 0;
6024#endif
6025 int options = SEARCH_KEEP;
6026 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006027 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006028
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006029 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006030 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006031 if (dir == 0)
6032 goto theend;
6033 flags = *flagsp;
6034 if (flags & SP_START)
6035 options |= SEARCH_START;
6036 if (flags & SP_END)
6037 options |= SEARCH_END;
6038 if (flags & SP_COLUMN)
6039 options |= SEARCH_COL;
6040
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006041 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006042 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
6043 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006044 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006045 if (lnum_stop < 0)
6046 goto theend;
6047#ifdef FEAT_RELTIME
6048 if (argvars[3].v_type != VAR_UNKNOWN)
6049 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006050 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006051 if (time_limit < 0)
6052 goto theend;
6053 }
6054#endif
6055 }
6056
6057#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006058 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006059 profile_setlimit(time_limit, &tm);
6060#endif
6061
6062 /*
6063 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
6064 * Check to make sure only those flags are set.
6065 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
6066 * flags cannot be set. Check for that condition also.
6067 */
6068 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
6069 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6070 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006071 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006072 goto theend;
6073 }
6074
6075 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006076 vim_memset(&sia, 0, sizeof(sia));
6077 sia.sa_stop_lnum = (linenr_T)lnum_stop;
6078#ifdef FEAT_RELTIME
6079 sia.sa_tm = &tm;
6080#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006081 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006082 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083 if (subpatnum != FAIL)
6084 {
6085 if (flags & SP_SUBPAT)
6086 retval = subpatnum;
6087 else
6088 retval = pos.lnum;
6089 if (flags & SP_SETPCMARK)
6090 setpcmark();
6091 curwin->w_cursor = pos;
6092 if (match_pos != NULL)
6093 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006094 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006095 match_pos->lnum = pos.lnum;
6096 match_pos->col = pos.col + 1;
6097 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006098 // "/$" will put the cursor after the end of the line, may need to
6099 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006100 check_cursor();
6101 }
6102
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006103 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006104 if (flags & SP_NOMOVE)
6105 curwin->w_cursor = save_cursor;
6106 else
6107 curwin->w_set_curswant = TRUE;
6108theend:
6109 p_ws = save_p_ws;
6110
6111 return retval;
6112}
6113
6114#ifdef FEAT_FLOAT
6115
6116/*
6117 * round() is not in C90, use ceil() or floor() instead.
6118 */
6119 float_T
6120vim_round(float_T f)
6121{
6122 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6123}
6124
6125/*
6126 * "round({float})" function
6127 */
6128 static void
6129f_round(typval_T *argvars, typval_T *rettv)
6130{
6131 float_T f = 0.0;
6132
6133 rettv->v_type = VAR_FLOAT;
6134 if (get_float_arg(argvars, &f) == OK)
6135 rettv->vval.v_float = vim_round(f);
6136 else
6137 rettv->vval.v_float = 0.0;
6138}
6139#endif
6140
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006141#ifdef FEAT_RUBY
6142/*
6143 * "rubyeval()" function
6144 */
6145 static void
6146f_rubyeval(typval_T *argvars, typval_T *rettv)
6147{
6148 char_u *str;
6149 char_u buf[NUMBUFLEN];
6150
6151 str = tv_get_string_buf(&argvars[0], buf);
6152 do_rubyeval(str, rettv);
6153}
6154#endif
6155
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006156/*
6157 * "screenattr()" function
6158 */
6159 static void
6160f_screenattr(typval_T *argvars, typval_T *rettv)
6161{
6162 int row;
6163 int col;
6164 int c;
6165
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006166 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6167 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006168 if (row < 0 || row >= screen_Rows
6169 || col < 0 || col >= screen_Columns)
6170 c = -1;
6171 else
6172 c = ScreenAttrs[LineOffset[row] + col];
6173 rettv->vval.v_number = c;
6174}
6175
6176/*
6177 * "screenchar()" function
6178 */
6179 static void
6180f_screenchar(typval_T *argvars, typval_T *rettv)
6181{
6182 int row;
6183 int col;
6184 int off;
6185 int c;
6186
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006187 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6188 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006189 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190 c = -1;
6191 else
6192 {
6193 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 if (enc_utf8 && ScreenLinesUC[off] != 0)
6195 c = ScreenLinesUC[off];
6196 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197 c = ScreenLines[off];
6198 }
6199 rettv->vval.v_number = c;
6200}
6201
6202/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006203 * "screenchars()" function
6204 */
6205 static void
6206f_screenchars(typval_T *argvars, typval_T *rettv)
6207{
6208 int row;
6209 int col;
6210 int off;
6211 int c;
6212 int i;
6213
6214 if (rettv_list_alloc(rettv) == FAIL)
6215 return;
6216 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6217 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6218 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6219 return;
6220
6221 off = LineOffset[row] + col;
6222 if (enc_utf8 && ScreenLinesUC[off] != 0)
6223 c = ScreenLinesUC[off];
6224 else
6225 c = ScreenLines[off];
6226 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6227
6228 if (enc_utf8)
6229
6230 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6231 list_append_number(rettv->vval.v_list,
6232 (varnumber_T)ScreenLinesC[i][off]);
6233}
6234
6235/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006236 * "screencol()" function
6237 *
6238 * First column is 1 to be consistent with virtcol().
6239 */
6240 static void
6241f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6242{
6243 rettv->vval.v_number = screen_screencol() + 1;
6244}
6245
6246/*
6247 * "screenrow()" function
6248 */
6249 static void
6250f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6251{
6252 rettv->vval.v_number = screen_screenrow() + 1;
6253}
6254
6255/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006256 * "screenstring()" function
6257 */
6258 static void
6259f_screenstring(typval_T *argvars, typval_T *rettv)
6260{
6261 int row;
6262 int col;
6263 int off;
6264 int c;
6265 int i;
6266 char_u buf[MB_MAXBYTES + 1];
6267 int buflen = 0;
6268
6269 rettv->vval.v_string = NULL;
6270 rettv->v_type = VAR_STRING;
6271
6272 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6273 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6274 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6275 return;
6276
6277 off = LineOffset[row] + col;
6278 if (enc_utf8 && ScreenLinesUC[off] != 0)
6279 c = ScreenLinesUC[off];
6280 else
6281 c = ScreenLines[off];
6282 buflen += mb_char2bytes(c, buf);
6283
6284 if (enc_utf8)
6285 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6286 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6287
6288 buf[buflen] = NUL;
6289 rettv->vval.v_string = vim_strsave(buf);
6290}
6291
6292/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006293 * "search()" function
6294 */
6295 static void
6296f_search(typval_T *argvars, typval_T *rettv)
6297{
6298 int flags = 0;
6299
6300 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6301}
6302
6303/*
6304 * "searchdecl()" function
6305 */
6306 static void
6307f_searchdecl(typval_T *argvars, typval_T *rettv)
6308{
6309 int locally = 1;
6310 int thisblock = 0;
6311 int error = FALSE;
6312 char_u *name;
6313
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006314 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006316 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006317 if (argvars[1].v_type != VAR_UNKNOWN)
6318 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006319 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006320 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006321 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006322 }
6323 if (!error && name != NULL)
6324 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6325 locally, thisblock, SEARCH_KEEP) == FAIL;
6326}
6327
6328/*
6329 * Used by searchpair() and searchpairpos()
6330 */
6331 static int
6332searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6333{
6334 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006335 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006336 int save_p_ws = p_ws;
6337 int dir;
6338 int flags = 0;
6339 char_u nbuf1[NUMBUFLEN];
6340 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006341 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006342 long lnum_stop = 0;
6343 long time_limit = 0;
6344
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006345 // Get the three pattern arguments: start, middle, end. Will result in an
6346 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006347 spat = tv_get_string_chk(&argvars[0]);
6348 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6349 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006350 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006351 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006352
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006353 // Handle the optional fourth argument: flags
6354 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006355 if (dir == 0)
6356 goto theend;
6357
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006358 // Don't accept SP_END or SP_SUBPAT.
6359 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006360 if ((flags & (SP_END | SP_SUBPAT)) != 0
6361 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6362 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006363 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006364 goto theend;
6365 }
6366
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006367 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006368 if (flags & SP_REPEAT)
6369 p_ws = FALSE;
6370
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006371 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006372 if (argvars[3].v_type == VAR_UNKNOWN
6373 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006374 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006375 else
6376 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006377 skip = &argvars[4];
6378 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6379 && skip->v_type != VAR_STRING)
6380 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006381 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006382 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006383 goto theend;
6384 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006385 if (argvars[5].v_type != VAR_UNKNOWN)
6386 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006387 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006388 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006389 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006390 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006391 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006392 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393#ifdef FEAT_RELTIME
6394 if (argvars[6].v_type != VAR_UNKNOWN)
6395 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006396 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006397 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006398 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006399 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006400 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006401 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006402 }
6403#endif
6404 }
6405 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406
6407 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6408 match_pos, lnum_stop, time_limit);
6409
6410theend:
6411 p_ws = save_p_ws;
6412
6413 return retval;
6414}
6415
6416/*
6417 * "searchpair()" function
6418 */
6419 static void
6420f_searchpair(typval_T *argvars, typval_T *rettv)
6421{
6422 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6423}
6424
6425/*
6426 * "searchpairpos()" function
6427 */
6428 static void
6429f_searchpairpos(typval_T *argvars, typval_T *rettv)
6430{
6431 pos_T match_pos;
6432 int lnum = 0;
6433 int col = 0;
6434
6435 if (rettv_list_alloc(rettv) == FAIL)
6436 return;
6437
6438 if (searchpair_cmn(argvars, &match_pos) > 0)
6439 {
6440 lnum = match_pos.lnum;
6441 col = match_pos.col;
6442 }
6443
6444 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6445 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6446}
6447
6448/*
6449 * Search for a start/middle/end thing.
6450 * Used by searchpair(), see its documentation for the details.
6451 * Returns 0 or -1 for no match,
6452 */
6453 long
6454do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006455 char_u *spat, // start pattern
6456 char_u *mpat, // middle pattern
6457 char_u *epat, // end pattern
6458 int dir, // BACKWARD or FORWARD
6459 typval_T *skip, // skip expression
6460 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006461 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006462 linenr_T lnum_stop, // stop at this line if not zero
6463 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006464{
6465 char_u *save_cpo;
6466 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6467 long retval = 0;
6468 pos_T pos;
6469 pos_T firstpos;
6470 pos_T foundpos;
6471 pos_T save_cursor;
6472 pos_T save_pos;
6473 int n;
6474 int r;
6475 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006476 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006477 int err;
6478 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006479#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006480 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006481#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006482
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006483 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 save_cpo = p_cpo;
6485 p_cpo = empty_option;
6486
6487#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006488 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489 profile_setlimit(time_limit, &tm);
6490#endif
6491
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006492 // Make two search patterns: start/end (pat2, for in nested pairs) and
6493 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006494 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6495 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496 if (pat2 == NULL || pat3 == NULL)
6497 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006498 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499 if (*mpat == NUL)
6500 STRCPY(pat3, pat2);
6501 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006502 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503 spat, epat, mpat);
6504 if (flags & SP_START)
6505 options |= SEARCH_START;
6506
Bram Moolenaar48570482017-10-30 21:48:41 +01006507 if (skip != NULL)
6508 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006509 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006510 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6511 use_skip = skip->vval.v_string != NULL
6512 && *skip->vval.v_string != NUL;
6513 }
6514
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006515 save_cursor = curwin->w_cursor;
6516 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006517 CLEAR_POS(&firstpos);
6518 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006519 pat = pat3;
6520 for (;;)
6521 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006522 searchit_arg_T sia;
6523
6524 vim_memset(&sia, 0, sizeof(sia));
6525 sia.sa_stop_lnum = lnum_stop;
6526#ifdef FEAT_RELTIME
6527 sia.sa_tm = &tm;
6528#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006529 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006530 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006531 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006532 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006533 break;
6534
6535 if (firstpos.lnum == 0)
6536 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006537 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006539 // Found the same position again. Can happen with a pattern that
6540 // has "\zs" at the end and searching backwards. Advance one
6541 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006542 if (dir == BACKWARD)
6543 decl(&pos);
6544 else
6545 incl(&pos);
6546 }
6547 foundpos = pos;
6548
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006549 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 options &= ~SEARCH_START;
6551
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006552 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006553 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006554 {
6555 save_pos = curwin->w_cursor;
6556 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006557 err = FALSE;
6558 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006559 curwin->w_cursor = save_pos;
6560 if (err)
6561 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006562 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006563 curwin->w_cursor = save_cursor;
6564 retval = -1;
6565 break;
6566 }
6567 if (r)
6568 continue;
6569 }
6570
6571 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6572 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006573 // Found end when searching backwards or start when searching
6574 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006575 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006576 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006577 }
6578 else
6579 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006580 // Found end when searching forward or start when searching
6581 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006582 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006583 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006584 }
6585
6586 if (nest == 0)
6587 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006588 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006589 if (flags & SP_RETCOUNT)
6590 ++retval;
6591 else
6592 retval = pos.lnum;
6593 if (flags & SP_SETPCMARK)
6594 setpcmark();
6595 curwin->w_cursor = pos;
6596 if (!(flags & SP_REPEAT))
6597 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006598 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006599 }
6600 }
6601
6602 if (match_pos != NULL)
6603 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006604 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006605 match_pos->lnum = curwin->w_cursor.lnum;
6606 match_pos->col = curwin->w_cursor.col + 1;
6607 }
6608
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006609 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006610 if ((flags & SP_NOMOVE) || retval == 0)
6611 curwin->w_cursor = save_cursor;
6612
6613theend:
6614 vim_free(pat2);
6615 vim_free(pat3);
6616 if (p_cpo == empty_option)
6617 p_cpo = save_cpo;
6618 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006619 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006620 free_string_option(save_cpo);
6621
6622 return retval;
6623}
6624
6625/*
6626 * "searchpos()" function
6627 */
6628 static void
6629f_searchpos(typval_T *argvars, typval_T *rettv)
6630{
6631 pos_T match_pos;
6632 int lnum = 0;
6633 int col = 0;
6634 int n;
6635 int flags = 0;
6636
6637 if (rettv_list_alloc(rettv) == FAIL)
6638 return;
6639
6640 n = search_cmn(argvars, &match_pos, &flags);
6641 if (n > 0)
6642 {
6643 lnum = match_pos.lnum;
6644 col = match_pos.col;
6645 }
6646
6647 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6648 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6649 if (flags & SP_SUBPAT)
6650 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6651}
6652
6653 static void
6654f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6655{
6656#ifdef FEAT_CLIENTSERVER
6657 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006658 char_u *server = tv_get_string_chk(&argvars[0]);
6659 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006660
6661 rettv->vval.v_number = -1;
6662 if (server == NULL || reply == NULL)
6663 return;
6664 if (check_restricted() || check_secure())
6665 return;
6666# ifdef FEAT_X11
6667 if (check_connection() == FAIL)
6668 return;
6669# endif
6670
6671 if (serverSendReply(server, reply) < 0)
6672 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006673 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006674 return;
6675 }
6676 rettv->vval.v_number = 0;
6677#else
6678 rettv->vval.v_number = -1;
6679#endif
6680}
6681
6682 static void
6683f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6684{
6685 char_u *r = NULL;
6686
6687#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006688# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 r = serverGetVimNames();
6690# else
6691 make_connection();
6692 if (X_DISPLAY != NULL)
6693 r = serverGetVimNames(X_DISPLAY);
6694# endif
6695#endif
6696 rettv->v_type = VAR_STRING;
6697 rettv->vval.v_string = r;
6698}
6699
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006700 static void
6701f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6702{
6703 dict_T *d;
6704 dictitem_T *di;
6705 char_u *csearch;
6706
6707 if (argvars[0].v_type != VAR_DICT)
6708 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006709 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006710 return;
6711 }
6712
6713 if ((d = argvars[0].vval.v_dict) != NULL)
6714 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006715 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006716 if (csearch != NULL)
6717 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006718 if (enc_utf8)
6719 {
6720 int pcc[MAX_MCO];
6721 int c = utfc_ptr2char(csearch, pcc);
6722
6723 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6724 }
6725 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006727 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006728 }
6729
6730 di = dict_find(d, (char_u *)"forward", -1);
6731 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006732 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006733 ? FORWARD : BACKWARD);
6734
6735 di = dict_find(d, (char_u *)"until", -1);
6736 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006737 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006738 }
6739}
6740
6741/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006742 * "setenv()" function
6743 */
6744 static void
6745f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6746{
6747 char_u namebuf[NUMBUFLEN];
6748 char_u valbuf[NUMBUFLEN];
6749 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6750
6751 if (argvars[1].v_type == VAR_SPECIAL
6752 && argvars[1].vval.v_number == VVAL_NULL)
6753 vim_unsetenv(name);
6754 else
6755 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6756}
6757
6758/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006759 * "setfperm({fname}, {mode})" function
6760 */
6761 static void
6762f_setfperm(typval_T *argvars, typval_T *rettv)
6763{
6764 char_u *fname;
6765 char_u modebuf[NUMBUFLEN];
6766 char_u *mode_str;
6767 int i;
6768 int mask;
6769 int mode = 0;
6770
6771 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006772 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006773 if (fname == NULL)
6774 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006775 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776 if (mode_str == NULL)
6777 return;
6778 if (STRLEN(mode_str) != 9)
6779 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006780 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006781 return;
6782 }
6783
6784 mask = 1;
6785 for (i = 8; i >= 0; --i)
6786 {
6787 if (mode_str[i] != '-')
6788 mode |= mask;
6789 mask = mask << 1;
6790 }
6791 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6792}
6793
6794/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006795 * "setpos()" function
6796 */
6797 static void
6798f_setpos(typval_T *argvars, typval_T *rettv)
6799{
6800 pos_T pos;
6801 int fnum;
6802 char_u *name;
6803 colnr_T curswant = -1;
6804
6805 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006806 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006807 if (name != NULL)
6808 {
6809 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6810 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006811 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006812 pos.col = 0;
6813 if (name[0] == '.' && name[1] == NUL)
6814 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006815 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006816 curwin->w_cursor = pos;
6817 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006818 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006819 curwin->w_curswant = curswant - 1;
6820 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006821 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006822 check_cursor();
6823 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006824 }
6825 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6826 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006827 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006828 if (setmark_pos(name[1], &pos, fnum) == OK)
6829 rettv->vval.v_number = 0;
6830 }
6831 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006832 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006833 }
6834 }
6835}
6836
6837/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006838 * "setreg()" function
6839 */
6840 static void
6841f_setreg(typval_T *argvars, typval_T *rettv)
6842{
6843 int regname;
6844 char_u *strregname;
6845 char_u *stropt;
6846 char_u *strval;
6847 int append;
6848 char_u yank_type;
6849 long block_len;
6850
6851 block_len = -1;
6852 yank_type = MAUTO;
6853 append = FALSE;
6854
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006855 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006856 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006857
6858 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006859 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006860 regname = *strregname;
6861 if (regname == 0 || regname == '@')
6862 regname = '"';
6863
6864 if (argvars[2].v_type != VAR_UNKNOWN)
6865 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006866 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006867 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006868 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869 for (; *stropt != NUL; ++stropt)
6870 switch (*stropt)
6871 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006872 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006873 append = TRUE;
6874 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006875 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006876 yank_type = MCHAR;
6877 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006878 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006879 yank_type = MLINE;
6880 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006881 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006882 yank_type = MBLOCK;
6883 if (VIM_ISDIGIT(stropt[1]))
6884 {
6885 ++stropt;
6886 block_len = getdigits(&stropt) - 1;
6887 --stropt;
6888 }
6889 break;
6890 }
6891 }
6892
6893 if (argvars[1].v_type == VAR_LIST)
6894 {
6895 char_u **lstval;
6896 char_u **allocval;
6897 char_u buf[NUMBUFLEN];
6898 char_u **curval;
6899 char_u **curallocval;
6900 list_T *ll = argvars[1].vval.v_list;
6901 listitem_T *li;
6902 int len;
6903
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006904 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006905 len = ll == NULL ? 0 : ll->lv_len;
6906
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006907 // First half: use for pointers to result lines; second half: use for
6908 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006909 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006910 if (lstval == NULL)
6911 return;
6912 curval = lstval;
6913 allocval = lstval + len + 2;
6914 curallocval = allocval;
6915
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006916 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006917 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006918 range_list_materialize(ll);
6919 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006920 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006921 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006922 if (strval == NULL)
6923 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006924 if (strval == buf)
6925 {
6926 // Need to make a copy, next tv_get_string_buf_chk() will
6927 // overwrite the string.
6928 strval = vim_strsave(buf);
6929 if (strval == NULL)
6930 goto free_lstval;
6931 *curallocval++ = strval;
6932 }
6933 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006934 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006935 }
6936 *curval++ = NULL;
6937
6938 write_reg_contents_lst(regname, lstval, -1,
6939 append, yank_type, block_len);
6940free_lstval:
6941 while (curallocval > allocval)
6942 vim_free(*--curallocval);
6943 vim_free(lstval);
6944 }
6945 else
6946 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006947 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006948 if (strval == NULL)
6949 return;
6950 write_reg_contents_ex(regname, strval, -1,
6951 append, yank_type, block_len);
6952 }
6953 rettv->vval.v_number = 0;
6954}
6955
6956/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006957 * "settagstack()" function
6958 */
6959 static void
6960f_settagstack(typval_T *argvars, typval_T *rettv)
6961{
6962 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6963 win_T *wp;
6964 dict_T *d;
6965 int action = 'r';
6966
6967 rettv->vval.v_number = -1;
6968
6969 // first argument: window number or id
6970 wp = find_win_by_nr_or_id(&argvars[0]);
6971 if (wp == NULL)
6972 return;
6973
6974 // second argument: dict with items to set in the tag stack
6975 if (argvars[1].v_type != VAR_DICT)
6976 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006977 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006978 return;
6979 }
6980 d = argvars[1].vval.v_dict;
6981 if (d == NULL)
6982 return;
6983
6984 // third argument: action - 'a' for append and 'r' for replace.
6985 // default is to replace the stack.
6986 if (argvars[2].v_type == VAR_UNKNOWN)
6987 action = 'r';
6988 else if (argvars[2].v_type == VAR_STRING)
6989 {
6990 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006991 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006992 if (actstr == NULL)
6993 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006994 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6995 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006996 action = *actstr;
6997 else
6998 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006999 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007000 return;
7001 }
7002 }
7003 else
7004 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007005 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01007006 return;
7007 }
7008
7009 if (set_tagstack(wp, d, action) == OK)
7010 rettv->vval.v_number = 0;
7011}
7012
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007013#ifdef FEAT_CRYPT
7014/*
7015 * "sha256({string})" function
7016 */
7017 static void
7018f_sha256(typval_T *argvars, typval_T *rettv)
7019{
7020 char_u *p;
7021
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007022 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007023 rettv->vval.v_string = vim_strsave(
7024 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
7025 rettv->v_type = VAR_STRING;
7026}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007027#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007028
7029/*
7030 * "shellescape({string})" function
7031 */
7032 static void
7033f_shellescape(typval_T *argvars, typval_T *rettv)
7034{
Bram Moolenaar20615522017-06-05 18:46:26 +02007035 int do_special = non_zero_arg(&argvars[1]);
7036
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007037 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007038 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039 rettv->v_type = VAR_STRING;
7040}
7041
7042/*
7043 * shiftwidth() function
7044 */
7045 static void
7046f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
7047{
Bram Moolenaarf9514162018-11-22 03:08:29 +01007048 rettv->vval.v_number = 0;
7049
7050 if (argvars[0].v_type != VAR_UNKNOWN)
7051 {
7052 long col;
7053
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007054 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01007055 if (col < 0)
7056 return; // type error; errmsg already given
7057#ifdef FEAT_VARTABS
7058 rettv->vval.v_number = get_sw_value_col(curbuf, col);
7059 return;
7060#endif
7061 }
7062
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007063 rettv->vval.v_number = get_sw_value(curbuf);
7064}
7065
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007066#ifdef FEAT_FLOAT
7067/*
7068 * "sin()" function
7069 */
7070 static void
7071f_sin(typval_T *argvars, typval_T *rettv)
7072{
7073 float_T f = 0.0;
7074
7075 rettv->v_type = VAR_FLOAT;
7076 if (get_float_arg(argvars, &f) == OK)
7077 rettv->vval.v_float = sin(f);
7078 else
7079 rettv->vval.v_float = 0.0;
7080}
7081
7082/*
7083 * "sinh()" function
7084 */
7085 static void
7086f_sinh(typval_T *argvars, typval_T *rettv)
7087{
7088 float_T f = 0.0;
7089
7090 rettv->v_type = VAR_FLOAT;
7091 if (get_float_arg(argvars, &f) == OK)
7092 rettv->vval.v_float = sinh(f);
7093 else
7094 rettv->vval.v_float = 0.0;
7095}
7096#endif
7097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007098/*
7099 * "soundfold({word})" function
7100 */
7101 static void
7102f_soundfold(typval_T *argvars, typval_T *rettv)
7103{
7104 char_u *s;
7105
7106 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007107 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007108#ifdef FEAT_SPELL
7109 rettv->vval.v_string = eval_soundfold(s);
7110#else
7111 rettv->vval.v_string = vim_strsave(s);
7112#endif
7113}
7114
7115/*
7116 * "spellbadword()" function
7117 */
7118 static void
7119f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7120{
7121 char_u *word = (char_u *)"";
7122 hlf_T attr = HLF_COUNT;
7123 int len = 0;
7124
7125 if (rettv_list_alloc(rettv) == FAIL)
7126 return;
7127
7128#ifdef FEAT_SPELL
7129 if (argvars[0].v_type == VAR_UNKNOWN)
7130 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007131 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007132 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7133 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007134 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007136 curwin->w_set_curswant = TRUE;
7137 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007138 }
7139 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7140 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007141 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142 int capcol = -1;
7143
7144 if (str != NULL)
7145 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007146 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007147 while (*str != NUL)
7148 {
7149 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7150 if (attr != HLF_COUNT)
7151 {
7152 word = str;
7153 break;
7154 }
7155 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007156 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007157 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007158 }
7159 }
7160 }
7161#endif
7162
7163 list_append_string(rettv->vval.v_list, word, len);
7164 list_append_string(rettv->vval.v_list, (char_u *)(
7165 attr == HLF_SPB ? "bad" :
7166 attr == HLF_SPR ? "rare" :
7167 attr == HLF_SPL ? "local" :
7168 attr == HLF_SPC ? "caps" :
7169 ""), -1);
7170}
7171
7172/*
7173 * "spellsuggest()" function
7174 */
7175 static void
7176f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7177{
7178#ifdef FEAT_SPELL
7179 char_u *str;
7180 int typeerr = FALSE;
7181 int maxcount;
7182 garray_T ga;
7183 int i;
7184 listitem_T *li;
7185 int need_capital = FALSE;
7186#endif
7187
7188 if (rettv_list_alloc(rettv) == FAIL)
7189 return;
7190
7191#ifdef FEAT_SPELL
7192 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7193 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007194 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007195 if (argvars[1].v_type != VAR_UNKNOWN)
7196 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007197 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007198 if (maxcount <= 0)
7199 return;
7200 if (argvars[2].v_type != VAR_UNKNOWN)
7201 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007202 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007203 if (typeerr)
7204 return;
7205 }
7206 }
7207 else
7208 maxcount = 25;
7209
7210 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7211
7212 for (i = 0; i < ga.ga_len; ++i)
7213 {
7214 str = ((char_u **)ga.ga_data)[i];
7215
7216 li = listitem_alloc();
7217 if (li == NULL)
7218 vim_free(str);
7219 else
7220 {
7221 li->li_tv.v_type = VAR_STRING;
7222 li->li_tv.v_lock = 0;
7223 li->li_tv.vval.v_string = str;
7224 list_append(rettv->vval.v_list, li);
7225 }
7226 }
7227 ga_clear(&ga);
7228 }
7229#endif
7230}
7231
7232 static void
7233f_split(typval_T *argvars, typval_T *rettv)
7234{
7235 char_u *str;
7236 char_u *end;
7237 char_u *pat = NULL;
7238 regmatch_T regmatch;
7239 char_u patbuf[NUMBUFLEN];
7240 char_u *save_cpo;
7241 int match;
7242 colnr_T col = 0;
7243 int keepempty = FALSE;
7244 int typeerr = FALSE;
7245
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007246 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007247 save_cpo = p_cpo;
7248 p_cpo = (char_u *)"";
7249
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007250 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007251 if (argvars[1].v_type != VAR_UNKNOWN)
7252 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007253 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254 if (pat == NULL)
7255 typeerr = TRUE;
7256 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007257 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007258 }
7259 if (pat == NULL || *pat == NUL)
7260 pat = (char_u *)"[\\x01- ]\\+";
7261
7262 if (rettv_list_alloc(rettv) == FAIL)
7263 return;
7264 if (typeerr)
7265 return;
7266
7267 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7268 if (regmatch.regprog != NULL)
7269 {
7270 regmatch.rm_ic = FALSE;
7271 while (*str != NUL || keepempty)
7272 {
7273 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007274 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007275 else
7276 match = vim_regexec_nl(&regmatch, str, col);
7277 if (match)
7278 end = regmatch.startp[0];
7279 else
7280 end = str + STRLEN(str);
7281 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7282 && *str != NUL && match && end < regmatch.endp[0]))
7283 {
7284 if (list_append_string(rettv->vval.v_list, str,
7285 (int)(end - str)) == FAIL)
7286 break;
7287 }
7288 if (!match)
7289 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007290 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007291 if (regmatch.endp[0] > str)
7292 col = 0;
7293 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007294 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007295 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007296 str = regmatch.endp[0];
7297 }
7298
7299 vim_regfree(regmatch.regprog);
7300 }
7301
7302 p_cpo = save_cpo;
7303}
7304
7305#ifdef FEAT_FLOAT
7306/*
7307 * "sqrt()" function
7308 */
7309 static void
7310f_sqrt(typval_T *argvars, typval_T *rettv)
7311{
7312 float_T f = 0.0;
7313
7314 rettv->v_type = VAR_FLOAT;
7315 if (get_float_arg(argvars, &f) == OK)
7316 rettv->vval.v_float = sqrt(f);
7317 else
7318 rettv->vval.v_float = 0.0;
7319}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007320#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007321
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007322#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007323/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007324 * "str2float()" function
7325 */
7326 static void
7327f_str2float(typval_T *argvars, typval_T *rettv)
7328{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007329 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007330 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007331
Bram Moolenaar08243d22017-01-10 16:12:29 +01007332 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007333 p = skipwhite(p + 1);
7334 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007335 if (isneg)
7336 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007337 rettv->v_type = VAR_FLOAT;
7338}
7339#endif
7340
7341/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007342 * "str2list()" function
7343 */
7344 static void
7345f_str2list(typval_T *argvars, typval_T *rettv)
7346{
7347 char_u *p;
7348 int utf8 = FALSE;
7349
7350 if (rettv_list_alloc(rettv) == FAIL)
7351 return;
7352
7353 if (argvars[1].v_type != VAR_UNKNOWN)
7354 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7355
7356 p = tv_get_string(&argvars[0]);
7357
7358 if (has_mbyte || utf8)
7359 {
7360 int (*ptr2len)(char_u *);
7361 int (*ptr2char)(char_u *);
7362
7363 if (utf8 || enc_utf8)
7364 {
7365 ptr2len = utf_ptr2len;
7366 ptr2char = utf_ptr2char;
7367 }
7368 else
7369 {
7370 ptr2len = mb_ptr2len;
7371 ptr2char = mb_ptr2char;
7372 }
7373
7374 for ( ; *p != NUL; p += (*ptr2len)(p))
7375 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7376 }
7377 else
7378 for ( ; *p != NUL; ++p)
7379 list_append_number(rettv->vval.v_list, *p);
7380}
7381
7382/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383 * "str2nr()" function
7384 */
7385 static void
7386f_str2nr(typval_T *argvars, typval_T *rettv)
7387{
7388 int base = 10;
7389 char_u *p;
7390 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007391 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007392 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007393
7394 if (argvars[1].v_type != VAR_UNKNOWN)
7395 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007396 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007397 if (base != 2 && base != 8 && base != 10 && base != 16)
7398 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007399 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007400 return;
7401 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007402 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7403 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007404 }
7405
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007406 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007407 isneg = (*p == '-');
7408 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007409 p = skipwhite(p + 1);
7410 switch (base)
7411 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007412 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7413 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7414 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007415 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007416 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7417 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007418 if (isneg)
7419 rettv->vval.v_number = -n;
7420 else
7421 rettv->vval.v_number = n;
7422
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423}
7424
7425#ifdef HAVE_STRFTIME
7426/*
7427 * "strftime({format}[, {time}])" function
7428 */
7429 static void
7430f_strftime(typval_T *argvars, typval_T *rettv)
7431{
7432 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007433 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434 struct tm *curtime;
7435 time_t seconds;
7436 char_u *p;
7437
7438 rettv->v_type = VAR_STRING;
7439
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007440 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441 if (argvars[1].v_type == VAR_UNKNOWN)
7442 seconds = time(NULL);
7443 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007444 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007445 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007446 // MSVC returns NULL for an invalid value of seconds.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007447 if (curtime == NULL)
7448 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7449 else
7450 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007451 vimconv_T conv;
7452 char_u *enc;
7453
7454 conv.vc_type = CONV_NONE;
7455 enc = enc_locale();
7456 convert_setup(&conv, p_enc, enc);
7457 if (conv.vc_type != CONV_NONE)
7458 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007459 if (p != NULL)
7460 (void)strftime((char *)result_buf, sizeof(result_buf),
7461 (char *)p, curtime);
7462 else
7463 result_buf[0] = NUL;
7464
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007465 if (conv.vc_type != CONV_NONE)
7466 vim_free(p);
7467 convert_setup(&conv, enc, p_enc);
7468 if (conv.vc_type != CONV_NONE)
7469 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7470 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471 rettv->vval.v_string = vim_strsave(result_buf);
7472
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007473 // Release conversion descriptors
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007474 convert_setup(&conv, NULL, NULL);
7475 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007476 }
7477}
7478#endif
7479
7480/*
7481 * "strgetchar()" function
7482 */
7483 static void
7484f_strgetchar(typval_T *argvars, typval_T *rettv)
7485{
7486 char_u *str;
7487 int len;
7488 int error = FALSE;
7489 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007490 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007491
7492 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007493 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007494 if (str == NULL)
7495 return;
7496 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007497 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007498 if (error)
7499 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007500
Bram Moolenaar13505972019-01-24 15:04:48 +01007501 while (charidx >= 0 && byteidx < len)
7502 {
7503 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007505 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7506 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007507 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007508 --charidx;
7509 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007510 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007511}
7512
7513/*
7514 * "stridx()" function
7515 */
7516 static void
7517f_stridx(typval_T *argvars, typval_T *rettv)
7518{
7519 char_u buf[NUMBUFLEN];
7520 char_u *needle;
7521 char_u *haystack;
7522 char_u *save_haystack;
7523 char_u *pos;
7524 int start_idx;
7525
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007526 needle = tv_get_string_chk(&argvars[1]);
7527 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007528 rettv->vval.v_number = -1;
7529 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007530 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007531
7532 if (argvars[2].v_type != VAR_UNKNOWN)
7533 {
7534 int error = FALSE;
7535
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007536 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537 if (error || start_idx >= (int)STRLEN(haystack))
7538 return;
7539 if (start_idx >= 0)
7540 haystack += start_idx;
7541 }
7542
7543 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7544 if (pos != NULL)
7545 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7546}
7547
7548/*
7549 * "string()" function
7550 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007551 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007552f_string(typval_T *argvars, typval_T *rettv)
7553{
7554 char_u *tofree;
7555 char_u numbuf[NUMBUFLEN];
7556
7557 rettv->v_type = VAR_STRING;
7558 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7559 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007560 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007561 if (rettv->vval.v_string != NULL && tofree == NULL)
7562 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7563}
7564
7565/*
7566 * "strlen()" function
7567 */
7568 static void
7569f_strlen(typval_T *argvars, typval_T *rettv)
7570{
7571 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007572 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007573}
7574
7575/*
7576 * "strchars()" function
7577 */
7578 static void
7579f_strchars(typval_T *argvars, typval_T *rettv)
7580{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007581 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007582 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007583 varnumber_T len = 0;
7584 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007585
7586 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007587 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007589 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007590 else
7591 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007592 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7593 while (*s != NUL)
7594 {
7595 func_mb_ptr2char_adv(&s);
7596 ++len;
7597 }
7598 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007599 }
7600}
7601
7602/*
7603 * "strdisplaywidth()" function
7604 */
7605 static void
7606f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7607{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007608 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007609 int col = 0;
7610
7611 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007612 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007613
7614 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7615}
7616
7617/*
7618 * "strwidth()" function
7619 */
7620 static void
7621f_strwidth(typval_T *argvars, typval_T *rettv)
7622{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007623 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007624
Bram Moolenaar13505972019-01-24 15:04:48 +01007625 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626}
7627
7628/*
7629 * "strcharpart()" function
7630 */
7631 static void
7632f_strcharpart(typval_T *argvars, typval_T *rettv)
7633{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007634 char_u *p;
7635 int nchar;
7636 int nbyte = 0;
7637 int charlen;
7638 int len = 0;
7639 int slen;
7640 int error = FALSE;
7641
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007642 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007643 slen = (int)STRLEN(p);
7644
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007645 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007646 if (!error)
7647 {
7648 if (nchar > 0)
7649 while (nchar > 0 && nbyte < slen)
7650 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007651 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007652 --nchar;
7653 }
7654 else
7655 nbyte = nchar;
7656 if (argvars[2].v_type != VAR_UNKNOWN)
7657 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007658 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007659 while (charlen > 0 && nbyte + len < slen)
7660 {
7661 int off = nbyte + len;
7662
7663 if (off < 0)
7664 len += 1;
7665 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007666 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007667 --charlen;
7668 }
7669 }
7670 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007671 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672 }
7673
7674 /*
7675 * Only return the overlap between the specified part and the actual
7676 * string.
7677 */
7678 if (nbyte < 0)
7679 {
7680 len += nbyte;
7681 nbyte = 0;
7682 }
7683 else if (nbyte > slen)
7684 nbyte = slen;
7685 if (len < 0)
7686 len = 0;
7687 else if (nbyte + len > slen)
7688 len = slen - nbyte;
7689
7690 rettv->v_type = VAR_STRING;
7691 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007692}
7693
7694/*
7695 * "strpart()" function
7696 */
7697 static void
7698f_strpart(typval_T *argvars, typval_T *rettv)
7699{
7700 char_u *p;
7701 int n;
7702 int len;
7703 int slen;
7704 int error = FALSE;
7705
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007706 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007707 slen = (int)STRLEN(p);
7708
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007709 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007710 if (error)
7711 len = 0;
7712 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007713 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007714 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007715 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716
7717 /*
7718 * Only return the overlap between the specified part and the actual
7719 * string.
7720 */
7721 if (n < 0)
7722 {
7723 len += n;
7724 n = 0;
7725 }
7726 else if (n > slen)
7727 n = slen;
7728 if (len < 0)
7729 len = 0;
7730 else if (n + len > slen)
7731 len = slen - n;
7732
7733 rettv->v_type = VAR_STRING;
7734 rettv->vval.v_string = vim_strnsave(p + n, len);
7735}
7736
Bram Moolenaar10455d42019-11-21 15:36:18 +01007737#ifdef HAVE_STRPTIME
7738/*
7739 * "strptime({format}, {timestring})" function
7740 */
7741 static void
7742f_strptime(typval_T *argvars, typval_T *rettv)
7743{
7744 struct tm tmval;
7745 char_u *fmt;
7746 char_u *str;
7747 vimconv_T conv;
7748 char_u *enc;
7749
7750 vim_memset(&tmval, NUL, sizeof(tmval));
7751 fmt = tv_get_string(&argvars[0]);
7752 str = tv_get_string(&argvars[1]);
7753
7754 conv.vc_type = CONV_NONE;
7755 enc = enc_locale();
7756 convert_setup(&conv, p_enc, enc);
7757 if (conv.vc_type != CONV_NONE)
7758 fmt = string_convert(&conv, fmt, NULL);
7759 if (fmt == NULL
7760 || strptime((char *)str, (char *)fmt, &tmval) == NULL
7761 || (rettv->vval.v_number = mktime(&tmval)) == -1)
7762 rettv->vval.v_number = 0;
7763
7764 if (conv.vc_type != CONV_NONE)
7765 vim_free(fmt);
7766 convert_setup(&conv, NULL, NULL);
7767 vim_free(enc);
7768}
7769#endif
7770
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007771/*
7772 * "strridx()" function
7773 */
7774 static void
7775f_strridx(typval_T *argvars, typval_T *rettv)
7776{
7777 char_u buf[NUMBUFLEN];
7778 char_u *needle;
7779 char_u *haystack;
7780 char_u *rest;
7781 char_u *lastmatch = NULL;
7782 int haystack_len, end_idx;
7783
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007784 needle = tv_get_string_chk(&argvars[1]);
7785 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007786
7787 rettv->vval.v_number = -1;
7788 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007789 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007790
7791 haystack_len = (int)STRLEN(haystack);
7792 if (argvars[2].v_type != VAR_UNKNOWN)
7793 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007794 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007795 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007796 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007797 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798 }
7799 else
7800 end_idx = haystack_len;
7801
7802 if (*needle == NUL)
7803 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007804 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805 lastmatch = haystack + end_idx;
7806 }
7807 else
7808 {
7809 for (rest = haystack; *rest != '\0'; ++rest)
7810 {
7811 rest = (char_u *)strstr((char *)rest, (char *)needle);
7812 if (rest == NULL || rest > haystack + end_idx)
7813 break;
7814 lastmatch = rest;
7815 }
7816 }
7817
7818 if (lastmatch == NULL)
7819 rettv->vval.v_number = -1;
7820 else
7821 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7822}
7823
7824/*
7825 * "strtrans()" function
7826 */
7827 static void
7828f_strtrans(typval_T *argvars, typval_T *rettv)
7829{
7830 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007831 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832}
7833
7834/*
7835 * "submatch()" function
7836 */
7837 static void
7838f_submatch(typval_T *argvars, typval_T *rettv)
7839{
7840 int error = FALSE;
7841 int no;
7842 int retList = 0;
7843
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007844 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007845 if (error)
7846 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007847 if (no < 0 || no >= NSUBEXP)
7848 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007849 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007850 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007851 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007852 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007853 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854 if (error)
7855 return;
7856
7857 if (retList == 0)
7858 {
7859 rettv->v_type = VAR_STRING;
7860 rettv->vval.v_string = reg_submatch(no);
7861 }
7862 else
7863 {
7864 rettv->v_type = VAR_LIST;
7865 rettv->vval.v_list = reg_submatch_list(no);
7866 }
7867}
7868
7869/*
7870 * "substitute()" function
7871 */
7872 static void
7873f_substitute(typval_T *argvars, typval_T *rettv)
7874{
7875 char_u patbuf[NUMBUFLEN];
7876 char_u subbuf[NUMBUFLEN];
7877 char_u flagsbuf[NUMBUFLEN];
7878
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007879 char_u *str = tv_get_string_chk(&argvars[0]);
7880 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007881 char_u *sub = NULL;
7882 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007883 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007884
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007885 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7886 expr = &argvars[2];
7887 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007888 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007889
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007891 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7892 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 rettv->vval.v_string = NULL;
7894 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007895 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007896}
7897
7898/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007899 * "swapinfo(swap_filename)" function
7900 */
7901 static void
7902f_swapinfo(typval_T *argvars, typval_T *rettv)
7903{
7904 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007905 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007906}
7907
7908/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007909 * "swapname(expr)" function
7910 */
7911 static void
7912f_swapname(typval_T *argvars, typval_T *rettv)
7913{
7914 buf_T *buf;
7915
7916 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007917 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007918 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7919 || buf->b_ml.ml_mfp->mf_fname == NULL)
7920 rettv->vval.v_string = NULL;
7921 else
7922 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7923}
7924
7925/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007926 * "synID(lnum, col, trans)" function
7927 */
7928 static void
7929f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7930{
7931 int id = 0;
7932#ifdef FEAT_SYN_HL
7933 linenr_T lnum;
7934 colnr_T col;
7935 int trans;
7936 int transerr = FALSE;
7937
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007938 lnum = tv_get_lnum(argvars); // -1 on type error
7939 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007940 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007941
7942 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7943 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7944 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7945#endif
7946
7947 rettv->vval.v_number = id;
7948}
7949
7950/*
7951 * "synIDattr(id, what [, mode])" function
7952 */
7953 static void
7954f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7955{
7956 char_u *p = NULL;
7957#ifdef FEAT_SYN_HL
7958 int id;
7959 char_u *what;
7960 char_u *mode;
7961 char_u modebuf[NUMBUFLEN];
7962 int modec;
7963
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007964 id = (int)tv_get_number(&argvars[0]);
7965 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007966 if (argvars[2].v_type != VAR_UNKNOWN)
7967 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007968 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007969 modec = TOLOWER_ASC(mode[0]);
7970 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007971 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007972 }
7973 else
7974 {
7975#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7976 if (USE_24BIT)
7977 modec = 'g';
7978 else
7979#endif
7980 if (t_colors > 1)
7981 modec = 'c';
7982 else
7983 modec = 't';
7984 }
7985
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007986 switch (TOLOWER_ASC(what[0]))
7987 {
7988 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007989 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007990 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007991 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992 p = highlight_has_attr(id, HL_BOLD, modec);
7993 break;
7994
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007995 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007996 p = highlight_color(id, what, modec);
7997 break;
7998
7999 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008000 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008001 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008002 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003 p = highlight_has_attr(id, HL_ITALIC, modec);
8004 break;
8005
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008006 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02008007 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008 break;
8009
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008010 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008011 p = highlight_has_attr(id, HL_INVERSE, modec);
8012 break;
8013
8014 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008015 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008016 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008017 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02008018 else if (TOLOWER_ASC(what[1]) == 't' &&
8019 TOLOWER_ASC(what[2]) == 'r')
8020 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008021 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008022 p = highlight_has_attr(id, HL_STANDOUT, modec);
8023 break;
8024
8025 case 'u':
8026 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008027 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008028 p = highlight_has_attr(id, HL_UNDERLINE, modec);
8029 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008030 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008031 p = highlight_has_attr(id, HL_UNDERCURL, modec);
8032 break;
8033 }
8034
8035 if (p != NULL)
8036 p = vim_strsave(p);
8037#endif
8038 rettv->v_type = VAR_STRING;
8039 rettv->vval.v_string = p;
8040}
8041
8042/*
8043 * "synIDtrans(id)" function
8044 */
8045 static void
8046f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8047{
8048 int id;
8049
8050#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008051 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008052
8053 if (id > 0)
8054 id = syn_get_final_id(id);
8055 else
8056#endif
8057 id = 0;
8058
8059 rettv->vval.v_number = id;
8060}
8061
8062/*
8063 * "synconcealed(lnum, col)" function
8064 */
8065 static void
8066f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8067{
8068#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8069 linenr_T lnum;
8070 colnr_T col;
8071 int syntax_flags = 0;
8072 int cchar;
8073 int matchid = 0;
8074 char_u str[NUMBUFLEN];
8075#endif
8076
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008077 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008078
8079#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008080 lnum = tv_get_lnum(argvars); // -1 on type error
8081 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082
8083 vim_memset(str, NUL, sizeof(str));
8084
8085 if (rettv_list_alloc(rettv) != FAIL)
8086 {
8087 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8088 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8089 && curwin->w_p_cole > 0)
8090 {
8091 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8092 syntax_flags = get_syntax_info(&matchid);
8093
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008094 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8096 {
8097 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008098 if (cchar == NUL && curwin->w_p_cole == 1)
8099 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008100 if (cchar != NUL)
8101 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008102 if (has_mbyte)
8103 (*mb_char2bytes)(cchar, str);
8104 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008105 str[0] = cchar;
8106 }
8107 }
8108 }
8109
8110 list_append_number(rettv->vval.v_list,
8111 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008112 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008113 list_append_string(rettv->vval.v_list, str, -1);
8114 list_append_number(rettv->vval.v_list, matchid);
8115 }
8116#endif
8117}
8118
8119/*
8120 * "synstack(lnum, col)" function
8121 */
8122 static void
8123f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8124{
8125#ifdef FEAT_SYN_HL
8126 linenr_T lnum;
8127 colnr_T col;
8128 int i;
8129 int id;
8130#endif
8131
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008132 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133
8134#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008135 lnum = tv_get_lnum(argvars); // -1 on type error
8136 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008137
8138 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8139 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8140 && rettv_list_alloc(rettv) != FAIL)
8141 {
8142 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8143 for (i = 0; ; ++i)
8144 {
8145 id = syn_get_stack_item(i);
8146 if (id < 0)
8147 break;
8148 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8149 break;
8150 }
8151 }
8152#endif
8153}
8154
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008155/*
8156 * "tabpagebuflist()" function
8157 */
8158 static void
8159f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8160{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008161 tabpage_T *tp;
8162 win_T *wp = NULL;
8163
8164 if (argvars[0].v_type == VAR_UNKNOWN)
8165 wp = firstwin;
8166 else
8167 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008168 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008169 if (tp != NULL)
8170 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8171 }
8172 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8173 {
8174 for (; wp != NULL; wp = wp->w_next)
8175 if (list_append_number(rettv->vval.v_list,
8176 wp->w_buffer->b_fnum) == FAIL)
8177 break;
8178 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179}
8180
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008181/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 * "tagfiles()" function
8183 */
8184 static void
8185f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8186{
8187 char_u *fname;
8188 tagname_T tn;
8189 int first;
8190
8191 if (rettv_list_alloc(rettv) == FAIL)
8192 return;
8193 fname = alloc(MAXPATHL);
8194 if (fname == NULL)
8195 return;
8196
8197 for (first = TRUE; ; first = FALSE)
8198 if (get_tagfname(&tn, first, fname) == FAIL
8199 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8200 break;
8201 tagname_free(&tn);
8202 vim_free(fname);
8203}
8204
8205/*
8206 * "taglist()" function
8207 */
8208 static void
8209f_taglist(typval_T *argvars, typval_T *rettv)
8210{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008211 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008212 char_u *tag_pattern;
8213
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008214 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008215
8216 rettv->vval.v_number = FALSE;
8217 if (*tag_pattern == NUL)
8218 return;
8219
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008220 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008221 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008222 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008223 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008224}
8225
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226#ifdef FEAT_FLOAT
8227/*
8228 * "tan()" function
8229 */
8230 static void
8231f_tan(typval_T *argvars, typval_T *rettv)
8232{
8233 float_T f = 0.0;
8234
8235 rettv->v_type = VAR_FLOAT;
8236 if (get_float_arg(argvars, &f) == OK)
8237 rettv->vval.v_float = tan(f);
8238 else
8239 rettv->vval.v_float = 0.0;
8240}
8241
8242/*
8243 * "tanh()" function
8244 */
8245 static void
8246f_tanh(typval_T *argvars, typval_T *rettv)
8247{
8248 float_T f = 0.0;
8249
8250 rettv->v_type = VAR_FLOAT;
8251 if (get_float_arg(argvars, &f) == OK)
8252 rettv->vval.v_float = tanh(f);
8253 else
8254 rettv->vval.v_float = 0.0;
8255}
8256#endif
8257
8258/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008259 * "tolower(string)" function
8260 */
8261 static void
8262f_tolower(typval_T *argvars, typval_T *rettv)
8263{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008264 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008265 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008266}
8267
8268/*
8269 * "toupper(string)" function
8270 */
8271 static void
8272f_toupper(typval_T *argvars, typval_T *rettv)
8273{
8274 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008275 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008276}
8277
8278/*
8279 * "tr(string, fromstr, tostr)" function
8280 */
8281 static void
8282f_tr(typval_T *argvars, typval_T *rettv)
8283{
8284 char_u *in_str;
8285 char_u *fromstr;
8286 char_u *tostr;
8287 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008288 int inlen;
8289 int fromlen;
8290 int tolen;
8291 int idx;
8292 char_u *cpstr;
8293 int cplen;
8294 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008295 char_u buf[NUMBUFLEN];
8296 char_u buf2[NUMBUFLEN];
8297 garray_T ga;
8298
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008299 in_str = tv_get_string(&argvars[0]);
8300 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8301 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008302
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008303 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008304 rettv->v_type = VAR_STRING;
8305 rettv->vval.v_string = NULL;
8306 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008307 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308 ga_init2(&ga, (int)sizeof(char), 80);
8309
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008310 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008311 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008312 if (STRLEN(fromstr) != STRLEN(tostr))
8313 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008314error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008315 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316 ga_clear(&ga);
8317 return;
8318 }
8319
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008320 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008321 while (*in_str != NUL)
8322 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008323 if (has_mbyte)
8324 {
8325 inlen = (*mb_ptr2len)(in_str);
8326 cpstr = in_str;
8327 cplen = inlen;
8328 idx = 0;
8329 for (p = fromstr; *p != NUL; p += fromlen)
8330 {
8331 fromlen = (*mb_ptr2len)(p);
8332 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8333 {
8334 for (p = tostr; *p != NUL; p += tolen)
8335 {
8336 tolen = (*mb_ptr2len)(p);
8337 if (idx-- == 0)
8338 {
8339 cplen = tolen;
8340 cpstr = p;
8341 break;
8342 }
8343 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008344 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008345 goto error;
8346 break;
8347 }
8348 ++idx;
8349 }
8350
8351 if (first && cpstr == in_str)
8352 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008353 // Check that fromstr and tostr have the same number of
8354 // (multi-byte) characters. Done only once when a character
8355 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008356 first = FALSE;
8357 for (p = tostr; *p != NUL; p += tolen)
8358 {
8359 tolen = (*mb_ptr2len)(p);
8360 --idx;
8361 }
8362 if (idx != 0)
8363 goto error;
8364 }
8365
8366 (void)ga_grow(&ga, cplen);
8367 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8368 ga.ga_len += cplen;
8369
8370 in_str += inlen;
8371 }
8372 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008373 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008374 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008375 p = vim_strchr(fromstr, *in_str);
8376 if (p != NULL)
8377 ga_append(&ga, tostr[p - fromstr]);
8378 else
8379 ga_append(&ga, *in_str);
8380 ++in_str;
8381 }
8382 }
8383
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008384 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008385 (void)ga_grow(&ga, 1);
8386 ga_append(&ga, NUL);
8387
8388 rettv->vval.v_string = ga.ga_data;
8389}
8390
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008391/*
8392 * "trim({expr})" function
8393 */
8394 static void
8395f_trim(typval_T *argvars, typval_T *rettv)
8396{
8397 char_u buf1[NUMBUFLEN];
8398 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008399 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008400 char_u *mask = NULL;
8401 char_u *tail;
8402 char_u *prev;
8403 char_u *p;
8404 int c1;
8405
8406 rettv->v_type = VAR_STRING;
8407 if (head == NULL)
8408 {
8409 rettv->vval.v_string = NULL;
8410 return;
8411 }
8412
8413 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008414 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008415
8416 while (*head != NUL)
8417 {
8418 c1 = PTR2CHAR(head);
8419 if (mask == NULL)
8420 {
8421 if (c1 > ' ' && c1 != 0xa0)
8422 break;
8423 }
8424 else
8425 {
8426 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8427 if (c1 == PTR2CHAR(p))
8428 break;
8429 if (*p == NUL)
8430 break;
8431 }
8432 MB_PTR_ADV(head);
8433 }
8434
8435 for (tail = head + STRLEN(head); tail > head; tail = prev)
8436 {
8437 prev = tail;
8438 MB_PTR_BACK(head, prev);
8439 c1 = PTR2CHAR(prev);
8440 if (mask == NULL)
8441 {
8442 if (c1 > ' ' && c1 != 0xa0)
8443 break;
8444 }
8445 else
8446 {
8447 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8448 if (c1 == PTR2CHAR(p))
8449 break;
8450 if (*p == NUL)
8451 break;
8452 }
8453 }
8454 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8455}
8456
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008457#ifdef FEAT_FLOAT
8458/*
8459 * "trunc({float})" function
8460 */
8461 static void
8462f_trunc(typval_T *argvars, typval_T *rettv)
8463{
8464 float_T f = 0.0;
8465
8466 rettv->v_type = VAR_FLOAT;
8467 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008468 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008469 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8470 else
8471 rettv->vval.v_float = 0.0;
8472}
8473#endif
8474
8475/*
8476 * "type(expr)" function
8477 */
8478 static void
8479f_type(typval_T *argvars, typval_T *rettv)
8480{
8481 int n = -1;
8482
8483 switch (argvars[0].v_type)
8484 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008485 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8486 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008487 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008488 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8489 case VAR_LIST: n = VAR_TYPE_LIST; break;
8490 case VAR_DICT: n = VAR_TYPE_DICT; break;
8491 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8492 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8493 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008494 case VAR_JOB: n = VAR_TYPE_JOB; break;
8495 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008496 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008497 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008498 case VAR_VOID:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008499 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008500 n = -1;
8501 break;
8502 }
8503 rettv->vval.v_number = n;
8504}
8505
8506/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008507 * "virtcol(string)" function
8508 */
8509 static void
8510f_virtcol(typval_T *argvars, typval_T *rettv)
8511{
8512 colnr_T vcol = 0;
8513 pos_T *fp;
8514 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008515 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008516
8517 fp = var2fpos(&argvars[0], FALSE, &fnum);
8518 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8519 && fnum == curbuf->b_fnum)
8520 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008521 // Limit the column to a valid value, getvvcol() doesn't check.
8522 if (fp->col < 0)
8523 fp->col = 0;
8524 else
8525 {
8526 len = (int)STRLEN(ml_get(fp->lnum));
8527 if (fp->col > len)
8528 fp->col = len;
8529 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530 getvvcol(curwin, fp, NULL, NULL, &vcol);
8531 ++vcol;
8532 }
8533
8534 rettv->vval.v_number = vcol;
8535}
8536
8537/*
8538 * "visualmode()" function
8539 */
8540 static void
8541f_visualmode(typval_T *argvars, typval_T *rettv)
8542{
8543 char_u str[2];
8544
8545 rettv->v_type = VAR_STRING;
8546 str[0] = curbuf->b_visual_mode_eval;
8547 str[1] = NUL;
8548 rettv->vval.v_string = vim_strsave(str);
8549
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008550 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008551 if (non_zero_arg(&argvars[0]))
8552 curbuf->b_visual_mode_eval = NUL;
8553}
8554
8555/*
8556 * "wildmenumode()" function
8557 */
8558 static void
8559f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8560{
8561#ifdef FEAT_WILDMENU
8562 if (wild_menu_showing)
8563 rettv->vval.v_number = 1;
8564#endif
8565}
8566
8567/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008568 * "windowsversion()" function
8569 */
8570 static void
8571f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8572{
8573 rettv->v_type = VAR_STRING;
8574 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8575}
8576
8577/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008578 * "wordcount()" function
8579 */
8580 static void
8581f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8582{
8583 if (rettv_dict_alloc(rettv) == FAIL)
8584 return;
8585 cursor_pos_info(rettv->vval.v_dict);
8586}
8587
8588/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008589 * "xor(expr, expr)" function
8590 */
8591 static void
8592f_xor(typval_T *argvars, typval_T *rettv)
8593{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008594 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8595 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008596}
8597
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008598#endif // FEAT_EVAL