blob: 6b00b4e6561189b712c19e452ff69120ca40f5d4 [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_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
105static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200106static void f_hlID(typval_T *argvars, typval_T *rettv);
107static void f_hlexists(typval_T *argvars, typval_T *rettv);
108static void f_hostname(typval_T *argvars, typval_T *rettv);
109static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200110static void f_index(typval_T *argvars, typval_T *rettv);
111static void f_input(typval_T *argvars, typval_T *rettv);
112static void f_inputdialog(typval_T *argvars, typval_T *rettv);
113static void f_inputlist(typval_T *argvars, typval_T *rettv);
114static void f_inputrestore(typval_T *argvars, typval_T *rettv);
115static void f_inputsave(typval_T *argvars, typval_T *rettv);
116static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100117static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_islocked(typval_T *argvars, typval_T *rettv);
120#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200121static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200122static void f_isnan(typval_T *argvars, typval_T *rettv);
123#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200124static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
125static void f_len(typval_T *argvars, typval_T *rettv);
126static void f_libcall(typval_T *argvars, typval_T *rettv);
127static void f_libcallnr(typval_T *argvars, typval_T *rettv);
128static void f_line(typval_T *argvars, typval_T *rettv);
129static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200130static void f_localtime(typval_T *argvars, typval_T *rettv);
131#ifdef FEAT_FLOAT
132static void f_log(typval_T *argvars, typval_T *rettv);
133static void f_log10(typval_T *argvars, typval_T *rettv);
134#endif
135#ifdef FEAT_LUA
136static void f_luaeval(typval_T *argvars, typval_T *rettv);
137#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200138static void f_maparg(typval_T *argvars, typval_T *rettv);
139static void f_mapcheck(typval_T *argvars, typval_T *rettv);
140static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141static void f_matchend(typval_T *argvars, typval_T *rettv);
142static void f_matchlist(typval_T *argvars, typval_T *rettv);
143static void f_matchstr(typval_T *argvars, typval_T *rettv);
144static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
145static void f_max(typval_T *argvars, typval_T *rettv);
146static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200147#ifdef FEAT_MZSCHEME
148static void f_mzeval(typval_T *argvars, typval_T *rettv);
149#endif
150static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
151static void f_nr2char(typval_T *argvars, typval_T *rettv);
152static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200153#ifdef FEAT_PERL
154static void f_perleval(typval_T *argvars, typval_T *rettv);
155#endif
156#ifdef FEAT_FLOAT
157static void f_pow(typval_T *argvars, typval_T *rettv);
158#endif
159static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
160static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200161static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200162static void f_pumvisible(typval_T *argvars, typval_T *rettv);
163#ifdef FEAT_PYTHON3
164static void f_py3eval(typval_T *argvars, typval_T *rettv);
165#endif
166#ifdef FEAT_PYTHON
167static void f_pyeval(typval_T *argvars, typval_T *rettv);
168#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100169#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
170static void f_pyxeval(typval_T *argvars, typval_T *rettv);
171#endif
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 Moolenaar06b0b4b2019-11-25 15:40:55 +0100229static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200230static void f_str2float(typval_T *argvars, typval_T *rettv);
231#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200232static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200233static void f_str2nr(typval_T *argvars, typval_T *rettv);
234static void f_strchars(typval_T *argvars, typval_T *rettv);
235#ifdef HAVE_STRFTIME
236static void f_strftime(typval_T *argvars, typval_T *rettv);
237#endif
238static void f_strgetchar(typval_T *argvars, typval_T *rettv);
239static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_strlen(typval_T *argvars, typval_T *rettv);
241static void f_strcharpart(typval_T *argvars, typval_T *rettv);
242static void f_strpart(typval_T *argvars, typval_T *rettv);
Bram Moolenaar10455d42019-11-21 15:36:18 +0100243#ifdef HAVE_STRPTIME
244static void f_strptime(typval_T *argvars, typval_T *rettv);
245#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200246static void f_strridx(typval_T *argvars, typval_T *rettv);
247static void f_strtrans(typval_T *argvars, typval_T *rettv);
248static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
249static void f_strwidth(typval_T *argvars, typval_T *rettv);
250static void f_submatch(typval_T *argvars, typval_T *rettv);
251static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200252static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200253static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200254static void f_synID(typval_T *argvars, typval_T *rettv);
255static void f_synIDattr(typval_T *argvars, typval_T *rettv);
256static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
257static void f_synstack(typval_T *argvars, typval_T *rettv);
258static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200259static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_taglist(typval_T *argvars, typval_T *rettv);
261static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200262#ifdef FEAT_FLOAT
263static void f_tan(typval_T *argvars, typval_T *rettv);
264static void f_tanh(typval_T *argvars, typval_T *rettv);
265#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200266static void f_tolower(typval_T *argvars, typval_T *rettv);
267static void f_toupper(typval_T *argvars, typval_T *rettv);
268static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100269static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200270#ifdef FEAT_FLOAT
271static void f_trunc(typval_T *argvars, typval_T *rettv);
272#endif
273static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200274static void f_virtcol(typval_T *argvars, typval_T *rettv);
275static void f_visualmode(typval_T *argvars, typval_T *rettv);
276static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200277static void f_wordcount(typval_T *argvars, typval_T *rettv);
278static void f_xor(typval_T *argvars, typval_T *rettv);
279
280/*
281 * Array with names and number of arguments of all internal functions
282 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
283 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200284typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200285{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200286 char *f_name; // function name
287 char f_min_argc; // minimal number of arguments
288 char f_max_argc; // maximal number of arguments
289 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200290 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200291 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200292} funcentry_T;
293
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200294// values for f_argtype; zero means it cannot be used as a method
295#define FEARG_1 1 // base is the first argument
296#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200297#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200298#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200299#define FEARG_LAST 9 // base is the last argument
300
Bram Moolenaarac92e252019-08-03 21:58:38 +0200301static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302{
303#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200304 {"abs", 1, 1, FEARG_1, f_abs},
305 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200306#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200307 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200308 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200309 {"append", 2, 2, FEARG_LAST, f_append},
310 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
311 {"argc", 0, 1, 0, f_argc},
312 {"argidx", 0, 0, 0, f_argidx},
313 {"arglistid", 0, 2, 0, f_arglistid},
314 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200315#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200316 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200317#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200318 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200319 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200320 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200321 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200322 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
323 {"assert_false", 1, 2, FEARG_1, f_assert_false},
324 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
325 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200326 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200327 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200328 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200329 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200330#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200331 {"atan", 1, 1, FEARG_1, f_atan},
332 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200333#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100334#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200335 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200336 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100337# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200338 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100339# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100340#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200341 {"browse", 4, 4, 0, f_browse},
342 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200343 {"bufadd", 1, 1, FEARG_1, f_bufadd},
344 {"bufexists", 1, 1, FEARG_1, f_bufexists},
345 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200346 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
347 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200348 {"buflisted", 1, 1, FEARG_1, f_buflisted},
349 {"bufload", 1, 1, FEARG_1, f_bufload},
350 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200351 {"bufname", 0, 1, FEARG_1, f_bufname},
352 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200353 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
354 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200355 {"byte2line", 1, 1, FEARG_1, f_byte2line},
356 {"byteidx", 2, 2, FEARG_1, f_byteidx},
357 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
358 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200360 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200361#endif
362#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200363 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
364 {"ch_close", 1, 1, FEARG_1, f_ch_close},
365 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
366 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
367 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
368 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
369 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
370 {"ch_info", 1, 1, FEARG_1, f_ch_info},
371 {"ch_log", 1, 2, FEARG_1, f_ch_log},
372 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
373 {"ch_open", 1, 2, FEARG_1, f_ch_open},
374 {"ch_read", 1, 2, FEARG_1, f_ch_read},
375 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
376 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
377 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
378 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
379 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
380 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200382 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200383 {"char2nr", 1, 2, FEARG_1, f_char2nr},
384 {"chdir", 1, 1, FEARG_1, f_chdir},
385 {"cindent", 1, 1, FEARG_1, f_cindent},
386 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
387 {"col", 1, 1, FEARG_1, f_col},
388 {"complete", 2, 2, FEARG_2, f_complete},
389 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200390 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200391 {"complete_info", 0, 1, FEARG_1, f_complete_info},
392 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200393 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200394#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200395 {"cos", 1, 1, FEARG_1, f_cos},
396 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200397#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200398 {"count", 2, 4, FEARG_1, f_count},
399 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200400 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100401#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200402 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200403#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200404 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
405 {"delete", 1, 2, FEARG_1, f_delete},
406 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200407 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200408 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
409 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200410 {"empty", 1, 1, FEARG_1, f_empty},
411 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200412 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200413 {"eval", 1, 1, FEARG_1, f_eval},
414 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200415 {"executable", 1, 1, FEARG_1, f_executable},
416 {"execute", 1, 2, FEARG_1, f_execute},
417 {"exepath", 1, 1, FEARG_1, f_exepath},
418 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200419#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200420 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200422 {"expand", 1, 3, FEARG_1, f_expand},
423 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200424 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200425 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
426 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
427 {"filereadable", 1, 1, FEARG_1, f_filereadable},
428 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200429 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200430 {"finddir", 1, 3, FEARG_1, f_finddir},
431 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200432#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200433 {"float2nr", 1, 1, FEARG_1, f_float2nr},
434 {"floor", 1, 1, FEARG_1, f_floor},
435 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200437 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
438 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
439 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
440 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
441 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200442 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200443 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200444 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200445 {"funcref", 1, 3, FEARG_1, f_funcref},
446 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200447 {"garbagecollect", 0, 1, 0, f_garbagecollect},
448 {"get", 2, 3, FEARG_1, f_get},
449 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200450 {"getbufline", 2, 3, FEARG_1, f_getbufline},
451 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
452 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200453 {"getchar", 0, 1, 0, f_getchar},
454 {"getcharmod", 0, 0, 0, f_getcharmod},
455 {"getcharsearch", 0, 0, 0, f_getcharsearch},
456 {"getcmdline", 0, 0, 0, f_getcmdline},
457 {"getcmdpos", 0, 0, 0, f_getcmdpos},
458 {"getcmdtype", 0, 0, 0, f_getcmdtype},
459 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200460 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200461 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200462 {"getcwd", 0, 2, FEARG_1, f_getcwd},
463 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200464 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200465 {"getfperm", 1, 1, FEARG_1, f_getfperm},
466 {"getfsize", 1, 1, FEARG_1, f_getfsize},
467 {"getftime", 1, 1, FEARG_1, f_getftime},
468 {"getftype", 1, 1, FEARG_1, f_getftype},
Bram Moolenaara3a12462019-09-07 15:08:38 +0200469 {"getimstatus", 0, 0, 0, f_getimstatus},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200470 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
471 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200472 {"getloclist", 1, 2, 0, f_getloclist},
473 {"getmatches", 0, 1, 0, f_getmatches},
Bram Moolenaardb3a2052019-11-16 18:22:41 +0100474 {"getmousepos", 0, 0, 0, f_getmousepos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200475 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200476 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200477 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200478 {"getreg", 0, 3, FEARG_1, f_getreg},
479 {"getregtype", 0, 1, FEARG_1, f_getregtype},
480 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
481 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
482 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200483 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
484 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
485 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200486 {"getwinposx", 0, 0, 0, f_getwinposx},
487 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200488 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
489 {"glob", 1, 4, FEARG_1, f_glob},
490 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
491 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200492 {"has", 1, 1, 0, f_has},
493 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200494 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
495 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
496 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
497 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
498 {"histadd", 2, 2, FEARG_2, f_histadd},
499 {"histdel", 1, 2, FEARG_1, f_histdel},
500 {"histget", 1, 2, FEARG_1, f_histget},
501 {"histnr", 1, 1, FEARG_1, f_histnr},
502 {"hlID", 1, 1, FEARG_1, f_hlID},
503 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200505 {"iconv", 3, 3, FEARG_1, f_iconv},
506 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200507 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200508 {"input", 1, 3, FEARG_1, f_input},
509 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
510 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200511 {"inputrestore", 0, 0, 0, f_inputrestore},
512 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200513 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200514 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100515 {"interrupt", 0, 0, 0, f_interrupt},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200516 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200517 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200518#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200519 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200520#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200521 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200522#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200523 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200524#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200525 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200527 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
528 {"job_info", 0, 1, FEARG_1, f_job_info},
529 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
530 {"job_start", 1, 2, FEARG_1, f_job_start},
531 {"job_status", 1, 1, FEARG_1, f_job_status},
532 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200534 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200535 {"js_decode", 1, 1, FEARG_1, f_js_decode},
536 {"js_encode", 1, 1, FEARG_1, f_js_encode},
537 {"json_decode", 1, 1, FEARG_1, f_json_decode},
538 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200539 {"keys", 1, 1, FEARG_1, f_keys},
540 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
541 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200542 {"libcall", 3, 3, FEARG_3, f_libcall},
543 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200544 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200545 {"line2byte", 1, 1, FEARG_1, f_line2byte},
546 {"lispindent", 1, 1, FEARG_1, f_lispindent},
547 {"list2str", 1, 2, FEARG_1, f_list2str},
548 {"listener_add", 1, 2, FEARG_2, f_listener_add},
549 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
550 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200551 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200552#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200553 {"log", 1, 1, FEARG_1, f_log},
554 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200555#endif
556#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200557 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200558#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200559 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200560 {"maparg", 1, 4, FEARG_1, f_maparg},
561 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
562 {"match", 2, 4, FEARG_1, f_match},
563 {"matchadd", 2, 5, FEARG_1, f_matchadd},
564 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
565 {"matcharg", 1, 1, FEARG_1, f_matcharg},
566 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
567 {"matchend", 2, 4, FEARG_1, f_matchend},
568 {"matchlist", 2, 4, FEARG_1, f_matchlist},
569 {"matchstr", 2, 4, FEARG_1, f_matchstr},
570 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200571 {"max", 1, 1, FEARG_1, f_max},
572 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200573 {"mkdir", 1, 3, FEARG_1, f_mkdir},
574 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200575#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200576 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200577#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200578 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
579 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200580 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200581 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200582#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200583 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200584#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200585#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200586 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
587 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200588 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200589 {"popup_close", 1, 2, FEARG_1, f_popup_close},
590 {"popup_create", 2, 2, FEARG_1, f_popup_create},
591 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200592 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
593 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200594 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
595 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200596 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
597 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
598 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200599 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200600 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
601 {"popup_move", 2, 2, FEARG_1, f_popup_move},
602 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
603 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
604 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
605 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200606#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200607#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200608 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200609#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200610 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200611 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200612#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200613 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
614 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
615 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200616#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100617#ifdef FEAT_TEXT_PROP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200618 {"prop_add", 3, 3, FEARG_1, f_prop_add},
619 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
620 {"prop_list", 1, 2, FEARG_1, f_prop_list},
621 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
622 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
623 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
624 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
625 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
626 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100627#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200628 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200629 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200630#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200631 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632#endif
633#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200634 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100636#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200637 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100638#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100639 {"rand", 0, 1, FEARG_1, f_rand},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200640 {"range", 1, 3, FEARG_1, f_range},
641 {"readdir", 1, 2, FEARG_1, f_readdir},
642 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200643 {"reg_executing", 0, 0, 0, f_reg_executing},
644 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200645 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200646#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200647 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200648#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200649 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
650 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
651 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
652 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
653 {"remote_read", 1, 2, FEARG_1, f_remote_read},
654 {"remote_send", 2, 3, FEARG_1, f_remote_send},
655 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200656 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200657 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200658 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200659 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200660 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200661#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200662 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200663#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100664#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200665 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100666#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200667 {"screenattr", 2, 2, FEARG_1, f_screenattr},
668 {"screenchar", 2, 2, FEARG_1, f_screenchar},
669 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200670 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200671 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200672 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200673 {"screenstring", 2, 2, FEARG_1, f_screenstring},
674 {"search", 1, 4, FEARG_1, f_search},
675 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200676 {"searchpair", 3, 7, 0, f_searchpair},
677 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200678 {"searchpos", 1, 4, FEARG_1, f_searchpos},
679 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200680 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200681 {"setbufline", 3, 3, FEARG_3, f_setbufline},
682 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
683 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
684 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
685 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200686 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200687 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200688 {"setloclist", 2, 4, FEARG_2, f_setloclist},
689 {"setmatches", 1, 2, FEARG_1, f_setmatches},
690 {"setpos", 2, 2, FEARG_2, f_setpos},
691 {"setqflist", 1, 3, FEARG_1, f_setqflist},
692 {"setreg", 2, 3, FEARG_2, f_setreg},
693 {"settabvar", 3, 3, FEARG_3, f_settabvar},
694 {"settabwinvar", 4, 4, FEARG_4, f_settabwinvar},
695 {"settagstack", 2, 3, FEARG_2, f_settagstack},
696 {"setwinvar", 3, 3, FEARG_3, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200697#ifdef FEAT_CRYPT
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200698 {"sha256", 1, 1, FEARG_1, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200699#endif
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200700 {"shellescape", 1, 2, FEARG_1, f_shellescape},
701 {"shiftwidth", 0, 1, FEARG_1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100702#ifdef FEAT_SIGNS
Bram Moolenaar93476fd2019-09-06 22:00:54 +0200703 {"sign_define", 1, 2, FEARG_1, f_sign_define},
704 {"sign_getdefined", 0, 1, FEARG_1, f_sign_getdefined},
705 {"sign_getplaced", 0, 2, FEARG_1, f_sign_getplaced},
706 {"sign_jump", 3, 3, FEARG_1, f_sign_jump},
707 {"sign_place", 4, 5, FEARG_1, f_sign_place},
708 {"sign_placelist", 1, 1, FEARG_1, f_sign_placelist},
709 {"sign_undefine", 0, 1, FEARG_1, f_sign_undefine},
710 {"sign_unplace", 1, 2, FEARG_1, f_sign_unplace},
711 {"sign_unplacelist", 1, 2, FEARG_1, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100712#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200713 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200714#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200715 {"sin", 1, 1, FEARG_1, f_sin},
716 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200717#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200718 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200719#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200720 {"sound_clear", 0, 0, 0, f_sound_clear},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200721 {"sound_playevent", 1, 2, FEARG_1, f_sound_playevent},
722 {"sound_playfile", 1, 2, FEARG_1, f_sound_playfile},
723 {"sound_stop", 1, 1, FEARG_1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200724#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200725 {"soundfold", 1, 1, FEARG_1, f_soundfold},
726 {"spellbadword", 0, 1, FEARG_1, f_spellbadword},
727 {"spellsuggest", 1, 3, FEARG_1, f_spellsuggest},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200728 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200729#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200730 {"sqrt", 1, 1, FEARG_1, f_sqrt},
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100731 {"srand", 0, 1, FEARG_1, f_srand},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200732#endif
733 {"state", 0, 1, FEARG_1, f_state},
734#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200735 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200736#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200737 {"str2list", 1, 2, FEARG_1, f_str2list},
Bram Moolenaar60a8de22019-09-15 14:33:22 +0200738 {"str2nr", 1, 3, FEARG_1, f_str2nr},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200739 {"strcharpart", 2, 3, FEARG_1, f_strcharpart},
740 {"strchars", 1, 2, FEARG_1, f_strchars},
741 {"strdisplaywidth", 1, 2, FEARG_1, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200742#ifdef HAVE_STRFTIME
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200743 {"strftime", 1, 2, FEARG_1, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200745 {"strgetchar", 2, 2, FEARG_1, f_strgetchar},
746 {"stridx", 2, 3, FEARG_1, f_stridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200747 {"string", 1, 1, FEARG_1, f_string},
748 {"strlen", 1, 1, FEARG_1, f_strlen},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200749 {"strpart", 2, 3, FEARG_1, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100750#ifdef HAVE_STRPTIME
751 {"strptime", 2, 2, FEARG_1, f_strptime},
752#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200753 {"strridx", 2, 3, FEARG_1, f_strridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200754 {"strtrans", 1, 1, FEARG_1, f_strtrans},
755 {"strwidth", 1, 1, FEARG_1, f_strwidth},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200756 {"submatch", 1, 2, FEARG_1, f_submatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200757 {"substitute", 4, 4, FEARG_1, f_substitute},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200758 {"swapinfo", 1, 1, FEARG_1, f_swapinfo},
759 {"swapname", 1, 1, FEARG_1, f_swapname},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200760 {"synID", 3, 3, 0, f_synID},
761 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
762 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
763 {"synconcealed", 2, 2, 0, f_synconcealed},
764 {"synstack", 2, 2, 0, f_synstack},
765 {"system", 1, 2, FEARG_1, f_system},
766 {"systemlist", 1, 2, FEARG_1, f_systemlist},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200767 {"tabpagebuflist", 0, 1, FEARG_1, f_tabpagebuflist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200768 {"tabpagenr", 0, 1, 0, f_tabpagenr},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200769 {"tabpagewinnr", 1, 2, FEARG_1, f_tabpagewinnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200770 {"tagfiles", 0, 0, 0, f_tagfiles},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200771 {"taglist", 1, 2, FEARG_1, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200772#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200773 {"tan", 1, 1, FEARG_1, f_tan},
774 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200775#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200776 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200777#ifdef FEAT_TERMINAL
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200778 {"term_dumpdiff", 2, 3, FEARG_1, f_term_dumpdiff},
779 {"term_dumpload", 1, 2, FEARG_1, f_term_dumpload},
780 {"term_dumpwrite", 2, 3, FEARG_2, f_term_dumpwrite},
781 {"term_getaltscreen", 1, 1, FEARG_1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200782# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200783 {"term_getansicolors", 1, 1, FEARG_1, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200784# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200785 {"term_getattr", 2, 2, FEARG_1, f_term_getattr},
786 {"term_getcursor", 1, 1, FEARG_1, f_term_getcursor},
787 {"term_getjob", 1, 1, FEARG_1, f_term_getjob},
788 {"term_getline", 2, 2, FEARG_1, f_term_getline},
789 {"term_getscrolled", 1, 1, FEARG_1, f_term_getscrolled},
790 {"term_getsize", 1, 1, FEARG_1, f_term_getsize},
791 {"term_getstatus", 1, 1, FEARG_1, f_term_getstatus},
792 {"term_gettitle", 1, 1, FEARG_1, f_term_gettitle},
793 {"term_gettty", 1, 2, FEARG_1, f_term_gettty},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200794 {"term_list", 0, 0, 0, f_term_list},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200795 {"term_scrape", 2, 2, FEARG_1, f_term_scrape},
796 {"term_sendkeys", 2, 2, FEARG_1, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200797# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200798 {"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200799# endif
Bram Moolenaard2842ea2019-09-26 23:08:54 +0200800 {"term_setapi", 2, 2, FEARG_1, f_term_setapi},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200801 {"term_setkill", 2, 2, FEARG_1, f_term_setkill},
802 {"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
803 {"term_setsize", 3, 3, FEARG_1, f_term_setsize},
804 {"term_start", 1, 2, FEARG_1, f_term_start},
805 {"term_wait", 1, 2, FEARG_1, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200806#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200807 {"test_alloc_fail", 3, 3, FEARG_1, f_test_alloc_fail},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200808 {"test_autochdir", 0, 0, 0, f_test_autochdir},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200809 {"test_feedinput", 1, 1, FEARG_1, f_test_feedinput},
810 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
811 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
812 {"test_getvalue", 1, 1, FEARG_1, f_test_getvalue},
813 {"test_ignore_error", 1, 1, FEARG_1, f_test_ignore_error},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200814 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200815#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200816 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200818 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200820 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200822 {"test_null_list", 0, 0, 0, f_test_null_list},
823 {"test_null_partial", 0, 0, 0, f_test_null_partial},
824 {"test_null_string", 0, 0, 0, f_test_null_string},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200825 {"test_option_not_set", 1, 1, FEARG_1, f_test_option_not_set},
826 {"test_override", 2, 2, FEARG_2, f_test_override},
827 {"test_refcount", 1, 1, FEARG_1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200828#ifdef FEAT_GUI
Bram Moolenaarce90e362019-09-08 18:58:44 +0200829 {"test_scrollbar", 3, 3, FEARG_2, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200830#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200831 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200832 {"test_settime", 1, 1, FEARG_1, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200833#ifdef FEAT_TIMERS
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200834 {"timer_info", 0, 1, FEARG_1, f_timer_info},
835 {"timer_pause", 2, 2, FEARG_1, f_timer_pause},
836 {"timer_start", 2, 3, FEARG_1, f_timer_start},
837 {"timer_stop", 1, 1, FEARG_1, f_timer_stop},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200838 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839#endif
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200840 {"tolower", 1, 1, FEARG_1, f_tolower},
841 {"toupper", 1, 1, FEARG_1, f_toupper},
842 {"tr", 3, 3, FEARG_1, f_tr},
843 {"trim", 1, 2, FEARG_1, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200844#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200845 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200846#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200847 {"type", 1, 1, FEARG_1, f_type},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200848 {"undofile", 1, 1, FEARG_1, f_undofile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200849 {"undotree", 0, 0, 0, f_undotree},
850 {"uniq", 1, 3, FEARG_1, f_uniq},
851 {"values", 1, 1, FEARG_1, f_values},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200852 {"virtcol", 1, 1, FEARG_1, f_virtcol},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200853 {"visualmode", 0, 1, 0, f_visualmode},
854 {"wildmenumode", 0, 0, 0, f_wildmenumode},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200855 {"win_execute", 2, 3, FEARG_2, f_win_execute},
856 {"win_findbuf", 1, 1, FEARG_1, f_win_findbuf},
857 {"win_getid", 0, 2, FEARG_1, f_win_getid},
858 {"win_gotoid", 1, 1, FEARG_1, f_win_gotoid},
859 {"win_id2tabwin", 1, 1, FEARG_1, f_win_id2tabwin},
860 {"win_id2win", 1, 1, FEARG_1, f_win_id2win},
861 {"win_screenpos", 1, 1, FEARG_1, f_win_screenpos},
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200862 {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200863 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200864 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200865 {"winheight", 1, 1, FEARG_1, f_winheight},
866 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200867 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200868 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200869 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200870 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200871 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200872 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200873 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200874 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200875 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200876};
877
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200878/*
879 * Function given to ExpandGeneric() to obtain the list of internal
880 * or user defined function names.
881 */
882 char_u *
883get_function_name(expand_T *xp, int idx)
884{
885 static int intidx = -1;
886 char_u *name;
887
888 if (idx == 0)
889 intidx = -1;
890 if (intidx < 0)
891 {
892 name = get_user_func_name(xp, idx);
893 if (name != NULL)
894 return name;
895 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200896 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200897 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200898 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200899 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200900 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200901 STRCAT(IObuff, ")");
902 return IObuff;
903 }
904
905 return NULL;
906}
907
908/*
909 * Function given to ExpandGeneric() to obtain the list of internal or
910 * user defined variable or function names.
911 */
912 char_u *
913get_expr_name(expand_T *xp, int idx)
914{
915 static int intidx = -1;
916 char_u *name;
917
918 if (idx == 0)
919 intidx = -1;
920 if (intidx < 0)
921 {
922 name = get_function_name(xp, idx);
923 if (name != NULL)
924 return name;
925 }
926 return get_user_var_name(xp, ++intidx);
927}
928
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200930 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200931 * Return index, or -1 if not found
932 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200933 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200934find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935{
936 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200937 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200938 int cmp;
939 int x;
940
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200941 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200942
943 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200944 while (first <= last)
945 {
946 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200947 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200948 if (cmp < 0)
949 last = x - 1;
950 else if (cmp > 0)
951 first = x + 1;
952 else
953 return x;
954 }
955 return -1;
956}
957
958 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200959has_internal_func(char_u *name)
960{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200961 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200962}
963
964 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200965call_internal_func(
966 char_u *name,
967 int argcount,
968 typval_T *argvars,
969 typval_T *rettv)
970{
971 int i;
972
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200973 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200974 if (i < 0)
975 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200976 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200977 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200978 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200979 return ERROR_TOOMANY;
980 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200981 global_functions[i].f_func(argvars, rettv);
982 return ERROR_NONE;
983}
984
985/*
986 * Invoke a method for base->method().
987 */
988 int
989call_internal_method(
990 char_u *name,
991 int argcount,
992 typval_T *argvars,
993 typval_T *rettv,
994 typval_T *basetv)
995{
996 int i;
997 int fi;
998 typval_T argv[MAX_FUNC_ARGS + 1];
999
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001000 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001001 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001002 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001003 if (global_functions[fi].f_argtype == 0)
1004 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001005 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001006 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001007 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001008 return ERROR_TOOMANY;
1009
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001010 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001011 {
1012 // base value goes last
1013 for (i = 0; i < argcount; ++i)
1014 argv[i] = argvars[i];
1015 argv[argcount] = *basetv;
1016 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001017 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001018 {
1019 // base value goes second
1020 argv[0] = argvars[0];
1021 argv[1] = *basetv;
1022 for (i = 1; i < argcount; ++i)
1023 argv[i + 1] = argvars[i];
1024 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001025 else if (global_functions[fi].f_argtype == FEARG_3)
1026 {
1027 // base value goes third
1028 argv[0] = argvars[0];
1029 argv[1] = argvars[1];
1030 argv[2] = *basetv;
1031 for (i = 2; i < argcount; ++i)
1032 argv[i + 1] = argvars[i];
1033 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001034 else if (global_functions[fi].f_argtype == FEARG_4)
1035 {
1036 // base value goes fourth
1037 argv[0] = argvars[0];
1038 argv[1] = argvars[1];
1039 argv[2] = argvars[2];
1040 argv[3] = *basetv;
1041 for (i = 3; i < argcount; ++i)
1042 argv[i + 1] = argvars[i];
1043 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001044 else
1045 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001046 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001047 argv[0] = *basetv;
1048 for (i = 0; i < argcount; ++i)
1049 argv[i + 1] = argvars[i];
1050 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001051 argv[argcount + 1].v_type = VAR_UNKNOWN;
1052
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001053 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001054 return ERROR_NONE;
1055}
1056
1057/*
1058 * Return TRUE for a non-zero Number and a non-empty String.
1059 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001060 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001061non_zero_arg(typval_T *argvars)
1062{
1063 return ((argvars[0].v_type == VAR_NUMBER
1064 && argvars[0].vval.v_number != 0)
1065 || (argvars[0].v_type == VAR_SPECIAL
1066 && argvars[0].vval.v_number == VVAL_TRUE)
1067 || (argvars[0].v_type == VAR_STRING
1068 && argvars[0].vval.v_string != NULL
1069 && *argvars[0].vval.v_string != NUL));
1070}
1071
1072/*
1073 * Get the lnum from the first argument.
1074 * Also accepts ".", "$", etc., but that only works for the current buffer.
1075 * Returns -1 on error.
1076 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001077 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001078tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001079{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080 linenr_T lnum;
1081
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001082 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001083 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001084 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001085 int fnum;
1086 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1087
1088 if (fp != NULL)
1089 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001090 }
1091 return lnum;
1092}
1093
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001094/*
1095 * Get the lnum from the first argument.
1096 * Also accepts "$", then "buf" is used.
1097 * Returns 0 on error.
1098 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001099 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001100tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1101{
1102 if (argvars[0].v_type == VAR_STRING
1103 && argvars[0].vval.v_string != NULL
1104 && argvars[0].vval.v_string[0] == '$'
1105 && buf != NULL)
1106 return buf->b_ml.ml_line_count;
1107 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1108}
1109
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001110#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001111/*
1112 * Get the float value of "argvars[0]" into "f".
1113 * Returns FAIL when the argument is not a Number or Float.
1114 */
1115 static int
1116get_float_arg(typval_T *argvars, float_T *f)
1117{
1118 if (argvars[0].v_type == VAR_FLOAT)
1119 {
1120 *f = argvars[0].vval.v_float;
1121 return OK;
1122 }
1123 if (argvars[0].v_type == VAR_NUMBER)
1124 {
1125 *f = (float_T)argvars[0].vval.v_number;
1126 return OK;
1127 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001128 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001129 return FAIL;
1130}
1131
1132/*
1133 * "abs(expr)" function
1134 */
1135 static void
1136f_abs(typval_T *argvars, typval_T *rettv)
1137{
1138 if (argvars[0].v_type == VAR_FLOAT)
1139 {
1140 rettv->v_type = VAR_FLOAT;
1141 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1142 }
1143 else
1144 {
1145 varnumber_T n;
1146 int error = FALSE;
1147
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001148 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001149 if (error)
1150 rettv->vval.v_number = -1;
1151 else if (n > 0)
1152 rettv->vval.v_number = n;
1153 else
1154 rettv->vval.v_number = -n;
1155 }
1156}
1157
1158/*
1159 * "acos()" function
1160 */
1161 static void
1162f_acos(typval_T *argvars, typval_T *rettv)
1163{
1164 float_T f = 0.0;
1165
1166 rettv->v_type = VAR_FLOAT;
1167 if (get_float_arg(argvars, &f) == OK)
1168 rettv->vval.v_float = acos(f);
1169 else
1170 rettv->vval.v_float = 0.0;
1171}
1172#endif
1173
1174/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001175 * "and(expr, expr)" function
1176 */
1177 static void
1178f_and(typval_T *argvars, typval_T *rettv)
1179{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001180 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1181 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001182}
1183
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001184#ifdef FEAT_FLOAT
1185/*
1186 * "asin()" function
1187 */
1188 static void
1189f_asin(typval_T *argvars, typval_T *rettv)
1190{
1191 float_T f = 0.0;
1192
1193 rettv->v_type = VAR_FLOAT;
1194 if (get_float_arg(argvars, &f) == OK)
1195 rettv->vval.v_float = asin(f);
1196 else
1197 rettv->vval.v_float = 0.0;
1198}
1199
1200/*
1201 * "atan()" function
1202 */
1203 static void
1204f_atan(typval_T *argvars, typval_T *rettv)
1205{
1206 float_T f = 0.0;
1207
1208 rettv->v_type = VAR_FLOAT;
1209 if (get_float_arg(argvars, &f) == OK)
1210 rettv->vval.v_float = atan(f);
1211 else
1212 rettv->vval.v_float = 0.0;
1213}
1214
1215/*
1216 * "atan2()" function
1217 */
1218 static void
1219f_atan2(typval_T *argvars, typval_T *rettv)
1220{
1221 float_T fx = 0.0, fy = 0.0;
1222
1223 rettv->v_type = VAR_FLOAT;
1224 if (get_float_arg(argvars, &fx) == OK
1225 && get_float_arg(&argvars[1], &fy) == OK)
1226 rettv->vval.v_float = atan2(fx, fy);
1227 else
1228 rettv->vval.v_float = 0.0;
1229}
1230#endif
1231
1232/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001233 * "balloon_show()" function
1234 */
1235#ifdef FEAT_BEVAL
1236 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001237f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1238{
1239 rettv->v_type = VAR_STRING;
1240 if (balloonEval != NULL)
1241 {
1242 if (balloonEval->msg == NULL)
1243 rettv->vval.v_string = NULL;
1244 else
1245 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1246 }
1247}
1248
1249 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001250f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1251{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001252 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001253 {
1254 if (argvars[0].v_type == VAR_LIST
1255# ifdef FEAT_GUI
1256 && !gui.in_use
1257# endif
1258 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001259 {
1260 list_T *l = argvars[0].vval.v_list;
1261
1262 // empty list removes the balloon
1263 post_balloon(balloonEval, NULL,
1264 l == NULL || l->lv_len == 0 ? NULL : l);
1265 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001266 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001267 {
1268 char_u *mesg = tv_get_string_chk(&argvars[0]);
1269
1270 if (mesg != NULL)
1271 // empty string removes the balloon
1272 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1273 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001274 }
1275}
1276
Bram Moolenaar669a8282017-11-19 20:13:05 +01001277# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001278 static void
1279f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1280{
1281 if (rettv_list_alloc(rettv) == OK)
1282 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001283 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001284
1285 if (msg != NULL)
1286 {
1287 pumitem_T *array;
1288 int size = split_message(msg, &array);
1289 int i;
1290
1291 /* Skip the first and last item, they are always empty. */
1292 for (i = 1; i < size - 1; ++i)
1293 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001294 while (size > 0)
1295 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001296 vim_free(array);
1297 }
1298 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001299}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001300# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001301#endif
1302
1303/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001304 * Get buffer by number or pattern.
1305 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001306 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001307tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001308{
1309 char_u *name = tv->vval.v_string;
1310 buf_T *buf;
1311
1312 if (tv->v_type == VAR_NUMBER)
1313 return buflist_findnr((int)tv->vval.v_number);
1314 if (tv->v_type != VAR_STRING)
1315 return NULL;
1316 if (name == NULL || *name == NUL)
1317 return curbuf;
1318 if (name[0] == '$' && name[1] == NUL)
1319 return lastbuf;
1320
1321 buf = buflist_find_by_name(name, curtab_only);
1322
1323 /* If not found, try expanding the name, like done for bufexists(). */
1324 if (buf == NULL)
1325 buf = find_buffer(tv);
1326
1327 return buf;
1328}
1329
1330/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001331 * Get the buffer from "arg" and give an error and return NULL if it is not
1332 * valid.
1333 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001334 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001335get_buf_arg(typval_T *arg)
1336{
1337 buf_T *buf;
1338
1339 ++emsg_off;
1340 buf = tv_get_buf(arg, FALSE);
1341 --emsg_off;
1342 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001343 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001344 return buf;
1345}
1346
1347/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001348 * "byte2line(byte)" function
1349 */
1350 static void
1351f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1352{
1353#ifndef FEAT_BYTEOFF
1354 rettv->vval.v_number = -1;
1355#else
1356 long boff = 0;
1357
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001358 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001359 if (boff < 0)
1360 rettv->vval.v_number = -1;
1361 else
1362 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1363 (linenr_T)0, &boff);
1364#endif
1365}
1366
1367 static void
1368byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1369{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001370 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001371 char_u *str;
1372 varnumber_T idx;
1373
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001374 str = tv_get_string_chk(&argvars[0]);
1375 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001376 rettv->vval.v_number = -1;
1377 if (str == NULL || idx < 0)
1378 return;
1379
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001380 t = str;
1381 for ( ; idx > 0; idx--)
1382 {
1383 if (*t == NUL) /* EOL reached */
1384 return;
1385 if (enc_utf8 && comp)
1386 t += utf_ptr2len(t);
1387 else
1388 t += (*mb_ptr2len)(t);
1389 }
1390 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001391}
1392
1393/*
1394 * "byteidx()" function
1395 */
1396 static void
1397f_byteidx(typval_T *argvars, typval_T *rettv)
1398{
1399 byteidx(argvars, rettv, FALSE);
1400}
1401
1402/*
1403 * "byteidxcomp()" function
1404 */
1405 static void
1406f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1407{
1408 byteidx(argvars, rettv, TRUE);
1409}
1410
1411/*
1412 * "call(func, arglist [, dict])" function
1413 */
1414 static void
1415f_call(typval_T *argvars, typval_T *rettv)
1416{
1417 char_u *func;
1418 partial_T *partial = NULL;
1419 dict_T *selfdict = NULL;
1420
1421 if (argvars[1].v_type != VAR_LIST)
1422 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001423 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001424 return;
1425 }
1426 if (argvars[1].vval.v_list == NULL)
1427 return;
1428
1429 if (argvars[0].v_type == VAR_FUNC)
1430 func = argvars[0].vval.v_string;
1431 else if (argvars[0].v_type == VAR_PARTIAL)
1432 {
1433 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001434 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001435 }
1436 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001437 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001438 if (*func == NUL)
1439 return; /* type error or empty name */
1440
1441 if (argvars[2].v_type != VAR_UNKNOWN)
1442 {
1443 if (argvars[2].v_type != VAR_DICT)
1444 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001445 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001446 return;
1447 }
1448 selfdict = argvars[2].vval.v_dict;
1449 }
1450
1451 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1452}
1453
1454#ifdef FEAT_FLOAT
1455/*
1456 * "ceil({float})" function
1457 */
1458 static void
1459f_ceil(typval_T *argvars, typval_T *rettv)
1460{
1461 float_T f = 0.0;
1462
1463 rettv->v_type = VAR_FLOAT;
1464 if (get_float_arg(argvars, &f) == OK)
1465 rettv->vval.v_float = ceil(f);
1466 else
1467 rettv->vval.v_float = 0.0;
1468}
1469#endif
1470
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001471/*
1472 * "changenr()" function
1473 */
1474 static void
1475f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1476{
1477 rettv->vval.v_number = curbuf->b_u_seq_cur;
1478}
1479
1480/*
1481 * "char2nr(string)" function
1482 */
1483 static void
1484f_char2nr(typval_T *argvars, typval_T *rettv)
1485{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486 if (has_mbyte)
1487 {
1488 int utf8 = 0;
1489
1490 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001491 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001492
1493 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001494 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001495 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001496 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001497 }
1498 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001499 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001500}
1501
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001502 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001503get_optional_window(typval_T *argvars, int idx)
1504{
1505 win_T *win = curwin;
1506
1507 if (argvars[idx].v_type != VAR_UNKNOWN)
1508 {
1509 win = find_win_by_nr_or_id(&argvars[idx]);
1510 if (win == NULL)
1511 {
1512 emsg(_(e_invalwindow));
1513 return NULL;
1514 }
1515 }
1516 return win;
1517}
1518
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001519/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001520 * "col(string)" function
1521 */
1522 static void
1523f_col(typval_T *argvars, typval_T *rettv)
1524{
1525 colnr_T col = 0;
1526 pos_T *fp;
1527 int fnum = curbuf->b_fnum;
1528
1529 fp = var2fpos(&argvars[0], FALSE, &fnum);
1530 if (fp != NULL && fnum == curbuf->b_fnum)
1531 {
1532 if (fp->col == MAXCOL)
1533 {
1534 /* '> can be MAXCOL, get the length of the line then */
1535 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1536 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1537 else
1538 col = MAXCOL;
1539 }
1540 else
1541 {
1542 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001543 /* col(".") when the cursor is on the NUL at the end of the line
1544 * because of "coladd" can be seen as an extra column. */
1545 if (virtual_active() && fp == &curwin->w_cursor)
1546 {
1547 char_u *p = ml_get_cursor();
1548
1549 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1550 curwin->w_virtcol - curwin->w_cursor.coladd))
1551 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001552 int l;
1553
1554 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1555 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 }
1557 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001558 }
1559 }
1560 rettv->vval.v_number = col;
1561}
1562
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001563/*
1564 * "confirm(message, buttons[, default [, type]])" function
1565 */
1566 static void
1567f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1568{
1569#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1570 char_u *message;
1571 char_u *buttons = NULL;
1572 char_u buf[NUMBUFLEN];
1573 char_u buf2[NUMBUFLEN];
1574 int def = 1;
1575 int type = VIM_GENERIC;
1576 char_u *typestr;
1577 int error = FALSE;
1578
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001579 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580 if (message == NULL)
1581 error = TRUE;
1582 if (argvars[1].v_type != VAR_UNKNOWN)
1583 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001584 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001585 if (buttons == NULL)
1586 error = TRUE;
1587 if (argvars[2].v_type != VAR_UNKNOWN)
1588 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001589 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001590 if (argvars[3].v_type != VAR_UNKNOWN)
1591 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001592 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001593 if (typestr == NULL)
1594 error = TRUE;
1595 else
1596 {
1597 switch (TOUPPER_ASC(*typestr))
1598 {
1599 case 'E': type = VIM_ERROR; break;
1600 case 'Q': type = VIM_QUESTION; break;
1601 case 'I': type = VIM_INFO; break;
1602 case 'W': type = VIM_WARNING; break;
1603 case 'G': type = VIM_GENERIC; break;
1604 }
1605 }
1606 }
1607 }
1608 }
1609
1610 if (buttons == NULL || *buttons == NUL)
1611 buttons = (char_u *)_("&Ok");
1612
1613 if (!error)
1614 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1615 def, NULL, FALSE);
1616#endif
1617}
1618
1619/*
1620 * "copy()" function
1621 */
1622 static void
1623f_copy(typval_T *argvars, typval_T *rettv)
1624{
1625 item_copy(&argvars[0], rettv, FALSE, 0);
1626}
1627
1628#ifdef FEAT_FLOAT
1629/*
1630 * "cos()" function
1631 */
1632 static void
1633f_cos(typval_T *argvars, typval_T *rettv)
1634{
1635 float_T f = 0.0;
1636
1637 rettv->v_type = VAR_FLOAT;
1638 if (get_float_arg(argvars, &f) == OK)
1639 rettv->vval.v_float = cos(f);
1640 else
1641 rettv->vval.v_float = 0.0;
1642}
1643
1644/*
1645 * "cosh()" function
1646 */
1647 static void
1648f_cosh(typval_T *argvars, typval_T *rettv)
1649{
1650 float_T f = 0.0;
1651
1652 rettv->v_type = VAR_FLOAT;
1653 if (get_float_arg(argvars, &f) == OK)
1654 rettv->vval.v_float = cosh(f);
1655 else
1656 rettv->vval.v_float = 0.0;
1657}
1658#endif
1659
1660/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661 * "cursor(lnum, col)" function, or
1662 * "cursor(list)"
1663 *
1664 * Moves the cursor to the specified line and column.
1665 * Returns 0 when the position could be set, -1 otherwise.
1666 */
1667 static void
1668f_cursor(typval_T *argvars, typval_T *rettv)
1669{
1670 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001671 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001672 int set_curswant = TRUE;
1673
1674 rettv->vval.v_number = -1;
1675 if (argvars[1].v_type == VAR_UNKNOWN)
1676 {
1677 pos_T pos;
1678 colnr_T curswant = -1;
1679
1680 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1681 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001682 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001683 return;
1684 }
1685 line = pos.lnum;
1686 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 if (curswant >= 0)
1689 {
1690 curwin->w_curswant = curswant - 1;
1691 set_curswant = FALSE;
1692 }
1693 }
1694 else
1695 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001696 line = tv_get_lnum(argvars);
1697 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001698 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001699 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001700 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001701 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001702 return; /* type error; errmsg already given */
1703 if (line > 0)
1704 curwin->w_cursor.lnum = line;
1705 if (col > 0)
1706 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001707 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001708
1709 /* Make sure the cursor is in a valid position. */
1710 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001711 /* Correct cursor for multi-byte character. */
1712 if (has_mbyte)
1713 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714
1715 curwin->w_set_curswant = set_curswant;
1716 rettv->vval.v_number = 0;
1717}
1718
Bram Moolenaar4f974752019-02-17 17:44:42 +01001719#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001720/*
1721 * "debugbreak()" function
1722 */
1723 static void
1724f_debugbreak(typval_T *argvars, typval_T *rettv)
1725{
1726 int pid;
1727
1728 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001729 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001730 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001731 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001732 else
1733 {
1734 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1735
1736 if (hProcess != NULL)
1737 {
1738 DebugBreakProcess(hProcess);
1739 CloseHandle(hProcess);
1740 rettv->vval.v_number = OK;
1741 }
1742 }
1743}
1744#endif
1745
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001746/*
1747 * "deepcopy()" function
1748 */
1749 static void
1750f_deepcopy(typval_T *argvars, typval_T *rettv)
1751{
1752 int noref = 0;
1753 int copyID;
1754
1755 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001756 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001757 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001758 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001759 else
1760 {
1761 copyID = get_copyID();
1762 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1763 }
1764}
1765
1766/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001767 * "did_filetype()" function
1768 */
1769 static void
1770f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1771{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001772 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001773}
1774
1775/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001776 * "empty({expr})" function
1777 */
1778 static void
1779f_empty(typval_T *argvars, typval_T *rettv)
1780{
1781 int n = FALSE;
1782
1783 switch (argvars[0].v_type)
1784 {
1785 case VAR_STRING:
1786 case VAR_FUNC:
1787 n = argvars[0].vval.v_string == NULL
1788 || *argvars[0].vval.v_string == NUL;
1789 break;
1790 case VAR_PARTIAL:
1791 n = FALSE;
1792 break;
1793 case VAR_NUMBER:
1794 n = argvars[0].vval.v_number == 0;
1795 break;
1796 case VAR_FLOAT:
1797#ifdef FEAT_FLOAT
1798 n = argvars[0].vval.v_float == 0.0;
1799 break;
1800#endif
1801 case VAR_LIST:
1802 n = argvars[0].vval.v_list == NULL
1803 || argvars[0].vval.v_list->lv_first == NULL;
1804 break;
1805 case VAR_DICT:
1806 n = argvars[0].vval.v_dict == NULL
1807 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1808 break;
1809 case VAR_SPECIAL:
1810 n = argvars[0].vval.v_number != VVAL_TRUE;
1811 break;
1812
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001813 case VAR_BLOB:
1814 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001815 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1816 break;
1817
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001818 case VAR_JOB:
1819#ifdef FEAT_JOB_CHANNEL
1820 n = argvars[0].vval.v_job == NULL
1821 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1822 break;
1823#endif
1824 case VAR_CHANNEL:
1825#ifdef FEAT_JOB_CHANNEL
1826 n = argvars[0].vval.v_channel == NULL
1827 || !channel_is_open(argvars[0].vval.v_channel);
1828 break;
1829#endif
1830 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001831 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 n = TRUE;
1833 break;
1834 }
1835
1836 rettv->vval.v_number = n;
1837}
1838
1839/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001840 * "environ()" function
1841 */
1842 static void
1843f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1844{
1845#if !defined(AMIGA)
1846 int i = 0;
1847 char_u *entry, *value;
1848# ifdef MSWIN
1849 extern wchar_t **_wenviron;
1850# else
1851 extern char **environ;
1852# endif
1853
1854 if (rettv_dict_alloc(rettv) != OK)
1855 return;
1856
1857# ifdef MSWIN
1858 if (*_wenviron == NULL)
1859 return;
1860# else
1861 if (*environ == NULL)
1862 return;
1863# endif
1864
1865 for (i = 0; ; ++i)
1866 {
1867# ifdef MSWIN
1868 short_u *p;
1869
1870 if ((p = (short_u *)_wenviron[i]) == NULL)
1871 return;
1872 entry = utf16_to_enc(p, NULL);
1873# else
1874 if ((entry = (char_u *)environ[i]) == NULL)
1875 return;
1876 entry = vim_strsave(entry);
1877# endif
1878 if (entry == NULL) // out of memory
1879 return;
1880 if ((value = vim_strchr(entry, '=')) == NULL)
1881 {
1882 vim_free(entry);
1883 continue;
1884 }
1885 *value++ = NUL;
1886 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1887 vim_free(entry);
1888 }
1889#endif
1890}
1891
1892/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001893 * "escape({string}, {chars})" function
1894 */
1895 static void
1896f_escape(typval_T *argvars, typval_T *rettv)
1897{
1898 char_u buf[NUMBUFLEN];
1899
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001900 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1901 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001902 rettv->v_type = VAR_STRING;
1903}
1904
1905/*
1906 * "eval()" function
1907 */
1908 static void
1909f_eval(typval_T *argvars, typval_T *rettv)
1910{
1911 char_u *s, *p;
1912
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001913 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001914 if (s != NULL)
1915 s = skipwhite(s);
1916
1917 p = s;
1918 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1919 {
1920 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001921 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001922 need_clr_eos = FALSE;
1923 rettv->v_type = VAR_NUMBER;
1924 rettv->vval.v_number = 0;
1925 }
1926 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001927 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928}
1929
1930/*
1931 * "eventhandler()" function
1932 */
1933 static void
1934f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1935{
1936 rettv->vval.v_number = vgetc_busy;
1937}
1938
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001939static garray_T redir_execute_ga;
1940
1941/*
1942 * Append "value[value_len]" to the execute() output.
1943 */
1944 void
1945execute_redir_str(char_u *value, int value_len)
1946{
1947 int len;
1948
1949 if (value_len == -1)
1950 len = (int)STRLEN(value); /* Append the entire string */
1951 else
1952 len = value_len; /* Append only "value_len" characters */
1953 if (ga_grow(&redir_execute_ga, len) == OK)
1954 {
1955 mch_memmove((char *)redir_execute_ga.ga_data
1956 + redir_execute_ga.ga_len, value, len);
1957 redir_execute_ga.ga_len += len;
1958 }
1959}
1960
1961/*
1962 * Get next line from a list.
1963 * Called by do_cmdline() to get the next line.
1964 * Returns allocated string, or NULL for end of function.
1965 */
1966
1967 static char_u *
1968get_list_line(
1969 int c UNUSED,
1970 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001971 int indent UNUSED,
1972 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001973{
1974 listitem_T **p = (listitem_T **)cookie;
1975 listitem_T *item = *p;
1976 char_u buf[NUMBUFLEN];
1977 char_u *s;
1978
1979 if (item == NULL)
1980 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001981 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001982 *p = item->li_next;
1983 return s == NULL ? NULL : vim_strsave(s);
1984}
1985
1986/*
1987 * "execute()" function
1988 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001989 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001990execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991{
1992 char_u *cmd = NULL;
1993 list_T *list = NULL;
1994 int save_msg_silent = msg_silent;
1995 int save_emsg_silent = emsg_silent;
1996 int save_emsg_noredir = emsg_noredir;
1997 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01001998 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001999 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002000 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002001 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002002
2003 rettv->vval.v_string = NULL;
2004 rettv->v_type = VAR_STRING;
2005
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002006 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002007 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002008 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002009 if (list == NULL || list->lv_first == NULL)
2010 /* empty list, no commands, empty output */
2011 return;
2012 ++list->lv_refcount;
2013 }
2014 else
2015 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002016 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002017 if (cmd == NULL)
2018 return;
2019 }
2020
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002021 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002022 {
2023 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002024 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002025
2026 if (s == NULL)
2027 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002028 if (*s == NUL)
2029 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002030 if (STRNCMP(s, "silent", 6) == 0)
2031 ++msg_silent;
2032 if (STRCMP(s, "silent!") == 0)
2033 {
2034 emsg_silent = TRUE;
2035 emsg_noredir = TRUE;
2036 }
2037 }
2038 else
2039 ++msg_silent;
2040
2041 if (redir_execute)
2042 save_ga = redir_execute_ga;
2043 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2044 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002045 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002046 if (!echo_output)
2047 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002048
2049 if (cmd != NULL)
2050 do_cmdline_cmd(cmd);
2051 else
2052 {
2053 listitem_T *item = list->lv_first;
2054
2055 do_cmdline(NULL, get_list_line, (void *)&item,
2056 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2057 --list->lv_refcount;
2058 }
2059
Bram Moolenaard297f352017-01-29 20:31:21 +01002060 /* Need to append a NUL to the result. */
2061 if (ga_grow(&redir_execute_ga, 1) == OK)
2062 {
2063 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2064 rettv->vval.v_string = redir_execute_ga.ga_data;
2065 }
2066 else
2067 {
2068 ga_clear(&redir_execute_ga);
2069 rettv->vval.v_string = NULL;
2070 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002071 msg_silent = save_msg_silent;
2072 emsg_silent = save_emsg_silent;
2073 emsg_noredir = save_emsg_noredir;
2074
2075 redir_execute = save_redir_execute;
2076 if (redir_execute)
2077 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002078 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002079
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002080 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002081 if (echo_output)
2082 // When not working silently: put it in column zero. A following
2083 // "echon" will overwrite the message, unavoidably.
2084 msg_col = 0;
2085 else
2086 // When working silently: Put it back where it was, since nothing
2087 // should have been written.
2088 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002089}
2090
2091/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002092 * "execute()" function
2093 */
2094 static void
2095f_execute(typval_T *argvars, typval_T *rettv)
2096{
2097 execute_common(argvars, rettv, 0);
2098}
2099
2100/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002101 * "exists()" function
2102 */
2103 static void
2104f_exists(typval_T *argvars, typval_T *rettv)
2105{
2106 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002107 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002108
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002109 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002110 if (*p == '$') /* environment variable */
2111 {
2112 /* first try "normal" environment variables (fast) */
2113 if (mch_getenv(p + 1) != NULL)
2114 n = TRUE;
2115 else
2116 {
2117 /* try expanding things like $VIM and ${HOME} */
2118 p = expand_env_save(p);
2119 if (p != NULL && *p != '$')
2120 n = TRUE;
2121 vim_free(p);
2122 }
2123 }
2124 else if (*p == '&' || *p == '+') /* option */
2125 {
2126 n = (get_option_tv(&p, NULL, TRUE) == OK);
2127 if (*skipwhite(p) != NUL)
2128 n = FALSE; /* trailing garbage */
2129 }
2130 else if (*p == '*') /* internal or user defined function */
2131 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002132 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002133 }
2134 else if (*p == ':')
2135 {
2136 n = cmd_exists(p + 1);
2137 }
2138 else if (*p == '#')
2139 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002140 if (p[1] == '#')
2141 n = autocmd_supported(p + 2);
2142 else
2143 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002144 }
2145 else /* internal variable */
2146 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002147 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002148 }
2149
2150 rettv->vval.v_number = n;
2151}
2152
2153#ifdef FEAT_FLOAT
2154/*
2155 * "exp()" function
2156 */
2157 static void
2158f_exp(typval_T *argvars, typval_T *rettv)
2159{
2160 float_T f = 0.0;
2161
2162 rettv->v_type = VAR_FLOAT;
2163 if (get_float_arg(argvars, &f) == OK)
2164 rettv->vval.v_float = exp(f);
2165 else
2166 rettv->vval.v_float = 0.0;
2167}
2168#endif
2169
2170/*
2171 * "expand()" function
2172 */
2173 static void
2174f_expand(typval_T *argvars, typval_T *rettv)
2175{
2176 char_u *s;
2177 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002178 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002179 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2180 expand_T xpc;
2181 int error = FALSE;
2182 char_u *result;
2183
2184 rettv->v_type = VAR_STRING;
2185 if (argvars[1].v_type != VAR_UNKNOWN
2186 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002187 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002188 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002189 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002190
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002191 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002192 if (*s == '%' || *s == '#' || *s == '<')
2193 {
2194 ++emsg_off;
2195 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2196 --emsg_off;
2197 if (rettv->v_type == VAR_LIST)
2198 {
2199 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2200 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002201 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002202 }
2203 else
2204 rettv->vval.v_string = result;
2205 }
2206 else
2207 {
2208 /* When the optional second argument is non-zero, don't remove matches
2209 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2210 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002211 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002212 options |= WILD_KEEP_ALL;
2213 if (!error)
2214 {
2215 ExpandInit(&xpc);
2216 xpc.xp_context = EXPAND_FILES;
2217 if (p_wic)
2218 options += WILD_ICASE;
2219 if (rettv->v_type == VAR_STRING)
2220 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2221 options, WILD_ALL);
2222 else if (rettv_list_alloc(rettv) != FAIL)
2223 {
2224 int i;
2225
2226 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2227 for (i = 0; i < xpc.xp_numfiles; i++)
2228 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2229 ExpandCleanup(&xpc);
2230 }
2231 }
2232 else
2233 rettv->vval.v_string = NULL;
2234 }
2235}
2236
2237/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002238 * "expandcmd()" function
2239 * Expand all the special characters in a command string.
2240 */
2241 static void
2242f_expandcmd(typval_T *argvars, typval_T *rettv)
2243{
2244 exarg_T eap;
2245 char_u *cmdstr;
2246 char *errormsg = NULL;
2247
2248 rettv->v_type = VAR_STRING;
2249 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2250
2251 memset(&eap, 0, sizeof(eap));
2252 eap.cmd = cmdstr;
2253 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002254 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002255 eap.usefilter = FALSE;
2256 eap.nextcmd = NULL;
2257 eap.cmdidx = CMD_USER;
2258
2259 expand_filename(&eap, &cmdstr, &errormsg);
2260 if (errormsg != NULL && *errormsg != NUL)
2261 emsg(errormsg);
2262
2263 rettv->vval.v_string = cmdstr;
2264}
2265
2266/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002267 * "feedkeys()" function
2268 */
2269 static void
2270f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2271{
2272 int remap = TRUE;
2273 int insert = FALSE;
2274 char_u *keys, *flags;
2275 char_u nbuf[NUMBUFLEN];
2276 int typed = FALSE;
2277 int execute = FALSE;
2278 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002279 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 char_u *keys_esc;
2281
2282 /* This is not allowed in the sandbox. If the commands would still be
2283 * executed in the sandbox it would be OK, but it probably happens later,
2284 * when "sandbox" is no longer set. */
2285 if (check_secure())
2286 return;
2287
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002288 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002289
2290 if (argvars[1].v_type != VAR_UNKNOWN)
2291 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002292 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002293 for ( ; *flags != NUL; ++flags)
2294 {
2295 switch (*flags)
2296 {
2297 case 'n': remap = FALSE; break;
2298 case 'm': remap = TRUE; break;
2299 case 't': typed = TRUE; break;
2300 case 'i': insert = TRUE; break;
2301 case 'x': execute = TRUE; break;
2302 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002303 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002304 }
2305 }
2306 }
2307
2308 if (*keys != NUL || execute)
2309 {
2310 /* Need to escape K_SPECIAL and CSI before putting the string in the
2311 * typeahead buffer. */
2312 keys_esc = vim_strsave_escape_csi(keys);
2313 if (keys_esc != NULL)
2314 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002315 if (lowlevel)
2316 {
2317#ifdef USE_INPUT_BUF
2318 add_to_input_buf(keys, (int)STRLEN(keys));
2319#else
2320 emsg(_("E980: lowlevel input not supported"));
2321#endif
2322 }
2323 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002324 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002325 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002326 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002327 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002328#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002329 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002330#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002331 )
2332 typebuf_was_filled = TRUE;
2333 }
2334 vim_free(keys_esc);
2335
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002336 if (execute)
2337 {
2338 int save_msg_scroll = msg_scroll;
2339
2340 /* Avoid a 1 second delay when the keys start Insert mode. */
2341 msg_scroll = FALSE;
2342
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002343 if (!dangerous)
2344 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002345 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002346 if (!dangerous)
2347 --ex_normal_busy;
2348
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002349 msg_scroll |= save_msg_scroll;
2350 }
2351 }
2352 }
2353}
2354
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002355#ifdef FEAT_FLOAT
2356/*
2357 * "float2nr({float})" function
2358 */
2359 static void
2360f_float2nr(typval_T *argvars, typval_T *rettv)
2361{
2362 float_T f = 0.0;
2363
2364 if (get_float_arg(argvars, &f) == OK)
2365 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002366 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002367 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002368 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002369 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370 else
2371 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002372 }
2373}
2374
2375/*
2376 * "floor({float})" function
2377 */
2378 static void
2379f_floor(typval_T *argvars, typval_T *rettv)
2380{
2381 float_T f = 0.0;
2382
2383 rettv->v_type = VAR_FLOAT;
2384 if (get_float_arg(argvars, &f) == OK)
2385 rettv->vval.v_float = floor(f);
2386 else
2387 rettv->vval.v_float = 0.0;
2388}
2389
2390/*
2391 * "fmod()" function
2392 */
2393 static void
2394f_fmod(typval_T *argvars, typval_T *rettv)
2395{
2396 float_T fx = 0.0, fy = 0.0;
2397
2398 rettv->v_type = VAR_FLOAT;
2399 if (get_float_arg(argvars, &fx) == OK
2400 && get_float_arg(&argvars[1], &fy) == OK)
2401 rettv->vval.v_float = fmod(fx, fy);
2402 else
2403 rettv->vval.v_float = 0.0;
2404}
2405#endif
2406
2407/*
2408 * "fnameescape({string})" function
2409 */
2410 static void
2411f_fnameescape(typval_T *argvars, typval_T *rettv)
2412{
2413 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002414 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002415 rettv->v_type = VAR_STRING;
2416}
2417
2418/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419 * "foreground()" function
2420 */
2421 static void
2422f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2423{
2424#ifdef FEAT_GUI
2425 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002426 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002427 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002428 return;
2429 }
2430#endif
2431#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002432 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002433#endif
2434}
2435
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002436 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002437common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002438{
2439 char_u *s;
2440 char_u *name;
2441 int use_string = FALSE;
2442 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002443 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002444
2445 if (argvars[0].v_type == VAR_FUNC)
2446 {
2447 /* function(MyFunc, [arg], dict) */
2448 s = argvars[0].vval.v_string;
2449 }
2450 else if (argvars[0].v_type == VAR_PARTIAL
2451 && argvars[0].vval.v_partial != NULL)
2452 {
2453 /* function(dict.MyFunc, [arg]) */
2454 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002455 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002456 }
2457 else
2458 {
2459 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002460 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 use_string = TRUE;
2462 }
2463
Bram Moolenaar843b8842016-08-21 14:36:15 +02002464 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002465 {
2466 name = s;
2467 trans_name = trans_function_name(&name, FALSE,
2468 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2469 if (*name != NUL)
2470 s = NULL;
2471 }
2472
Bram Moolenaar843b8842016-08-21 14:36:15 +02002473 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2474 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002475 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002476 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002477 else if (trans_name != NULL && (is_funcref
2478 ? find_func(trans_name) == NULL
2479 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002480 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002481 else
2482 {
2483 int dict_idx = 0;
2484 int arg_idx = 0;
2485 list_T *list = NULL;
2486
2487 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2488 {
2489 char sid_buf[25];
2490 int off = *s == 's' ? 2 : 5;
2491
2492 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2493 * also be called from another script. Using trans_function_name()
2494 * would also work, but some plugins depend on the name being
2495 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002496 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002497 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002498 if (name != NULL)
2499 {
2500 STRCPY(name, sid_buf);
2501 STRCAT(name, s + off);
2502 }
2503 }
2504 else
2505 name = vim_strsave(s);
2506
2507 if (argvars[1].v_type != VAR_UNKNOWN)
2508 {
2509 if (argvars[2].v_type != VAR_UNKNOWN)
2510 {
2511 /* function(name, [args], dict) */
2512 arg_idx = 1;
2513 dict_idx = 2;
2514 }
2515 else if (argvars[1].v_type == VAR_DICT)
2516 /* function(name, dict) */
2517 dict_idx = 1;
2518 else
2519 /* function(name, [args]) */
2520 arg_idx = 1;
2521 if (dict_idx > 0)
2522 {
2523 if (argvars[dict_idx].v_type != VAR_DICT)
2524 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002525 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002527 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528 }
2529 if (argvars[dict_idx].vval.v_dict == NULL)
2530 dict_idx = 0;
2531 }
2532 if (arg_idx > 0)
2533 {
2534 if (argvars[arg_idx].v_type != VAR_LIST)
2535 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002536 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002538 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002539 }
2540 list = argvars[arg_idx].vval.v_list;
2541 if (list == NULL || list->lv_len == 0)
2542 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002543 else if (list->lv_len > MAX_FUNC_ARGS)
2544 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002545 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002546 vim_free(name);
2547 goto theend;
2548 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002549 }
2550 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002551 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002552 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002553 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554
2555 /* result is a VAR_PARTIAL */
2556 if (pt == NULL)
2557 vim_free(name);
2558 else
2559 {
2560 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2561 {
2562 listitem_T *li;
2563 int i = 0;
2564 int arg_len = 0;
2565 int lv_len = 0;
2566
2567 if (arg_pt != NULL)
2568 arg_len = arg_pt->pt_argc;
2569 if (list != NULL)
2570 lv_len = list->lv_len;
2571 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002572 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002573 if (pt->pt_argv == NULL)
2574 {
2575 vim_free(pt);
2576 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002577 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002578 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002579 for (i = 0; i < arg_len; i++)
2580 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2581 if (lv_len > 0)
2582 for (li = list->lv_first; li != NULL;
2583 li = li->li_next)
2584 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002585 }
2586
2587 /* For "function(dict.func, [], dict)" and "func" is a partial
2588 * use "dict". That is backwards compatible. */
2589 if (dict_idx > 0)
2590 {
2591 /* The dict is bound explicitly, pt_auto is FALSE. */
2592 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2593 ++pt->pt_dict->dv_refcount;
2594 }
2595 else if (arg_pt != NULL)
2596 {
2597 /* If the dict was bound automatically the result is also
2598 * bound automatically. */
2599 pt->pt_dict = arg_pt->pt_dict;
2600 pt->pt_auto = arg_pt->pt_auto;
2601 if (pt->pt_dict != NULL)
2602 ++pt->pt_dict->dv_refcount;
2603 }
2604
2605 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002606 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2607 {
2608 pt->pt_func = arg_pt->pt_func;
2609 func_ptr_ref(pt->pt_func);
2610 vim_free(name);
2611 }
2612 else if (is_funcref)
2613 {
2614 pt->pt_func = find_func(trans_name);
2615 func_ptr_ref(pt->pt_func);
2616 vim_free(name);
2617 }
2618 else
2619 {
2620 pt->pt_name = name;
2621 func_ref(name);
2622 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002623 }
2624 rettv->v_type = VAR_PARTIAL;
2625 rettv->vval.v_partial = pt;
2626 }
2627 else
2628 {
2629 /* result is a VAR_FUNC */
2630 rettv->v_type = VAR_FUNC;
2631 rettv->vval.v_string = name;
2632 func_ref(name);
2633 }
2634 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002635theend:
2636 vim_free(trans_name);
2637}
2638
2639/*
2640 * "funcref()" function
2641 */
2642 static void
2643f_funcref(typval_T *argvars, typval_T *rettv)
2644{
2645 common_function(argvars, rettv, TRUE);
2646}
2647
2648/*
2649 * "function()" function
2650 */
2651 static void
2652f_function(typval_T *argvars, typval_T *rettv)
2653{
2654 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002655}
2656
2657/*
2658 * "garbagecollect()" function
2659 */
2660 static void
2661f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2662{
2663 /* This is postponed until we are back at the toplevel, because we may be
2664 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2665 want_garbage_collect = TRUE;
2666
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002667 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002668 garbage_collect_at_exit = TRUE;
2669}
2670
2671/*
2672 * "get()" function
2673 */
2674 static void
2675f_get(typval_T *argvars, typval_T *rettv)
2676{
2677 listitem_T *li;
2678 list_T *l;
2679 dictitem_T *di;
2680 dict_T *d;
2681 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002682 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002683
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002684 if (argvars[0].v_type == VAR_BLOB)
2685 {
2686 int error = FALSE;
2687 int idx = tv_get_number_chk(&argvars[1], &error);
2688
2689 if (!error)
2690 {
2691 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002692 if (idx < 0)
2693 idx = blob_len(argvars[0].vval.v_blob) + idx;
2694 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2695 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002696 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002697 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002698 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002699 tv = rettv;
2700 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002701 }
2702 }
2703 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002704 {
2705 if ((l = argvars[0].vval.v_list) != NULL)
2706 {
2707 int error = FALSE;
2708
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002709 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002710 if (!error && li != NULL)
2711 tv = &li->li_tv;
2712 }
2713 }
2714 else if (argvars[0].v_type == VAR_DICT)
2715 {
2716 if ((d = argvars[0].vval.v_dict) != NULL)
2717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002718 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719 if (di != NULL)
2720 tv = &di->di_tv;
2721 }
2722 }
2723 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2724 {
2725 partial_T *pt;
2726 partial_T fref_pt;
2727
2728 if (argvars[0].v_type == VAR_PARTIAL)
2729 pt = argvars[0].vval.v_partial;
2730 else
2731 {
2732 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2733 fref_pt.pt_name = argvars[0].vval.v_string;
2734 pt = &fref_pt;
2735 }
2736
2737 if (pt != NULL)
2738 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002739 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002740 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002741
2742 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2743 {
2744 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002745 n = partial_name(pt);
2746 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002747 rettv->vval.v_string = NULL;
2748 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002749 {
2750 rettv->vval.v_string = vim_strsave(n);
2751 if (rettv->v_type == VAR_FUNC)
2752 func_ref(rettv->vval.v_string);
2753 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002754 }
2755 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002756 {
2757 what_is_dict = TRUE;
2758 if (pt->pt_dict != NULL)
2759 rettv_dict_set(rettv, pt->pt_dict);
2760 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002761 else if (STRCMP(what, "args") == 0)
2762 {
2763 rettv->v_type = VAR_LIST;
2764 if (rettv_list_alloc(rettv) == OK)
2765 {
2766 int i;
2767
2768 for (i = 0; i < pt->pt_argc; ++i)
2769 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2770 }
2771 }
2772 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002773 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002774
2775 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2776 // third argument
2777 if (!what_is_dict)
2778 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002779 }
2780 }
2781 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002782 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002783
2784 if (tv == NULL)
2785 {
2786 if (argvars[2].v_type != VAR_UNKNOWN)
2787 copy_tv(&argvars[2], rettv);
2788 }
2789 else
2790 copy_tv(tv, rettv);
2791}
2792
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002793/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002794 * "getchangelist()" function
2795 */
2796 static void
2797f_getchangelist(typval_T *argvars, typval_T *rettv)
2798{
2799#ifdef FEAT_JUMPLIST
2800 buf_T *buf;
2801 int i;
2802 list_T *l;
2803 dict_T *d;
2804#endif
2805
2806 if (rettv_list_alloc(rettv) != OK)
2807 return;
2808
2809#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002810 if (argvars[0].v_type == VAR_UNKNOWN)
2811 buf = curbuf;
2812 else
2813 {
2814 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2815 ++emsg_off;
2816 buf = tv_get_buf(&argvars[0], FALSE);
2817 --emsg_off;
2818 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002819 if (buf == NULL)
2820 return;
2821
2822 l = list_alloc();
2823 if (l == NULL)
2824 return;
2825
2826 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2827 return;
2828 /*
2829 * The current window change list index tracks only the position in the
2830 * current buffer change list. For other buffers, use the change list
2831 * length as the current index.
2832 */
2833 list_append_number(rettv->vval.v_list,
2834 (varnumber_T)((buf == curwin->w_buffer)
2835 ? curwin->w_changelistidx : buf->b_changelistlen));
2836
2837 for (i = 0; i < buf->b_changelistlen; ++i)
2838 {
2839 if (buf->b_changelist[i].lnum == 0)
2840 continue;
2841 if ((d = dict_alloc()) == NULL)
2842 return;
2843 if (list_append_dict(l, d) == FAIL)
2844 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002845 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2846 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002847 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002848 }
2849#endif
2850}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002851
2852/*
2853 * "getcharsearch()" function
2854 */
2855 static void
2856f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2857{
2858 if (rettv_dict_alloc(rettv) != FAIL)
2859 {
2860 dict_T *dict = rettv->vval.v_dict;
2861
Bram Moolenaare0be1672018-07-08 16:50:37 +02002862 dict_add_string(dict, "char", last_csearch());
2863 dict_add_number(dict, "forward", last_csearch_forward());
2864 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002865 }
2866}
2867
2868/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869 * "getcmdwintype()" function
2870 */
2871 static void
2872f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2873{
2874 rettv->v_type = VAR_STRING;
2875 rettv->vval.v_string = NULL;
2876#ifdef FEAT_CMDWIN
2877 rettv->vval.v_string = alloc(2);
2878 if (rettv->vval.v_string != NULL)
2879 {
2880 rettv->vval.v_string[0] = cmdwin_type;
2881 rettv->vval.v_string[1] = NUL;
2882 }
2883#endif
2884}
2885
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002886/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002887 * "getenv()" function
2888 */
2889 static void
2890f_getenv(typval_T *argvars, typval_T *rettv)
2891{
2892 int mustfree = FALSE;
2893 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2894
2895 if (p == NULL)
2896 {
2897 rettv->v_type = VAR_SPECIAL;
2898 rettv->vval.v_number = VVAL_NULL;
2899 return;
2900 }
2901 if (!mustfree)
2902 p = vim_strsave(p);
2903 rettv->vval.v_string = p;
2904 rettv->v_type = VAR_STRING;
2905}
2906
2907/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002908 * "getfontname()" function
2909 */
2910 static void
2911f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2912{
2913 rettv->v_type = VAR_STRING;
2914 rettv->vval.v_string = NULL;
2915#ifdef FEAT_GUI
2916 if (gui.in_use)
2917 {
2918 GuiFont font;
2919 char_u *name = NULL;
2920
2921 if (argvars[0].v_type == VAR_UNKNOWN)
2922 {
2923 /* Get the "Normal" font. Either the name saved by
2924 * hl_set_font_name() or from the font ID. */
2925 font = gui.norm_font;
2926 name = hl_get_font_name();
2927 }
2928 else
2929 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002930 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002931 if (STRCMP(name, "*") == 0) /* don't use font dialog */
2932 return;
2933 font = gui_mch_get_font(name, FALSE);
2934 if (font == NOFONT)
2935 return; /* Invalid font name, return empty string. */
2936 }
2937 rettv->vval.v_string = gui_mch_get_fontname(font, name);
2938 if (argvars[0].v_type != VAR_UNKNOWN)
2939 gui_mch_free_font(font);
2940 }
2941#endif
2942}
2943
2944/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01002945 * "getjumplist()" function
2946 */
2947 static void
2948f_getjumplist(typval_T *argvars, typval_T *rettv)
2949{
2950#ifdef FEAT_JUMPLIST
2951 win_T *wp;
2952 int i;
2953 list_T *l;
2954 dict_T *d;
2955#endif
2956
2957 if (rettv_list_alloc(rettv) != OK)
2958 return;
2959
2960#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02002961 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002962 if (wp == NULL)
2963 return;
2964
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01002965 cleanup_jumplist(wp, TRUE);
2966
Bram Moolenaar4f505882018-02-10 21:06:32 +01002967 l = list_alloc();
2968 if (l == NULL)
2969 return;
2970
2971 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2972 return;
2973 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
2974
2975 for (i = 0; i < wp->w_jumplistlen; ++i)
2976 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002977 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
2978 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01002979 if ((d = dict_alloc()) == NULL)
2980 return;
2981 if (list_append_dict(l, d) == FAIL)
2982 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002983 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
2984 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002985 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002986 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002987 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02002988 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002989 }
2990#endif
2991}
2992
2993/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002994 * "getpid()" function
2995 */
2996 static void
2997f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
2998{
2999 rettv->vval.v_number = mch_get_pid();
3000}
3001
3002 static void
3003getpos_both(
3004 typval_T *argvars,
3005 typval_T *rettv,
3006 int getcurpos)
3007{
3008 pos_T *fp;
3009 list_T *l;
3010 int fnum = -1;
3011
3012 if (rettv_list_alloc(rettv) == OK)
3013 {
3014 l = rettv->vval.v_list;
3015 if (getcurpos)
3016 fp = &curwin->w_cursor;
3017 else
3018 fp = var2fpos(&argvars[0], TRUE, &fnum);
3019 if (fnum != -1)
3020 list_append_number(l, (varnumber_T)fnum);
3021 else
3022 list_append_number(l, (varnumber_T)0);
3023 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3024 : (varnumber_T)0);
3025 list_append_number(l, (fp != NULL)
3026 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3027 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003028 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003029 (varnumber_T)0);
3030 if (getcurpos)
3031 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003032 int save_set_curswant = curwin->w_set_curswant;
3033 colnr_T save_curswant = curwin->w_curswant;
3034 colnr_T save_virtcol = curwin->w_virtcol;
3035
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 update_curswant();
3037 list_append_number(l, curwin->w_curswant == MAXCOL ?
3038 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003039
3040 // Do not change "curswant", as it is unexpected that a get
3041 // function has a side effect.
3042 if (save_set_curswant)
3043 {
3044 curwin->w_set_curswant = save_set_curswant;
3045 curwin->w_curswant = save_curswant;
3046 curwin->w_virtcol = save_virtcol;
3047 curwin->w_valid &= ~VALID_VIRTCOL;
3048 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003049 }
3050 }
3051 else
3052 rettv->vval.v_number = FALSE;
3053}
3054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003055/*
3056 * "getcurpos()" function
3057 */
3058 static void
3059f_getcurpos(typval_T *argvars, typval_T *rettv)
3060{
3061 getpos_both(argvars, rettv, TRUE);
3062}
3063
3064/*
3065 * "getpos(string)" function
3066 */
3067 static void
3068f_getpos(typval_T *argvars, typval_T *rettv)
3069{
3070 getpos_both(argvars, rettv, FALSE);
3071}
3072
3073/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003074 * "getreg()" function
3075 */
3076 static void
3077f_getreg(typval_T *argvars, typval_T *rettv)
3078{
3079 char_u *strregname;
3080 int regname;
3081 int arg2 = FALSE;
3082 int return_list = FALSE;
3083 int error = FALSE;
3084
3085 if (argvars[0].v_type != VAR_UNKNOWN)
3086 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003087 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003088 error = strregname == NULL;
3089 if (argvars[1].v_type != VAR_UNKNOWN)
3090 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003091 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003092 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003093 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003094 }
3095 }
3096 else
3097 strregname = get_vim_var_str(VV_REG);
3098
3099 if (error)
3100 return;
3101
3102 regname = (strregname == NULL ? '"' : *strregname);
3103 if (regname == 0)
3104 regname = '"';
3105
3106 if (return_list)
3107 {
3108 rettv->v_type = VAR_LIST;
3109 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3110 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3111 if (rettv->vval.v_list == NULL)
3112 (void)rettv_list_alloc(rettv);
3113 else
3114 ++rettv->vval.v_list->lv_refcount;
3115 }
3116 else
3117 {
3118 rettv->v_type = VAR_STRING;
3119 rettv->vval.v_string = get_reg_contents(regname,
3120 arg2 ? GREG_EXPR_SRC : 0);
3121 }
3122}
3123
3124/*
3125 * "getregtype()" function
3126 */
3127 static void
3128f_getregtype(typval_T *argvars, typval_T *rettv)
3129{
3130 char_u *strregname;
3131 int regname;
3132 char_u buf[NUMBUFLEN + 2];
3133 long reglen = 0;
3134
3135 if (argvars[0].v_type != VAR_UNKNOWN)
3136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003137 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003138 if (strregname == NULL) /* type error; errmsg already given */
3139 {
3140 rettv->v_type = VAR_STRING;
3141 rettv->vval.v_string = NULL;
3142 return;
3143 }
3144 }
3145 else
3146 /* Default to v:register */
3147 strregname = get_vim_var_str(VV_REG);
3148
3149 regname = (strregname == NULL ? '"' : *strregname);
3150 if (regname == 0)
3151 regname = '"';
3152
3153 buf[0] = NUL;
3154 buf[1] = NUL;
3155 switch (get_reg_type(regname, &reglen))
3156 {
3157 case MLINE: buf[0] = 'V'; break;
3158 case MCHAR: buf[0] = 'v'; break;
3159 case MBLOCK:
3160 buf[0] = Ctrl_V;
3161 sprintf((char *)buf + 1, "%ld", reglen + 1);
3162 break;
3163 }
3164 rettv->v_type = VAR_STRING;
3165 rettv->vval.v_string = vim_strsave(buf);
3166}
3167
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003168/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003169 * "gettagstack()" function
3170 */
3171 static void
3172f_gettagstack(typval_T *argvars, typval_T *rettv)
3173{
3174 win_T *wp = curwin; // default is current window
3175
3176 if (rettv_dict_alloc(rettv) != OK)
3177 return;
3178
3179 if (argvars[0].v_type != VAR_UNKNOWN)
3180 {
3181 wp = find_win_by_nr_or_id(&argvars[0]);
3182 if (wp == NULL)
3183 return;
3184 }
3185
3186 get_tagstack(wp, rettv->vval.v_dict);
3187}
3188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003189/* for VIM_VERSION_ defines */
3190#include "version.h"
3191
3192/*
3193 * "has()" function
3194 */
3195 static void
3196f_has(typval_T *argvars, typval_T *rettv)
3197{
3198 int i;
3199 char_u *name;
3200 int n = FALSE;
3201 static char *(has_list[]) =
3202 {
3203#ifdef AMIGA
3204 "amiga",
3205# ifdef FEAT_ARP
3206 "arp",
3207# endif
3208#endif
3209#ifdef __BEOS__
3210 "beos",
3211#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003212#if defined(BSD) && !defined(MACOS_X)
3213 "bsd",
3214#endif
3215#ifdef hpux
3216 "hpux",
3217#endif
3218#ifdef __linux__
3219 "linux",
3220#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003221#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003222 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3223 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003224# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003225 "macunix", /* Mac OS X, with the darwin feature */
3226 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003227# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003228#endif
3229#ifdef __QNX__
3230 "qnx",
3231#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003232#ifdef SUN_SYSTEM
3233 "sun",
3234#else
3235 "moon",
3236#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003237#ifdef UNIX
3238 "unix",
3239#endif
3240#ifdef VMS
3241 "vms",
3242#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003243#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003244 "win32",
3245#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003246#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003247 "win32unix",
3248#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003249#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003250 "win64",
3251#endif
3252#ifdef EBCDIC
3253 "ebcdic",
3254#endif
3255#ifndef CASE_INSENSITIVE_FILENAME
3256 "fname_case",
3257#endif
3258#ifdef HAVE_ACL
3259 "acl",
3260#endif
3261#ifdef FEAT_ARABIC
3262 "arabic",
3263#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003264 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003265#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003266 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003267#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003268#ifdef FEAT_AUTOSERVERNAME
3269 "autoservername",
3270#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003271#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003272 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003273# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003274 "balloon_multiline",
3275# endif
3276#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003277#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003278 "balloon_eval_term",
3279#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003280#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3281 "builtin_terms",
3282# ifdef ALL_BUILTIN_TCAPS
3283 "all_builtin_terms",
3284# endif
3285#endif
3286#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003287 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003288 || defined(FEAT_GUI_MOTIF))
3289 "browsefilter",
3290#endif
3291#ifdef FEAT_BYTEOFF
3292 "byte_offset",
3293#endif
3294#ifdef FEAT_JOB_CHANNEL
3295 "channel",
3296#endif
3297#ifdef FEAT_CINDENT
3298 "cindent",
3299#endif
3300#ifdef FEAT_CLIENTSERVER
3301 "clientserver",
3302#endif
3303#ifdef FEAT_CLIPBOARD
3304 "clipboard",
3305#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003306 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003307 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003309#ifdef FEAT_CONCEAL
3310 "conceal",
3311#endif
3312#ifdef FEAT_CRYPT
3313 "cryptv",
3314 "crypt-blowfish",
3315 "crypt-blowfish2",
3316#endif
3317#ifdef FEAT_CSCOPE
3318 "cscope",
3319#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003320 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003321#ifdef CURSOR_SHAPE
3322 "cursorshape",
3323#endif
3324#ifdef DEBUG
3325 "debug",
3326#endif
3327#ifdef FEAT_CON_DIALOG
3328 "dialog_con",
3329#endif
3330#ifdef FEAT_GUI_DIALOG
3331 "dialog_gui",
3332#endif
3333#ifdef FEAT_DIFF
3334 "diff",
3335#endif
3336#ifdef FEAT_DIGRAPHS
3337 "digraphs",
3338#endif
3339#ifdef FEAT_DIRECTX
3340 "directx",
3341#endif
3342#ifdef FEAT_DND
3343 "dnd",
3344#endif
3345#ifdef FEAT_EMACS_TAGS
3346 "emacs_tags",
3347#endif
3348 "eval", /* always present, of course! */
3349 "ex_extra", /* graduated feature */
3350#ifdef FEAT_SEARCH_EXTRA
3351 "extra_search",
3352#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003353#ifdef FEAT_SEARCHPATH
3354 "file_in_path",
3355#endif
3356#ifdef FEAT_FILTERPIPE
3357 "filterpipe",
3358#endif
3359#ifdef FEAT_FIND_ID
3360 "find_in_path",
3361#endif
3362#ifdef FEAT_FLOAT
3363 "float",
3364#endif
3365#ifdef FEAT_FOLDING
3366 "folding",
3367#endif
3368#ifdef FEAT_FOOTER
3369 "footer",
3370#endif
3371#if !defined(USE_SYSTEM) && defined(UNIX)
3372 "fork",
3373#endif
3374#ifdef FEAT_GETTEXT
3375 "gettext",
3376#endif
3377#ifdef FEAT_GUI
3378 "gui",
3379#endif
3380#ifdef FEAT_GUI_ATHENA
3381# ifdef FEAT_GUI_NEXTAW
3382 "gui_neXtaw",
3383# else
3384 "gui_athena",
3385# endif
3386#endif
3387#ifdef FEAT_GUI_GTK
3388 "gui_gtk",
3389# ifdef USE_GTK3
3390 "gui_gtk3",
3391# else
3392 "gui_gtk2",
3393# endif
3394#endif
3395#ifdef FEAT_GUI_GNOME
3396 "gui_gnome",
3397#endif
3398#ifdef FEAT_GUI_MAC
3399 "gui_mac",
3400#endif
3401#ifdef FEAT_GUI_MOTIF
3402 "gui_motif",
3403#endif
3404#ifdef FEAT_GUI_PHOTON
3405 "gui_photon",
3406#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003407#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003408 "gui_win32",
3409#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003410#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3411 "iconv",
3412#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003413 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414#ifdef FEAT_JOB_CHANNEL
3415 "job",
3416#endif
3417#ifdef FEAT_JUMPLIST
3418 "jumplist",
3419#endif
3420#ifdef FEAT_KEYMAP
3421 "keymap",
3422#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003423 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003424#ifdef FEAT_LANGMAP
3425 "langmap",
3426#endif
3427#ifdef FEAT_LIBCALL
3428 "libcall",
3429#endif
3430#ifdef FEAT_LINEBREAK
3431 "linebreak",
3432#endif
3433#ifdef FEAT_LISP
3434 "lispindent",
3435#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003437 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003438#ifdef FEAT_LUA
3439# ifndef DYNAMIC_LUA
3440 "lua",
3441# endif
3442#endif
3443#ifdef FEAT_MENU
3444 "menu",
3445#endif
3446#ifdef FEAT_SESSION
3447 "mksession",
3448#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003449 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003450 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003451#ifdef FEAT_MOUSESHAPE
3452 "mouseshape",
3453#endif
3454#if defined(UNIX) || defined(VMS)
3455# ifdef FEAT_MOUSE_DEC
3456 "mouse_dec",
3457# endif
3458# ifdef FEAT_MOUSE_GPM
3459 "mouse_gpm",
3460# endif
3461# ifdef FEAT_MOUSE_JSB
3462 "mouse_jsbterm",
3463# endif
3464# ifdef FEAT_MOUSE_NET
3465 "mouse_netterm",
3466# endif
3467# ifdef FEAT_MOUSE_PTERM
3468 "mouse_pterm",
3469# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003470# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471 "mouse_sgr",
3472# endif
3473# ifdef FEAT_SYSMOUSE
3474 "mouse_sysmouse",
3475# endif
3476# ifdef FEAT_MOUSE_URXVT
3477 "mouse_urxvt",
3478# endif
3479# ifdef FEAT_MOUSE_XTERM
3480 "mouse_xterm",
3481# endif
3482#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003484#ifdef FEAT_MBYTE_IME
3485 "multi_byte_ime",
3486#endif
3487#ifdef FEAT_MULTI_LANG
3488 "multi_lang",
3489#endif
3490#ifdef FEAT_MZSCHEME
3491#ifndef DYNAMIC_MZSCHEME
3492 "mzscheme",
3493#endif
3494#endif
3495#ifdef FEAT_NUM64
3496 "num64",
3497#endif
3498#ifdef FEAT_OLE
3499 "ole",
3500#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003501#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003502 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003503#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003504#ifdef FEAT_PATH_EXTRA
3505 "path_extra",
3506#endif
3507#ifdef FEAT_PERL
3508#ifndef DYNAMIC_PERL
3509 "perl",
3510#endif
3511#endif
3512#ifdef FEAT_PERSISTENT_UNDO
3513 "persistent_undo",
3514#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003515#if defined(FEAT_PYTHON)
3516 "python_compiled",
3517# if defined(DYNAMIC_PYTHON)
3518 "python_dynamic",
3519# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003521 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003522# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003523#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003524#if defined(FEAT_PYTHON3)
3525 "python3_compiled",
3526# if defined(DYNAMIC_PYTHON3)
3527 "python3_dynamic",
3528# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003529 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003530 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003531# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003532#endif
3533#ifdef FEAT_POSTSCRIPT
3534 "postscript",
3535#endif
3536#ifdef FEAT_PRINTER
3537 "printer",
3538#endif
3539#ifdef FEAT_PROFILE
3540 "profile",
3541#endif
3542#ifdef FEAT_RELTIME
3543 "reltime",
3544#endif
3545#ifdef FEAT_QUICKFIX
3546 "quickfix",
3547#endif
3548#ifdef FEAT_RIGHTLEFT
3549 "rightleft",
3550#endif
3551#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3552 "ruby",
3553#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003554 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003555#ifdef FEAT_CMDL_INFO
3556 "showcmd",
3557 "cmdline_info",
3558#endif
3559#ifdef FEAT_SIGNS
3560 "signs",
3561#endif
3562#ifdef FEAT_SMARTINDENT
3563 "smartindent",
3564#endif
3565#ifdef STARTUPTIME
3566 "startuptime",
3567#endif
3568#ifdef FEAT_STL_OPT
3569 "statusline",
3570#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003571#ifdef FEAT_NETBEANS_INTG
3572 "netbeans_intg",
3573#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003574#ifdef FEAT_SOUND
3575 "sound",
3576#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003577#ifdef FEAT_SPELL
3578 "spell",
3579#endif
3580#ifdef FEAT_SYN_HL
3581 "syntax",
3582#endif
3583#if defined(USE_SYSTEM) || !defined(UNIX)
3584 "system",
3585#endif
3586#ifdef FEAT_TAG_BINS
3587 "tag_binary",
3588#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003589#ifdef FEAT_TCL
3590# ifndef DYNAMIC_TCL
3591 "tcl",
3592# endif
3593#endif
3594#ifdef FEAT_TERMGUICOLORS
3595 "termguicolors",
3596#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003597#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003598 "terminal",
3599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600#ifdef TERMINFO
3601 "terminfo",
3602#endif
3603#ifdef FEAT_TERMRESPONSE
3604 "termresponse",
3605#endif
3606#ifdef FEAT_TEXTOBJ
3607 "textobjects",
3608#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003609#ifdef FEAT_TEXT_PROP
3610 "textprop",
3611#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003612#ifdef HAVE_TGETENT
3613 "tgetent",
3614#endif
3615#ifdef FEAT_TIMERS
3616 "timers",
3617#endif
3618#ifdef FEAT_TITLE
3619 "title",
3620#endif
3621#ifdef FEAT_TOOLBAR
3622 "toolbar",
3623#endif
3624#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3625 "unnamedplus",
3626#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003627 "user-commands", /* was accidentally included in 5.4 */
3628 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003629#ifdef FEAT_VARTABS
3630 "vartabs",
3631#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003632 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003633#ifdef FEAT_VIMINFO
3634 "viminfo",
3635#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003636 "vimscript-1",
3637 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003638 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003639 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003640 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003641 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003642 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003644#ifdef FEAT_VTP
3645 "vtp",
3646#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647#ifdef FEAT_WILDIGN
3648 "wildignore",
3649#endif
3650#ifdef FEAT_WILDMENU
3651 "wildmenu",
3652#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003653 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654#ifdef FEAT_WAK
3655 "winaltkeys",
3656#endif
3657#ifdef FEAT_WRITEBACKUP
3658 "writebackup",
3659#endif
3660#ifdef FEAT_XIM
3661 "xim",
3662#endif
3663#ifdef FEAT_XFONTSET
3664 "xfontset",
3665#endif
3666#ifdef FEAT_XPM_W32
3667 "xpm",
3668 "xpm_w32", /* for backward compatibility */
3669#else
3670# if defined(HAVE_XPM)
3671 "xpm",
3672# endif
3673#endif
3674#ifdef USE_XSMP
3675 "xsmp",
3676#endif
3677#ifdef USE_XSMP_INTERACT
3678 "xsmp_interact",
3679#endif
3680#ifdef FEAT_XCLIPBOARD
3681 "xterm_clipboard",
3682#endif
3683#ifdef FEAT_XTERM_SAVE
3684 "xterm_save",
3685#endif
3686#if defined(UNIX) && defined(FEAT_X11)
3687 "X11",
3688#endif
3689 NULL
3690 };
3691
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003692 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003693 for (i = 0; has_list[i] != NULL; ++i)
3694 if (STRICMP(name, has_list[i]) == 0)
3695 {
3696 n = TRUE;
3697 break;
3698 }
3699
3700 if (n == FALSE)
3701 {
3702 if (STRNICMP(name, "patch", 5) == 0)
3703 {
3704 if (name[5] == '-'
3705 && STRLEN(name) >= 11
3706 && vim_isdigit(name[6])
3707 && vim_isdigit(name[8])
3708 && vim_isdigit(name[10]))
3709 {
3710 int major = atoi((char *)name + 6);
3711 int minor = atoi((char *)name + 8);
3712
3713 /* Expect "patch-9.9.01234". */
3714 n = (major < VIM_VERSION_MAJOR
3715 || (major == VIM_VERSION_MAJOR
3716 && (minor < VIM_VERSION_MINOR
3717 || (minor == VIM_VERSION_MINOR
3718 && has_patch(atoi((char *)name + 10))))));
3719 }
3720 else
3721 n = has_patch(atoi((char *)name + 5));
3722 }
3723 else if (STRICMP(name, "vim_starting") == 0)
3724 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003725 else if (STRICMP(name, "ttyin") == 0)
3726 n = mch_input_isatty();
3727 else if (STRICMP(name, "ttyout") == 0)
3728 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003729 else if (STRICMP(name, "multi_byte_encoding") == 0)
3730 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003731#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003732 else if (STRICMP(name, "balloon_multiline") == 0)
3733 n = multiline_balloon_available();
3734#endif
3735#ifdef DYNAMIC_TCL
3736 else if (STRICMP(name, "tcl") == 0)
3737 n = tcl_enabled(FALSE);
3738#endif
3739#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3740 else if (STRICMP(name, "iconv") == 0)
3741 n = iconv_enabled(FALSE);
3742#endif
3743#ifdef DYNAMIC_LUA
3744 else if (STRICMP(name, "lua") == 0)
3745 n = lua_enabled(FALSE);
3746#endif
3747#ifdef DYNAMIC_MZSCHEME
3748 else if (STRICMP(name, "mzscheme") == 0)
3749 n = mzscheme_enabled(FALSE);
3750#endif
3751#ifdef DYNAMIC_RUBY
3752 else if (STRICMP(name, "ruby") == 0)
3753 n = ruby_enabled(FALSE);
3754#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003755#ifdef DYNAMIC_PYTHON
3756 else if (STRICMP(name, "python") == 0)
3757 n = python_enabled(FALSE);
3758#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003759#ifdef DYNAMIC_PYTHON3
3760 else if (STRICMP(name, "python3") == 0)
3761 n = python3_enabled(FALSE);
3762#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003763#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3764 else if (STRICMP(name, "pythonx") == 0)
3765 {
3766# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3767 if (p_pyx == 0)
3768 n = python3_enabled(FALSE) || python_enabled(FALSE);
3769 else if (p_pyx == 3)
3770 n = python3_enabled(FALSE);
3771 else if (p_pyx == 2)
3772 n = python_enabled(FALSE);
3773# elif defined(DYNAMIC_PYTHON)
3774 n = python_enabled(FALSE);
3775# elif defined(DYNAMIC_PYTHON3)
3776 n = python3_enabled(FALSE);
3777# endif
3778 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003779#endif
3780#ifdef DYNAMIC_PERL
3781 else if (STRICMP(name, "perl") == 0)
3782 n = perl_enabled(FALSE);
3783#endif
3784#ifdef FEAT_GUI
3785 else if (STRICMP(name, "gui_running") == 0)
3786 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003787# ifdef FEAT_BROWSE
3788 else if (STRICMP(name, "browse") == 0)
3789 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3790# endif
3791#endif
3792#ifdef FEAT_SYN_HL
3793 else if (STRICMP(name, "syntax_items") == 0)
3794 n = syntax_present(curwin);
3795#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003796#ifdef FEAT_VTP
3797 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003798 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003799#endif
3800#ifdef FEAT_NETBEANS_INTG
3801 else if (STRICMP(name, "netbeans_enabled") == 0)
3802 n = netbeans_active();
3803#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003804#ifdef FEAT_MOUSE_GPM
3805 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3806 n = gpm_enabled();
3807#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003808#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003809 else if (STRICMP(name, "terminal") == 0)
3810 n = terminal_enabled();
3811#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003812#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003813 else if (STRICMP(name, "conpty") == 0)
3814 n = use_conpty();
3815#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003816#ifdef FEAT_CLIPBOARD
3817 else if (STRICMP(name, "clipboard_working") == 0)
3818 n = clip_star.available;
3819#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003820 }
3821
3822 rettv->vval.v_number = n;
3823}
3824
3825/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826 * "haslocaldir()" function
3827 */
3828 static void
3829f_haslocaldir(typval_T *argvars, typval_T *rettv)
3830{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003831 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003832 win_T *wp = NULL;
3833
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003834 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3835
3836 // Check for window-local and tab-local directories
3837 if (wp != NULL && wp->w_localdir != NULL)
3838 rettv->vval.v_number = 1;
3839 else if (tp != NULL && tp->tp_localdir != NULL)
3840 rettv->vval.v_number = 2;
3841 else
3842 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003843}
3844
3845/*
3846 * "hasmapto()" function
3847 */
3848 static void
3849f_hasmapto(typval_T *argvars, typval_T *rettv)
3850{
3851 char_u *name;
3852 char_u *mode;
3853 char_u buf[NUMBUFLEN];
3854 int abbr = FALSE;
3855
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003856 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003857 if (argvars[1].v_type == VAR_UNKNOWN)
3858 mode = (char_u *)"nvo";
3859 else
3860 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003861 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003862 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003863 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864 }
3865
3866 if (map_to_exists(name, mode, abbr))
3867 rettv->vval.v_number = TRUE;
3868 else
3869 rettv->vval.v_number = FALSE;
3870}
3871
3872/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003873 * "highlightID(name)" function
3874 */
3875 static void
3876f_hlID(typval_T *argvars, typval_T *rettv)
3877{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003878 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003879}
3880
3881/*
3882 * "highlight_exists()" function
3883 */
3884 static void
3885f_hlexists(typval_T *argvars, typval_T *rettv)
3886{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003887 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003888}
3889
3890/*
3891 * "hostname()" function
3892 */
3893 static void
3894f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3895{
3896 char_u hostname[256];
3897
3898 mch_get_host_name(hostname, 256);
3899 rettv->v_type = VAR_STRING;
3900 rettv->vval.v_string = vim_strsave(hostname);
3901}
3902
3903/*
3904 * iconv() function
3905 */
3906 static void
3907f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3908{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909 char_u buf1[NUMBUFLEN];
3910 char_u buf2[NUMBUFLEN];
3911 char_u *from, *to, *str;
3912 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003913
3914 rettv->v_type = VAR_STRING;
3915 rettv->vval.v_string = NULL;
3916
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003917 str = tv_get_string(&argvars[0]);
3918 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3919 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003920 vimconv.vc_type = CONV_NONE;
3921 convert_setup(&vimconv, from, to);
3922
3923 /* If the encodings are equal, no conversion needed. */
3924 if (vimconv.vc_type == CONV_NONE)
3925 rettv->vval.v_string = vim_strsave(str);
3926 else
3927 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
3928
3929 convert_setup(&vimconv, NULL, NULL);
3930 vim_free(from);
3931 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932}
3933
3934/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003935 * "index()" function
3936 */
3937 static void
3938f_index(typval_T *argvars, typval_T *rettv)
3939{
3940 list_T *l;
3941 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003942 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003943 long idx = 0;
3944 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003945 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003946
3947 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003948 if (argvars[0].v_type == VAR_BLOB)
3949 {
3950 typval_T tv;
3951 int start = 0;
3952
3953 if (argvars[2].v_type != VAR_UNKNOWN)
3954 {
3955 start = tv_get_number_chk(&argvars[2], &error);
3956 if (error)
3957 return;
3958 }
3959 b = argvars[0].vval.v_blob;
3960 if (b == NULL)
3961 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01003962 if (start < 0)
3963 {
3964 start = blob_len(b) + start;
3965 if (start < 0)
3966 start = 0;
3967 }
3968
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003969 for (idx = start; idx < blob_len(b); ++idx)
3970 {
3971 tv.v_type = VAR_NUMBER;
3972 tv.vval.v_number = blob_get(b, idx);
3973 if (tv_equal(&tv, &argvars[1], ic, FALSE))
3974 {
3975 rettv->vval.v_number = idx;
3976 return;
3977 }
3978 }
3979 return;
3980 }
3981 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003982 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003983 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984 return;
3985 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003986
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003987 l = argvars[0].vval.v_list;
3988 if (l != NULL)
3989 {
3990 item = l->lv_first;
3991 if (argvars[2].v_type != VAR_UNKNOWN)
3992 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003993 /* Start at specified item. Use the cached index that list_find()
3994 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003995 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003996 idx = l->lv_idx;
3997 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003998 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003999 if (error)
4000 item = NULL;
4001 }
4002
4003 for ( ; item != NULL; item = item->li_next, ++idx)
4004 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4005 {
4006 rettv->vval.v_number = idx;
4007 break;
4008 }
4009 }
4010}
4011
4012static int inputsecret_flag = 0;
4013
4014/*
4015 * "input()" function
4016 * Also handles inputsecret() when inputsecret is set.
4017 */
4018 static void
4019f_input(typval_T *argvars, typval_T *rettv)
4020{
4021 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4022}
4023
4024/*
4025 * "inputdialog()" function
4026 */
4027 static void
4028f_inputdialog(typval_T *argvars, typval_T *rettv)
4029{
4030#if defined(FEAT_GUI_TEXTDIALOG)
4031 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4032 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4033 {
4034 char_u *message;
4035 char_u buf[NUMBUFLEN];
4036 char_u *defstr = (char_u *)"";
4037
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004038 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004039 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004040 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004041 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4042 else
4043 IObuff[0] = NUL;
4044 if (message != NULL && defstr != NULL
4045 && do_dialog(VIM_QUESTION, NULL, message,
4046 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4047 rettv->vval.v_string = vim_strsave(IObuff);
4048 else
4049 {
4050 if (message != NULL && defstr != NULL
4051 && argvars[1].v_type != VAR_UNKNOWN
4052 && argvars[2].v_type != VAR_UNKNOWN)
4053 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004054 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004055 else
4056 rettv->vval.v_string = NULL;
4057 }
4058 rettv->v_type = VAR_STRING;
4059 }
4060 else
4061#endif
4062 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4063}
4064
4065/*
4066 * "inputlist()" function
4067 */
4068 static void
4069f_inputlist(typval_T *argvars, typval_T *rettv)
4070{
4071 listitem_T *li;
4072 int selected;
4073 int mouse_used;
4074
4075#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004076 /* While starting up, there is no place to enter text. When running tests
4077 * with --not-a-term we assume feedkeys() will be used. */
4078 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004079 return;
4080#endif
4081 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4082 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004083 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004084 return;
4085 }
4086
4087 msg_start();
4088 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4089 lines_left = Rows; /* avoid more prompt */
4090 msg_scroll = TRUE;
4091 msg_clr_eos();
4092
4093 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4094 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004095 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004096 msg_putchar('\n');
4097 }
4098
4099 /* Ask for choice. */
4100 selected = prompt_for_number(&mouse_used);
4101 if (mouse_used)
4102 selected -= lines_left;
4103
4104 rettv->vval.v_number = selected;
4105}
4106
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004107static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4108
4109/*
4110 * "inputrestore()" function
4111 */
4112 static void
4113f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4114{
4115 if (ga_userinput.ga_len > 0)
4116 {
4117 --ga_userinput.ga_len;
4118 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4119 + ga_userinput.ga_len);
4120 /* default return is zero == OK */
4121 }
4122 else if (p_verbose > 1)
4123 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004124 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004125 rettv->vval.v_number = 1; /* Failed */
4126 }
4127}
4128
4129/*
4130 * "inputsave()" function
4131 */
4132 static void
4133f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4134{
4135 /* Add an entry to the stack of typeahead storage. */
4136 if (ga_grow(&ga_userinput, 1) == OK)
4137 {
4138 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4139 + ga_userinput.ga_len);
4140 ++ga_userinput.ga_len;
4141 /* default return is zero == OK */
4142 }
4143 else
4144 rettv->vval.v_number = 1; /* Failed */
4145}
4146
4147/*
4148 * "inputsecret()" function
4149 */
4150 static void
4151f_inputsecret(typval_T *argvars, typval_T *rettv)
4152{
4153 ++cmdline_star;
4154 ++inputsecret_flag;
4155 f_input(argvars, rettv);
4156 --cmdline_star;
4157 --inputsecret_flag;
4158}
4159
4160/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004161 * "interrupt()" function
4162 */
4163 static void
4164f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4165{
4166 got_int = TRUE;
4167}
4168
4169/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004170 * "invert(expr)" function
4171 */
4172 static void
4173f_invert(typval_T *argvars, typval_T *rettv)
4174{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004175 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004176}
4177
4178/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004179 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4180 * or it refers to a List or Dictionary that is locked.
4181 */
4182 static int
4183tv_islocked(typval_T *tv)
4184{
4185 return (tv->v_lock & VAR_LOCKED)
4186 || (tv->v_type == VAR_LIST
4187 && tv->vval.v_list != NULL
4188 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4189 || (tv->v_type == VAR_DICT
4190 && tv->vval.v_dict != NULL
4191 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4192}
4193
4194/*
4195 * "islocked()" function
4196 */
4197 static void
4198f_islocked(typval_T *argvars, typval_T *rettv)
4199{
4200 lval_T lv;
4201 char_u *end;
4202 dictitem_T *di;
4203
4204 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004205 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004206 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004207 if (end != NULL && lv.ll_name != NULL)
4208 {
4209 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004210 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004211 else
4212 {
4213 if (lv.ll_tv == NULL)
4214 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004215 di = find_var(lv.ll_name, NULL, TRUE);
4216 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004217 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004218 /* Consider a variable locked when:
4219 * 1. the variable itself is locked
4220 * 2. the value of the variable is locked.
4221 * 3. the List or Dict value is locked.
4222 */
4223 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4224 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004225 }
4226 }
4227 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004228 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004229 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004230 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004231 else if (lv.ll_list != NULL)
4232 /* List item. */
4233 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4234 else
4235 /* Dictionary item. */
4236 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4237 }
4238 }
4239
4240 clear_lval(&lv);
4241}
4242
4243#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4244/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004245 * "isinf()" function
4246 */
4247 static void
4248f_isinf(typval_T *argvars, typval_T *rettv)
4249{
4250 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4251 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4252}
4253
4254/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255 * "isnan()" function
4256 */
4257 static void
4258f_isnan(typval_T *argvars, typval_T *rettv)
4259{
4260 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4261 && isnan(argvars[0].vval.v_float);
4262}
4263#endif
4264
4265/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004266 * "last_buffer_nr()" function.
4267 */
4268 static void
4269f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4270{
4271 int n = 0;
4272 buf_T *buf;
4273
Bram Moolenaar29323592016-07-24 22:04:11 +02004274 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004275 if (n < buf->b_fnum)
4276 n = buf->b_fnum;
4277
4278 rettv->vval.v_number = n;
4279}
4280
4281/*
4282 * "len()" function
4283 */
4284 static void
4285f_len(typval_T *argvars, typval_T *rettv)
4286{
4287 switch (argvars[0].v_type)
4288 {
4289 case VAR_STRING:
4290 case VAR_NUMBER:
4291 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004292 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004293 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004294 case VAR_BLOB:
4295 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4296 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004297 case VAR_LIST:
4298 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4299 break;
4300 case VAR_DICT:
4301 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4302 break;
4303 case VAR_UNKNOWN:
4304 case VAR_SPECIAL:
4305 case VAR_FLOAT:
4306 case VAR_FUNC:
4307 case VAR_PARTIAL:
4308 case VAR_JOB:
4309 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004310 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004311 break;
4312 }
4313}
4314
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004315 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004316libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004317{
4318#ifdef FEAT_LIBCALL
4319 char_u *string_in;
4320 char_u **string_result;
4321 int nr_result;
4322#endif
4323
4324 rettv->v_type = type;
4325 if (type != VAR_NUMBER)
4326 rettv->vval.v_string = NULL;
4327
4328 if (check_restricted() || check_secure())
4329 return;
4330
4331#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004332 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004333 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4334 {
4335 string_in = NULL;
4336 if (argvars[2].v_type == VAR_STRING)
4337 string_in = argvars[2].vval.v_string;
4338 if (type == VAR_NUMBER)
4339 string_result = NULL;
4340 else
4341 string_result = &rettv->vval.v_string;
4342 if (mch_libcall(argvars[0].vval.v_string,
4343 argvars[1].vval.v_string,
4344 string_in,
4345 argvars[2].vval.v_number,
4346 string_result,
4347 &nr_result) == OK
4348 && type == VAR_NUMBER)
4349 rettv->vval.v_number = nr_result;
4350 }
4351#endif
4352}
4353
4354/*
4355 * "libcall()" function
4356 */
4357 static void
4358f_libcall(typval_T *argvars, typval_T *rettv)
4359{
4360 libcall_common(argvars, rettv, VAR_STRING);
4361}
4362
4363/*
4364 * "libcallnr()" function
4365 */
4366 static void
4367f_libcallnr(typval_T *argvars, typval_T *rettv)
4368{
4369 libcall_common(argvars, rettv, VAR_NUMBER);
4370}
4371
4372/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004373 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004374 */
4375 static void
4376f_line(typval_T *argvars, typval_T *rettv)
4377{
4378 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004379 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004380 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004381 int id;
4382 tabpage_T *tp;
4383 win_T *wp;
4384 win_T *save_curwin;
4385 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004386
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004387 if (argvars[1].v_type != VAR_UNKNOWN)
4388 {
4389 // use window specified in the second argument
4390 id = (int)tv_get_number(&argvars[1]);
4391 wp = win_id2wp_tp(id, &tp);
4392 if (wp != NULL && tp != NULL)
4393 {
4394 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4395 == OK)
4396 {
4397 check_cursor();
4398 fp = var2fpos(&argvars[0], TRUE, &fnum);
4399 }
4400 restore_win_noblock(save_curwin, save_curtab, TRUE);
4401 }
4402 }
4403 else
4404 // use current window
4405 fp = var2fpos(&argvars[0], TRUE, &fnum);
4406
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004407 if (fp != NULL)
4408 lnum = fp->lnum;
4409 rettv->vval.v_number = lnum;
4410}
4411
4412/*
4413 * "line2byte(lnum)" function
4414 */
4415 static void
4416f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4417{
4418#ifndef FEAT_BYTEOFF
4419 rettv->vval.v_number = -1;
4420#else
4421 linenr_T lnum;
4422
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004423 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004424 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4425 rettv->vval.v_number = -1;
4426 else
4427 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4428 if (rettv->vval.v_number >= 0)
4429 ++rettv->vval.v_number;
4430#endif
4431}
4432
4433/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004434 * "localtime()" function
4435 */
4436 static void
4437f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4438{
4439 rettv->vval.v_number = (varnumber_T)time(NULL);
4440}
4441
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004442#ifdef FEAT_FLOAT
4443/*
4444 * "log()" function
4445 */
4446 static void
4447f_log(typval_T *argvars, typval_T *rettv)
4448{
4449 float_T f = 0.0;
4450
4451 rettv->v_type = VAR_FLOAT;
4452 if (get_float_arg(argvars, &f) == OK)
4453 rettv->vval.v_float = log(f);
4454 else
4455 rettv->vval.v_float = 0.0;
4456}
4457
4458/*
4459 * "log10()" function
4460 */
4461 static void
4462f_log10(typval_T *argvars, typval_T *rettv)
4463{
4464 float_T f = 0.0;
4465
4466 rettv->v_type = VAR_FLOAT;
4467 if (get_float_arg(argvars, &f) == OK)
4468 rettv->vval.v_float = log10(f);
4469 else
4470 rettv->vval.v_float = 0.0;
4471}
4472#endif
4473
4474#ifdef FEAT_LUA
4475/*
4476 * "luaeval()" function
4477 */
4478 static void
4479f_luaeval(typval_T *argvars, typval_T *rettv)
4480{
4481 char_u *str;
4482 char_u buf[NUMBUFLEN];
4483
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004484 if (check_restricted() || check_secure())
4485 return;
4486
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004487 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004488 do_luaeval(str, argvars + 1, rettv);
4489}
4490#endif
4491
4492/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004493 * "maparg()" function
4494 */
4495 static void
4496f_maparg(typval_T *argvars, typval_T *rettv)
4497{
4498 get_maparg(argvars, rettv, TRUE);
4499}
4500
4501/*
4502 * "mapcheck()" function
4503 */
4504 static void
4505f_mapcheck(typval_T *argvars, typval_T *rettv)
4506{
4507 get_maparg(argvars, rettv, FALSE);
4508}
4509
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004510typedef enum
4511{
4512 MATCH_END, /* matchend() */
4513 MATCH_MATCH, /* match() */
4514 MATCH_STR, /* matchstr() */
4515 MATCH_LIST, /* matchlist() */
4516 MATCH_POS /* matchstrpos() */
4517} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004518
4519 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004520find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004521{
4522 char_u *str = NULL;
4523 long len = 0;
4524 char_u *expr = NULL;
4525 char_u *pat;
4526 regmatch_T regmatch;
4527 char_u patbuf[NUMBUFLEN];
4528 char_u strbuf[NUMBUFLEN];
4529 char_u *save_cpo;
4530 long start = 0;
4531 long nth = 1;
4532 colnr_T startcol = 0;
4533 int match = 0;
4534 list_T *l = NULL;
4535 listitem_T *li = NULL;
4536 long idx = 0;
4537 char_u *tofree = NULL;
4538
4539 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4540 save_cpo = p_cpo;
4541 p_cpo = (char_u *)"";
4542
4543 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004544 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004545 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004546 /* type MATCH_LIST: return empty list when there are no matches.
4547 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004548 if (rettv_list_alloc(rettv) == FAIL)
4549 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004550 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004551 && (list_append_string(rettv->vval.v_list,
4552 (char_u *)"", 0) == FAIL
4553 || list_append_number(rettv->vval.v_list,
4554 (varnumber_T)-1) == FAIL
4555 || list_append_number(rettv->vval.v_list,
4556 (varnumber_T)-1) == FAIL
4557 || list_append_number(rettv->vval.v_list,
4558 (varnumber_T)-1) == FAIL))
4559 {
4560 list_free(rettv->vval.v_list);
4561 rettv->vval.v_list = NULL;
4562 goto theend;
4563 }
4564 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004565 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004566 {
4567 rettv->v_type = VAR_STRING;
4568 rettv->vval.v_string = NULL;
4569 }
4570
4571 if (argvars[0].v_type == VAR_LIST)
4572 {
4573 if ((l = argvars[0].vval.v_list) == NULL)
4574 goto theend;
4575 li = l->lv_first;
4576 }
4577 else
4578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004579 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004580 len = (long)STRLEN(str);
4581 }
4582
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004583 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004584 if (pat == NULL)
4585 goto theend;
4586
4587 if (argvars[2].v_type != VAR_UNKNOWN)
4588 {
4589 int error = FALSE;
4590
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004591 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004592 if (error)
4593 goto theend;
4594 if (l != NULL)
4595 {
4596 li = list_find(l, start);
4597 if (li == NULL)
4598 goto theend;
4599 idx = l->lv_idx; /* use the cached index */
4600 }
4601 else
4602 {
4603 if (start < 0)
4604 start = 0;
4605 if (start > len)
4606 goto theend;
4607 /* When "count" argument is there ignore matches before "start",
4608 * otherwise skip part of the string. Differs when pattern is "^"
4609 * or "\<". */
4610 if (argvars[3].v_type != VAR_UNKNOWN)
4611 startcol = start;
4612 else
4613 {
4614 str += start;
4615 len -= start;
4616 }
4617 }
4618
4619 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004620 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004621 if (error)
4622 goto theend;
4623 }
4624
4625 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4626 if (regmatch.regprog != NULL)
4627 {
4628 regmatch.rm_ic = p_ic;
4629
4630 for (;;)
4631 {
4632 if (l != NULL)
4633 {
4634 if (li == NULL)
4635 {
4636 match = FALSE;
4637 break;
4638 }
4639 vim_free(tofree);
4640 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4641 if (str == NULL)
4642 break;
4643 }
4644
4645 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4646
4647 if (match && --nth <= 0)
4648 break;
4649 if (l == NULL && !match)
4650 break;
4651
4652 /* Advance to just after the match. */
4653 if (l != NULL)
4654 {
4655 li = li->li_next;
4656 ++idx;
4657 }
4658 else
4659 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004660 startcol = (colnr_T)(regmatch.startp[0]
4661 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004662 if (startcol > (colnr_T)len
4663 || str + startcol <= regmatch.startp[0])
4664 {
4665 match = FALSE;
4666 break;
4667 }
4668 }
4669 }
4670
4671 if (match)
4672 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004673 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004674 {
4675 listitem_T *li1 = rettv->vval.v_list->lv_first;
4676 listitem_T *li2 = li1->li_next;
4677 listitem_T *li3 = li2->li_next;
4678 listitem_T *li4 = li3->li_next;
4679
4680 vim_free(li1->li_tv.vval.v_string);
4681 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4682 (int)(regmatch.endp[0] - regmatch.startp[0]));
4683 li3->li_tv.vval.v_number =
4684 (varnumber_T)(regmatch.startp[0] - expr);
4685 li4->li_tv.vval.v_number =
4686 (varnumber_T)(regmatch.endp[0] - expr);
4687 if (l != NULL)
4688 li2->li_tv.vval.v_number = (varnumber_T)idx;
4689 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004690 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004691 {
4692 int i;
4693
4694 /* return list with matched string and submatches */
4695 for (i = 0; i < NSUBEXP; ++i)
4696 {
4697 if (regmatch.endp[i] == NULL)
4698 {
4699 if (list_append_string(rettv->vval.v_list,
4700 (char_u *)"", 0) == FAIL)
4701 break;
4702 }
4703 else if (list_append_string(rettv->vval.v_list,
4704 regmatch.startp[i],
4705 (int)(regmatch.endp[i] - regmatch.startp[i]))
4706 == FAIL)
4707 break;
4708 }
4709 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004710 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004711 {
4712 /* return matched string */
4713 if (l != NULL)
4714 copy_tv(&li->li_tv, rettv);
4715 else
4716 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4717 (int)(regmatch.endp[0] - regmatch.startp[0]));
4718 }
4719 else if (l != NULL)
4720 rettv->vval.v_number = idx;
4721 else
4722 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004723 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004724 rettv->vval.v_number =
4725 (varnumber_T)(regmatch.startp[0] - str);
4726 else
4727 rettv->vval.v_number =
4728 (varnumber_T)(regmatch.endp[0] - str);
4729 rettv->vval.v_number += (varnumber_T)(str - expr);
4730 }
4731 }
4732 vim_regfree(regmatch.regprog);
4733 }
4734
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004735theend:
4736 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004737 /* matchstrpos() without a list: drop the second item. */
4738 listitem_remove(rettv->vval.v_list,
4739 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004740 vim_free(tofree);
4741 p_cpo = save_cpo;
4742}
4743
4744/*
4745 * "match()" function
4746 */
4747 static void
4748f_match(typval_T *argvars, typval_T *rettv)
4749{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004750 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004751}
4752
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004753/*
4754 * "matchend()" function
4755 */
4756 static void
4757f_matchend(typval_T *argvars, typval_T *rettv)
4758{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004759 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004760}
4761
4762/*
4763 * "matchlist()" function
4764 */
4765 static void
4766f_matchlist(typval_T *argvars, typval_T *rettv)
4767{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004768 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004769}
4770
4771/*
4772 * "matchstr()" function
4773 */
4774 static void
4775f_matchstr(typval_T *argvars, typval_T *rettv)
4776{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004777 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004778}
4779
4780/*
4781 * "matchstrpos()" function
4782 */
4783 static void
4784f_matchstrpos(typval_T *argvars, typval_T *rettv)
4785{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004786 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004787}
4788
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004789 static void
4790max_min(typval_T *argvars, typval_T *rettv, int domax)
4791{
4792 varnumber_T n = 0;
4793 varnumber_T i;
4794 int error = FALSE;
4795
4796 if (argvars[0].v_type == VAR_LIST)
4797 {
4798 list_T *l;
4799 listitem_T *li;
4800
4801 l = argvars[0].vval.v_list;
4802 if (l != NULL)
4803 {
4804 li = l->lv_first;
4805 if (li != NULL)
4806 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004807 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004808 for (;;)
4809 {
4810 li = li->li_next;
4811 if (li == NULL)
4812 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004813 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004814 if (domax ? i > n : i < n)
4815 n = i;
4816 }
4817 }
4818 }
4819 }
4820 else if (argvars[0].v_type == VAR_DICT)
4821 {
4822 dict_T *d;
4823 int first = TRUE;
4824 hashitem_T *hi;
4825 int todo;
4826
4827 d = argvars[0].vval.v_dict;
4828 if (d != NULL)
4829 {
4830 todo = (int)d->dv_hashtab.ht_used;
4831 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4832 {
4833 if (!HASHITEM_EMPTY(hi))
4834 {
4835 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004836 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004837 if (first)
4838 {
4839 n = i;
4840 first = FALSE;
4841 }
4842 else if (domax ? i > n : i < n)
4843 n = i;
4844 }
4845 }
4846 }
4847 }
4848 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004849 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850 rettv->vval.v_number = error ? 0 : n;
4851}
4852
4853/*
4854 * "max()" function
4855 */
4856 static void
4857f_max(typval_T *argvars, typval_T *rettv)
4858{
4859 max_min(argvars, rettv, TRUE);
4860}
4861
4862/*
4863 * "min()" function
4864 */
4865 static void
4866f_min(typval_T *argvars, typval_T *rettv)
4867{
4868 max_min(argvars, rettv, FALSE);
4869}
4870
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004871#if defined(FEAT_MZSCHEME) || defined(PROTO)
4872/*
4873 * "mzeval()" function
4874 */
4875 static void
4876f_mzeval(typval_T *argvars, typval_T *rettv)
4877{
4878 char_u *str;
4879 char_u buf[NUMBUFLEN];
4880
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004881 if (check_restricted() || check_secure())
4882 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004883 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004884 do_mzeval(str, rettv);
4885}
4886
4887 void
4888mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4889{
4890 typval_T argvars[3];
4891
4892 argvars[0].v_type = VAR_STRING;
4893 argvars[0].vval.v_string = name;
4894 copy_tv(args, &argvars[1]);
4895 argvars[2].v_type = VAR_UNKNOWN;
4896 f_call(argvars, rettv);
4897 clear_tv(&argvars[1]);
4898}
4899#endif
4900
4901/*
4902 * "nextnonblank()" function
4903 */
4904 static void
4905f_nextnonblank(typval_T *argvars, typval_T *rettv)
4906{
4907 linenr_T lnum;
4908
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004909 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004910 {
4911 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
4912 {
4913 lnum = 0;
4914 break;
4915 }
4916 if (*skipwhite(ml_get(lnum)) != NUL)
4917 break;
4918 }
4919 rettv->vval.v_number = lnum;
4920}
4921
4922/*
4923 * "nr2char()" function
4924 */
4925 static void
4926f_nr2char(typval_T *argvars, typval_T *rettv)
4927{
4928 char_u buf[NUMBUFLEN];
4929
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930 if (has_mbyte)
4931 {
4932 int utf8 = 0;
4933
4934 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004935 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004936 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01004937 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004938 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004939 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940 }
4941 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004943 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004944 buf[1] = NUL;
4945 }
4946 rettv->v_type = VAR_STRING;
4947 rettv->vval.v_string = vim_strsave(buf);
4948}
4949
4950/*
4951 * "or(expr, expr)" function
4952 */
4953 static void
4954f_or(typval_T *argvars, typval_T *rettv)
4955{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004956 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
4957 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004958}
4959
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004960#ifdef FEAT_PERL
4961/*
4962 * "perleval()" function
4963 */
4964 static void
4965f_perleval(typval_T *argvars, typval_T *rettv)
4966{
4967 char_u *str;
4968 char_u buf[NUMBUFLEN];
4969
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004970 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004971 do_perleval(str, rettv);
4972}
4973#endif
4974
4975#ifdef FEAT_FLOAT
4976/*
4977 * "pow()" function
4978 */
4979 static void
4980f_pow(typval_T *argvars, typval_T *rettv)
4981{
4982 float_T fx = 0.0, fy = 0.0;
4983
4984 rettv->v_type = VAR_FLOAT;
4985 if (get_float_arg(argvars, &fx) == OK
4986 && get_float_arg(&argvars[1], &fy) == OK)
4987 rettv->vval.v_float = pow(fx, fy);
4988 else
4989 rettv->vval.v_float = 0.0;
4990}
4991#endif
4992
4993/*
4994 * "prevnonblank()" function
4995 */
4996 static void
4997f_prevnonblank(typval_T *argvars, typval_T *rettv)
4998{
4999 linenr_T lnum;
5000
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005001 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005002 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5003 lnum = 0;
5004 else
5005 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5006 --lnum;
5007 rettv->vval.v_number = lnum;
5008}
5009
5010/* This dummy va_list is here because:
5011 * - passing a NULL pointer doesn't work when va_list isn't a pointer
5012 * - locally in the function results in a "used before set" warning
5013 * - using va_start() to initialize it gives "function with fixed args" error */
5014static va_list ap;
5015
5016/*
5017 * "printf()" function
5018 */
5019 static void
5020f_printf(typval_T *argvars, typval_T *rettv)
5021{
5022 char_u buf[NUMBUFLEN];
5023 int len;
5024 char_u *s;
5025 int saved_did_emsg = did_emsg;
5026 char *fmt;
5027
5028 rettv->v_type = VAR_STRING;
5029 rettv->vval.v_string = NULL;
5030
5031 /* Get the required length, allocate the buffer and do it for real. */
5032 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005033 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005034 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005035 if (!did_emsg)
5036 {
5037 s = alloc(len + 1);
5038 if (s != NULL)
5039 {
5040 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005041 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5042 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005043 }
5044 }
5045 did_emsg |= saved_did_emsg;
5046}
5047
5048/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005049 * "pum_getpos()" function
5050 */
5051 static void
5052f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5053{
5054 if (rettv_dict_alloc(rettv) != OK)
5055 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005056 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005057}
5058
5059/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060 * "pumvisible()" function
5061 */
5062 static void
5063f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5064{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005065 if (pum_visible())
5066 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005067}
5068
5069#ifdef FEAT_PYTHON3
5070/*
5071 * "py3eval()" function
5072 */
5073 static void
5074f_py3eval(typval_T *argvars, typval_T *rettv)
5075{
5076 char_u *str;
5077 char_u buf[NUMBUFLEN];
5078
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005079 if (check_restricted() || check_secure())
5080 return;
5081
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005082 if (p_pyx == 0)
5083 p_pyx = 3;
5084
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005085 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005086 do_py3eval(str, rettv);
5087}
5088#endif
5089
5090#ifdef FEAT_PYTHON
5091/*
5092 * "pyeval()" function
5093 */
5094 static void
5095f_pyeval(typval_T *argvars, typval_T *rettv)
5096{
5097 char_u *str;
5098 char_u buf[NUMBUFLEN];
5099
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005100 if (check_restricted() || check_secure())
5101 return;
5102
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005103 if (p_pyx == 0)
5104 p_pyx = 2;
5105
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005106 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 do_pyeval(str, rettv);
5108}
5109#endif
5110
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005111#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5112/*
5113 * "pyxeval()" function
5114 */
5115 static void
5116f_pyxeval(typval_T *argvars, typval_T *rettv)
5117{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005118 if (check_restricted() || check_secure())
5119 return;
5120
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005121# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5122 init_pyxversion();
5123 if (p_pyx == 2)
5124 f_pyeval(argvars, rettv);
5125 else
5126 f_py3eval(argvars, rettv);
5127# elif defined(FEAT_PYTHON)
5128 f_pyeval(argvars, rettv);
5129# elif defined(FEAT_PYTHON3)
5130 f_py3eval(argvars, rettv);
5131# endif
5132}
5133#endif
5134
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005135/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005136 * "rand()" function
5137 */
5138 static void
5139f_rand(typval_T *argvars, typval_T *rettv)
5140{
5141 list_T *l = NULL;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005142 static list_T *globl = NULL;
5143 UINT32_T x, y, z, w, t, result;
5144 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005145
5146 if (argvars[0].v_type == VAR_UNKNOWN)
5147 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005148 // When no argument is given use the global seed list.
5149 if (globl == NULL)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005150 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005151 // Initialize the global seed list.
5152 f_srand(argvars, rettv);
5153 l = rettv->vval.v_list;
5154 if (l == NULL || list_len(l) != 4)
5155 {
5156 clear_tv(rettv);
5157 goto theend;
5158 }
5159 globl = l;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005160 }
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005161 else
5162 l = globl;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005163 }
5164 else if (argvars[0].v_type == VAR_LIST)
5165 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005166 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005167 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005168 goto theend;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005169 }
5170 else
5171 goto theend;
5172
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005173 lx = list_find(l, 0L);
5174 ly = list_find(l, 1L);
5175 lz = list_find(l, 2L);
5176 lw = list_find(l, 3L);
5177 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5178 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5179 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5180 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5181 x = (UINT32_T)lx->li_tv.vval.v_number;
5182 y = (UINT32_T)ly->li_tv.vval.v_number;
5183 z = (UINT32_T)lz->li_tv.vval.v_number;
5184 w = (UINT32_T)lw->li_tv.vval.v_number;
5185
5186 // SHUFFLE_XOSHIRO128STARSTAR
5187#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5188 result = ROTL(y * 5, 7) * 9;
5189 t = y << 9;
5190 z ^= x;
5191 w ^= y;
5192 y ^= z, x ^= w;
5193 z ^= t;
5194 w = ROTL(w, 11);
5195#undef ROTL
5196
5197 lx->li_tv.vval.v_number = (varnumber_T)x;
5198 ly->li_tv.vval.v_number = (varnumber_T)y;
5199 lz->li_tv.vval.v_number = (varnumber_T)z;
5200 lw->li_tv.vval.v_number = (varnumber_T)w;
5201
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005202 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005203 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005204 return;
5205
5206theend:
5207 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005208 rettv->v_type = VAR_NUMBER;
5209 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005210}
5211
5212/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005213 * "range()" function
5214 */
5215 static void
5216f_range(typval_T *argvars, typval_T *rettv)
5217{
5218 varnumber_T start;
5219 varnumber_T end;
5220 varnumber_T stride = 1;
5221 varnumber_T i;
5222 int error = FALSE;
5223
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005224 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005225 if (argvars[1].v_type == VAR_UNKNOWN)
5226 {
5227 end = start - 1;
5228 start = 0;
5229 }
5230 else
5231 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005232 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005233 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005234 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005235 }
5236
5237 if (error)
5238 return; /* type error; errmsg already given */
5239 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005240 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005241 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005242 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005243 else
5244 {
5245 if (rettv_list_alloc(rettv) == OK)
5246 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5247 if (list_append_number(rettv->vval.v_list,
5248 (varnumber_T)i) == FAIL)
5249 break;
5250 }
5251}
5252
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005253 static void
5254return_register(int regname, typval_T *rettv)
5255{
5256 char_u buf[2] = {0, 0};
5257
5258 buf[0] = (char_u)regname;
5259 rettv->v_type = VAR_STRING;
5260 rettv->vval.v_string = vim_strsave(buf);
5261}
5262
5263/*
5264 * "reg_executing()" function
5265 */
5266 static void
5267f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5268{
5269 return_register(reg_executing, rettv);
5270}
5271
5272/*
5273 * "reg_recording()" function
5274 */
5275 static void
5276f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5277{
5278 return_register(reg_recording, rettv);
5279}
5280
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005281#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005282/*
5283 * Convert a List to proftime_T.
5284 * Return FAIL when there is something wrong.
5285 */
5286 static int
5287list2proftime(typval_T *arg, proftime_T *tm)
5288{
5289 long n1, n2;
5290 int error = FALSE;
5291
5292 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5293 || arg->vval.v_list->lv_len != 2)
5294 return FAIL;
5295 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5296 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005297# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 tm->HighPart = n1;
5299 tm->LowPart = n2;
5300# else
5301 tm->tv_sec = n1;
5302 tm->tv_usec = n2;
5303# endif
5304 return error ? FAIL : OK;
5305}
5306#endif /* FEAT_RELTIME */
5307
5308/*
5309 * "reltime()" function
5310 */
5311 static void
5312f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5313{
5314#ifdef FEAT_RELTIME
5315 proftime_T res;
5316 proftime_T start;
5317
5318 if (argvars[0].v_type == VAR_UNKNOWN)
5319 {
5320 /* No arguments: get current time. */
5321 profile_start(&res);
5322 }
5323 else if (argvars[1].v_type == VAR_UNKNOWN)
5324 {
5325 if (list2proftime(&argvars[0], &res) == FAIL)
5326 return;
5327 profile_end(&res);
5328 }
5329 else
5330 {
5331 /* Two arguments: compute the difference. */
5332 if (list2proftime(&argvars[0], &start) == FAIL
5333 || list2proftime(&argvars[1], &res) == FAIL)
5334 return;
5335 profile_sub(&res, &start);
5336 }
5337
5338 if (rettv_list_alloc(rettv) == OK)
5339 {
5340 long n1, n2;
5341
Bram Moolenaar4f974752019-02-17 17:44:42 +01005342# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005343 n1 = res.HighPart;
5344 n2 = res.LowPart;
5345# else
5346 n1 = res.tv_sec;
5347 n2 = res.tv_usec;
5348# endif
5349 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5350 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5351 }
5352#endif
5353}
5354
5355#ifdef FEAT_FLOAT
5356/*
5357 * "reltimefloat()" function
5358 */
5359 static void
5360f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5361{
5362# ifdef FEAT_RELTIME
5363 proftime_T tm;
5364# endif
5365
5366 rettv->v_type = VAR_FLOAT;
5367 rettv->vval.v_float = 0;
5368# ifdef FEAT_RELTIME
5369 if (list2proftime(&argvars[0], &tm) == OK)
5370 rettv->vval.v_float = profile_float(&tm);
5371# endif
5372}
5373#endif
5374
5375/*
5376 * "reltimestr()" function
5377 */
5378 static void
5379f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5380{
5381#ifdef FEAT_RELTIME
5382 proftime_T tm;
5383#endif
5384
5385 rettv->v_type = VAR_STRING;
5386 rettv->vval.v_string = NULL;
5387#ifdef FEAT_RELTIME
5388 if (list2proftime(&argvars[0], &tm) == OK)
5389 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5390#endif
5391}
5392
5393#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005394 static void
5395make_connection(void)
5396{
5397 if (X_DISPLAY == NULL
5398# ifdef FEAT_GUI
5399 && !gui.in_use
5400# endif
5401 )
5402 {
5403 x_force_connect = TRUE;
5404 setup_term_clip();
5405 x_force_connect = FALSE;
5406 }
5407}
5408
5409 static int
5410check_connection(void)
5411{
5412 make_connection();
5413 if (X_DISPLAY == NULL)
5414 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005415 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005416 return FAIL;
5417 }
5418 return OK;
5419}
5420#endif
5421
5422#ifdef FEAT_CLIENTSERVER
5423 static void
5424remote_common(typval_T *argvars, typval_T *rettv, int expr)
5425{
5426 char_u *server_name;
5427 char_u *keys;
5428 char_u *r = NULL;
5429 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005430 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005431# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005432 HWND w;
5433# else
5434 Window w;
5435# endif
5436
5437 if (check_restricted() || check_secure())
5438 return;
5439
5440# ifdef FEAT_X11
5441 if (check_connection() == FAIL)
5442 return;
5443# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005444 if (argvars[2].v_type != VAR_UNKNOWN
5445 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005446 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005447
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005448 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005449 if (server_name == NULL)
5450 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005451 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005452# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005453 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005454# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005455 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5456 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005457# endif
5458 {
5459 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005460 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005461 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005462 vim_free(r);
5463 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005464 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005465 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005466 return;
5467 }
5468
5469 rettv->vval.v_string = r;
5470
5471 if (argvars[2].v_type != VAR_UNKNOWN)
5472 {
5473 dictitem_T v;
5474 char_u str[30];
5475 char_u *idvar;
5476
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005477 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005478 if (idvar != NULL && *idvar != NUL)
5479 {
5480 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5481 v.di_tv.v_type = VAR_STRING;
5482 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005483 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005484 vim_free(v.di_tv.vval.v_string);
5485 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005486 }
5487}
5488#endif
5489
5490/*
5491 * "remote_expr()" function
5492 */
5493 static void
5494f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5495{
5496 rettv->v_type = VAR_STRING;
5497 rettv->vval.v_string = NULL;
5498#ifdef FEAT_CLIENTSERVER
5499 remote_common(argvars, rettv, TRUE);
5500#endif
5501}
5502
5503/*
5504 * "remote_foreground()" function
5505 */
5506 static void
5507f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5508{
5509#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005510# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005511 /* On Win32 it's done in this application. */
5512 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005513 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005514
5515 if (server_name != NULL)
5516 serverForeground(server_name);
5517 }
5518# else
5519 /* Send a foreground() expression to the server. */
5520 argvars[1].v_type = VAR_STRING;
5521 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5522 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005523 rettv->v_type = VAR_STRING;
5524 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005525 remote_common(argvars, rettv, TRUE);
5526 vim_free(argvars[1].vval.v_string);
5527# endif
5528#endif
5529}
5530
5531 static void
5532f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5533{
5534#ifdef FEAT_CLIENTSERVER
5535 dictitem_T v;
5536 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005537# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005538 long_u n = 0;
5539# endif
5540 char_u *serverid;
5541
5542 if (check_restricted() || check_secure())
5543 {
5544 rettv->vval.v_number = -1;
5545 return;
5546 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005547 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005548 if (serverid == NULL)
5549 {
5550 rettv->vval.v_number = -1;
5551 return; /* type error; errmsg already given */
5552 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005553# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005554 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5555 if (n == 0)
5556 rettv->vval.v_number = -1;
5557 else
5558 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005559 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005560 rettv->vval.v_number = (s != NULL);
5561 }
5562# else
5563 if (check_connection() == FAIL)
5564 return;
5565
5566 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5567 serverStrToWin(serverid), &s);
5568# endif
5569
5570 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5571 {
5572 char_u *retvar;
5573
5574 v.di_tv.v_type = VAR_STRING;
5575 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005576 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 if (retvar != NULL)
5578 set_var(retvar, &v.di_tv, FALSE);
5579 vim_free(v.di_tv.vval.v_string);
5580 }
5581#else
5582 rettv->vval.v_number = -1;
5583#endif
5584}
5585
5586 static void
5587f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5588{
5589 char_u *r = NULL;
5590
5591#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005592 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005593
5594 if (serverid != NULL && !check_restricted() && !check_secure())
5595 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005596 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005597# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005598 /* The server's HWND is encoded in the 'id' parameter */
5599 long_u n = 0;
5600# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005601
5602 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005603 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005604
Bram Moolenaar4f974752019-02-17 17:44:42 +01005605# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005606 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5607 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005608 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005609 if (r == NULL)
5610# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005611 if (check_connection() == FAIL
5612 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5613 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005614# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005615 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005616 }
5617#endif
5618 rettv->v_type = VAR_STRING;
5619 rettv->vval.v_string = r;
5620}
5621
5622/*
5623 * "remote_send()" function
5624 */
5625 static void
5626f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5627{
5628 rettv->v_type = VAR_STRING;
5629 rettv->vval.v_string = NULL;
5630#ifdef FEAT_CLIENTSERVER
5631 remote_common(argvars, rettv, FALSE);
5632#endif
5633}
5634
5635/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005636 * "remote_startserver()" function
5637 */
5638 static void
5639f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5640{
5641#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005642 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005643
5644 if (server == NULL)
5645 return; /* type error; errmsg already given */
5646 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005647 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005648 else
5649 {
5650# ifdef FEAT_X11
5651 if (check_connection() == OK)
5652 serverRegisterName(X_DISPLAY, server);
5653# else
5654 serverSetName(server);
5655# endif
5656 }
5657#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005658 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005659#endif
5660}
5661
5662/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005663 * "rename({from}, {to})" function
5664 */
5665 static void
5666f_rename(typval_T *argvars, typval_T *rettv)
5667{
5668 char_u buf[NUMBUFLEN];
5669
5670 if (check_restricted() || check_secure())
5671 rettv->vval.v_number = -1;
5672 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005673 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5674 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005675}
5676
5677/*
5678 * "repeat()" function
5679 */
5680 static void
5681f_repeat(typval_T *argvars, typval_T *rettv)
5682{
5683 char_u *p;
5684 int n;
5685 int slen;
5686 int len;
5687 char_u *r;
5688 int i;
5689
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005690 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691 if (argvars[0].v_type == VAR_LIST)
5692 {
5693 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5694 while (n-- > 0)
5695 if (list_extend(rettv->vval.v_list,
5696 argvars[0].vval.v_list, NULL) == FAIL)
5697 break;
5698 }
5699 else
5700 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005701 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005702 rettv->v_type = VAR_STRING;
5703 rettv->vval.v_string = NULL;
5704
5705 slen = (int)STRLEN(p);
5706 len = slen * n;
5707 if (len <= 0)
5708 return;
5709
5710 r = alloc(len + 1);
5711 if (r != NULL)
5712 {
5713 for (i = 0; i < n; i++)
5714 mch_memmove(r + i * slen, p, (size_t)slen);
5715 r[len] = NUL;
5716 }
5717
5718 rettv->vval.v_string = r;
5719 }
5720}
5721
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005722#define SP_NOMOVE 0x01 /* don't move cursor */
5723#define SP_REPEAT 0x02 /* repeat to find outer pair */
5724#define SP_RETCOUNT 0x04 /* return matchcount */
5725#define SP_SETPCMARK 0x08 /* set previous context mark */
5726#define SP_START 0x10 /* accept match at start position */
5727#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5728#define SP_END 0x40 /* leave cursor at end of match */
5729#define SP_COLUMN 0x80 /* start at cursor column */
5730
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005731/*
5732 * Get flags for a search function.
5733 * Possibly sets "p_ws".
5734 * Returns BACKWARD, FORWARD or zero (for an error).
5735 */
5736 static int
5737get_search_arg(typval_T *varp, int *flagsp)
5738{
5739 int dir = FORWARD;
5740 char_u *flags;
5741 char_u nbuf[NUMBUFLEN];
5742 int mask;
5743
5744 if (varp->v_type != VAR_UNKNOWN)
5745 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005746 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005747 if (flags == NULL)
5748 return 0; /* type error; errmsg already given */
5749 while (*flags != NUL)
5750 {
5751 switch (*flags)
5752 {
5753 case 'b': dir = BACKWARD; break;
5754 case 'w': p_ws = TRUE; break;
5755 case 'W': p_ws = FALSE; break;
5756 default: mask = 0;
5757 if (flagsp != NULL)
5758 switch (*flags)
5759 {
5760 case 'c': mask = SP_START; break;
5761 case 'e': mask = SP_END; break;
5762 case 'm': mask = SP_RETCOUNT; break;
5763 case 'n': mask = SP_NOMOVE; break;
5764 case 'p': mask = SP_SUBPAT; break;
5765 case 'r': mask = SP_REPEAT; break;
5766 case 's': mask = SP_SETPCMARK; break;
5767 case 'z': mask = SP_COLUMN; break;
5768 }
5769 if (mask == 0)
5770 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005771 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005772 dir = 0;
5773 }
5774 else
5775 *flagsp |= mask;
5776 }
5777 if (dir == 0)
5778 break;
5779 ++flags;
5780 }
5781 }
5782 return dir;
5783}
5784
5785/*
5786 * Shared by search() and searchpos() functions.
5787 */
5788 static int
5789search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5790{
5791 int flags;
5792 char_u *pat;
5793 pos_T pos;
5794 pos_T save_cursor;
5795 int save_p_ws = p_ws;
5796 int dir;
5797 int retval = 0; /* default: FAIL */
5798 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005800 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 long time_limit = 0;
5802#endif
5803 int options = SEARCH_KEEP;
5804 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005805 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005806
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005807 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005808 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5809 if (dir == 0)
5810 goto theend;
5811 flags = *flagsp;
5812 if (flags & SP_START)
5813 options |= SEARCH_START;
5814 if (flags & SP_END)
5815 options |= SEARCH_END;
5816 if (flags & SP_COLUMN)
5817 options |= SEARCH_COL;
5818
5819 /* Optional arguments: line number to stop searching and timeout. */
5820 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5821 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005822 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005823 if (lnum_stop < 0)
5824 goto theend;
5825#ifdef FEAT_RELTIME
5826 if (argvars[3].v_type != VAR_UNKNOWN)
5827 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005828 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829 if (time_limit < 0)
5830 goto theend;
5831 }
5832#endif
5833 }
5834
5835#ifdef FEAT_RELTIME
5836 /* Set the time limit, if there is one. */
5837 profile_setlimit(time_limit, &tm);
5838#endif
5839
5840 /*
5841 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5842 * Check to make sure only those flags are set.
5843 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5844 * flags cannot be set. Check for that condition also.
5845 */
5846 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5847 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5848 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005849 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005850 goto theend;
5851 }
5852
5853 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005854 vim_memset(&sia, 0, sizeof(sia));
5855 sia.sa_stop_lnum = (linenr_T)lnum_stop;
5856#ifdef FEAT_RELTIME
5857 sia.sa_tm = &tm;
5858#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005859 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005860 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005861 if (subpatnum != FAIL)
5862 {
5863 if (flags & SP_SUBPAT)
5864 retval = subpatnum;
5865 else
5866 retval = pos.lnum;
5867 if (flags & SP_SETPCMARK)
5868 setpcmark();
5869 curwin->w_cursor = pos;
5870 if (match_pos != NULL)
5871 {
5872 /* Store the match cursor position */
5873 match_pos->lnum = pos.lnum;
5874 match_pos->col = pos.col + 1;
5875 }
5876 /* "/$" will put the cursor after the end of the line, may need to
5877 * correct that here */
5878 check_cursor();
5879 }
5880
5881 /* If 'n' flag is used: restore cursor position. */
5882 if (flags & SP_NOMOVE)
5883 curwin->w_cursor = save_cursor;
5884 else
5885 curwin->w_set_curswant = TRUE;
5886theend:
5887 p_ws = save_p_ws;
5888
5889 return retval;
5890}
5891
5892#ifdef FEAT_FLOAT
5893
5894/*
5895 * round() is not in C90, use ceil() or floor() instead.
5896 */
5897 float_T
5898vim_round(float_T f)
5899{
5900 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
5901}
5902
5903/*
5904 * "round({float})" function
5905 */
5906 static void
5907f_round(typval_T *argvars, typval_T *rettv)
5908{
5909 float_T f = 0.0;
5910
5911 rettv->v_type = VAR_FLOAT;
5912 if (get_float_arg(argvars, &f) == OK)
5913 rettv->vval.v_float = vim_round(f);
5914 else
5915 rettv->vval.v_float = 0.0;
5916}
5917#endif
5918
Bram Moolenaare99be0e2019-03-26 22:51:09 +01005919#ifdef FEAT_RUBY
5920/*
5921 * "rubyeval()" function
5922 */
5923 static void
5924f_rubyeval(typval_T *argvars, typval_T *rettv)
5925{
5926 char_u *str;
5927 char_u buf[NUMBUFLEN];
5928
5929 str = tv_get_string_buf(&argvars[0], buf);
5930 do_rubyeval(str, rettv);
5931}
5932#endif
5933
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005934/*
5935 * "screenattr()" function
5936 */
5937 static void
5938f_screenattr(typval_T *argvars, typval_T *rettv)
5939{
5940 int row;
5941 int col;
5942 int c;
5943
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005944 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5945 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005946 if (row < 0 || row >= screen_Rows
5947 || col < 0 || col >= screen_Columns)
5948 c = -1;
5949 else
5950 c = ScreenAttrs[LineOffset[row] + col];
5951 rettv->vval.v_number = c;
5952}
5953
5954/*
5955 * "screenchar()" function
5956 */
5957 static void
5958f_screenchar(typval_T *argvars, typval_T *rettv)
5959{
5960 int row;
5961 int col;
5962 int off;
5963 int c;
5964
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005965 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5966 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005967 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005968 c = -1;
5969 else
5970 {
5971 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972 if (enc_utf8 && ScreenLinesUC[off] != 0)
5973 c = ScreenLinesUC[off];
5974 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005975 c = ScreenLines[off];
5976 }
5977 rettv->vval.v_number = c;
5978}
5979
5980/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005981 * "screenchars()" function
5982 */
5983 static void
5984f_screenchars(typval_T *argvars, typval_T *rettv)
5985{
5986 int row;
5987 int col;
5988 int off;
5989 int c;
5990 int i;
5991
5992 if (rettv_list_alloc(rettv) == FAIL)
5993 return;
5994 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5995 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5996 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5997 return;
5998
5999 off = LineOffset[row] + col;
6000 if (enc_utf8 && ScreenLinesUC[off] != 0)
6001 c = ScreenLinesUC[off];
6002 else
6003 c = ScreenLines[off];
6004 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6005
6006 if (enc_utf8)
6007
6008 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6009 list_append_number(rettv->vval.v_list,
6010 (varnumber_T)ScreenLinesC[i][off]);
6011}
6012
6013/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006014 * "screencol()" function
6015 *
6016 * First column is 1 to be consistent with virtcol().
6017 */
6018 static void
6019f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6020{
6021 rettv->vval.v_number = screen_screencol() + 1;
6022}
6023
6024/*
6025 * "screenrow()" function
6026 */
6027 static void
6028f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6029{
6030 rettv->vval.v_number = screen_screenrow() + 1;
6031}
6032
6033/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006034 * "screenstring()" function
6035 */
6036 static void
6037f_screenstring(typval_T *argvars, typval_T *rettv)
6038{
6039 int row;
6040 int col;
6041 int off;
6042 int c;
6043 int i;
6044 char_u buf[MB_MAXBYTES + 1];
6045 int buflen = 0;
6046
6047 rettv->vval.v_string = NULL;
6048 rettv->v_type = VAR_STRING;
6049
6050 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6051 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6052 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6053 return;
6054
6055 off = LineOffset[row] + col;
6056 if (enc_utf8 && ScreenLinesUC[off] != 0)
6057 c = ScreenLinesUC[off];
6058 else
6059 c = ScreenLines[off];
6060 buflen += mb_char2bytes(c, buf);
6061
6062 if (enc_utf8)
6063 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6064 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6065
6066 buf[buflen] = NUL;
6067 rettv->vval.v_string = vim_strsave(buf);
6068}
6069
6070/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006071 * "search()" function
6072 */
6073 static void
6074f_search(typval_T *argvars, typval_T *rettv)
6075{
6076 int flags = 0;
6077
6078 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6079}
6080
6081/*
6082 * "searchdecl()" function
6083 */
6084 static void
6085f_searchdecl(typval_T *argvars, typval_T *rettv)
6086{
6087 int locally = 1;
6088 int thisblock = 0;
6089 int error = FALSE;
6090 char_u *name;
6091
6092 rettv->vval.v_number = 1; /* default: FAIL */
6093
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006094 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006095 if (argvars[1].v_type != VAR_UNKNOWN)
6096 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006097 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006098 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006099 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006100 }
6101 if (!error && name != NULL)
6102 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6103 locally, thisblock, SEARCH_KEEP) == FAIL;
6104}
6105
6106/*
6107 * Used by searchpair() and searchpairpos()
6108 */
6109 static int
6110searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6111{
6112 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006113 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006114 int save_p_ws = p_ws;
6115 int dir;
6116 int flags = 0;
6117 char_u nbuf1[NUMBUFLEN];
6118 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006119 int retval = 0; /* default: FAIL */
6120 long lnum_stop = 0;
6121 long time_limit = 0;
6122
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006123 /* Get the three pattern arguments: start, middle, end. Will result in an
6124 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006125 spat = tv_get_string_chk(&argvars[0]);
6126 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6127 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006128 if (spat == NULL || mpat == NULL || epat == NULL)
6129 goto theend; /* type error */
6130
6131 /* Handle the optional fourth argument: flags */
6132 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6133 if (dir == 0)
6134 goto theend;
6135
6136 /* Don't accept SP_END or SP_SUBPAT.
6137 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6138 */
6139 if ((flags & (SP_END | SP_SUBPAT)) != 0
6140 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6141 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006142 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143 goto theend;
6144 }
6145
6146 /* Using 'r' implies 'W', otherwise it doesn't work. */
6147 if (flags & SP_REPEAT)
6148 p_ws = FALSE;
6149
6150 /* Optional fifth argument: skip expression */
6151 if (argvars[3].v_type == VAR_UNKNOWN
6152 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006153 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006154 else
6155 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006156 skip = &argvars[4];
6157 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6158 && skip->v_type != VAR_STRING)
6159 {
6160 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006161 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006162 goto theend;
6163 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006164 if (argvars[5].v_type != VAR_UNKNOWN)
6165 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006166 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006167 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006168 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006169 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006170 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006171 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006172#ifdef FEAT_RELTIME
6173 if (argvars[6].v_type != VAR_UNKNOWN)
6174 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006175 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006176 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006177 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006178 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006179 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006180 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006181 }
6182#endif
6183 }
6184 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185
6186 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6187 match_pos, lnum_stop, time_limit);
6188
6189theend:
6190 p_ws = save_p_ws;
6191
6192 return retval;
6193}
6194
6195/*
6196 * "searchpair()" function
6197 */
6198 static void
6199f_searchpair(typval_T *argvars, typval_T *rettv)
6200{
6201 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6202}
6203
6204/*
6205 * "searchpairpos()" function
6206 */
6207 static void
6208f_searchpairpos(typval_T *argvars, typval_T *rettv)
6209{
6210 pos_T match_pos;
6211 int lnum = 0;
6212 int col = 0;
6213
6214 if (rettv_list_alloc(rettv) == FAIL)
6215 return;
6216
6217 if (searchpair_cmn(argvars, &match_pos) > 0)
6218 {
6219 lnum = match_pos.lnum;
6220 col = match_pos.col;
6221 }
6222
6223 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6224 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6225}
6226
6227/*
6228 * Search for a start/middle/end thing.
6229 * Used by searchpair(), see its documentation for the details.
6230 * Returns 0 or -1 for no match,
6231 */
6232 long
6233do_searchpair(
6234 char_u *spat, /* start pattern */
6235 char_u *mpat, /* middle pattern */
6236 char_u *epat, /* end pattern */
6237 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006238 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006239 int flags, /* SP_SETPCMARK and other SP_ values */
6240 pos_T *match_pos,
6241 linenr_T lnum_stop, /* stop at this line if not zero */
6242 long time_limit UNUSED) /* stop after this many msec */
6243{
6244 char_u *save_cpo;
6245 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6246 long retval = 0;
6247 pos_T pos;
6248 pos_T firstpos;
6249 pos_T foundpos;
6250 pos_T save_cursor;
6251 pos_T save_pos;
6252 int n;
6253 int r;
6254 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006255 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006256 int err;
6257 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006258#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006259 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006260#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006261
6262 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6263 save_cpo = p_cpo;
6264 p_cpo = empty_option;
6265
6266#ifdef FEAT_RELTIME
6267 /* Set the time limit, if there is one. */
6268 profile_setlimit(time_limit, &tm);
6269#endif
6270
6271 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6272 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006273 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6274 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006275 if (pat2 == NULL || pat3 == NULL)
6276 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006277 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006278 if (*mpat == NUL)
6279 STRCPY(pat3, pat2);
6280 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006281 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006282 spat, epat, mpat);
6283 if (flags & SP_START)
6284 options |= SEARCH_START;
6285
Bram Moolenaar48570482017-10-30 21:48:41 +01006286 if (skip != NULL)
6287 {
6288 /* Empty string means to not use the skip expression. */
6289 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6290 use_skip = skip->vval.v_string != NULL
6291 && *skip->vval.v_string != NUL;
6292 }
6293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006294 save_cursor = curwin->w_cursor;
6295 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006296 CLEAR_POS(&firstpos);
6297 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006298 pat = pat3;
6299 for (;;)
6300 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006301 searchit_arg_T sia;
6302
6303 vim_memset(&sia, 0, sizeof(sia));
6304 sia.sa_stop_lnum = lnum_stop;
6305#ifdef FEAT_RELTIME
6306 sia.sa_tm = &tm;
6307#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006308 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006309 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006310 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006311 /* didn't find it or found the first match again: FAIL */
6312 break;
6313
6314 if (firstpos.lnum == 0)
6315 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006316 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006317 {
6318 /* Found the same position again. Can happen with a pattern that
6319 * has "\zs" at the end and searching backwards. Advance one
6320 * character and try again. */
6321 if (dir == BACKWARD)
6322 decl(&pos);
6323 else
6324 incl(&pos);
6325 }
6326 foundpos = pos;
6327
6328 /* clear the start flag to avoid getting stuck here */
6329 options &= ~SEARCH_START;
6330
6331 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006332 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333 {
6334 save_pos = curwin->w_cursor;
6335 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006336 err = FALSE;
6337 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006338 curwin->w_cursor = save_pos;
6339 if (err)
6340 {
6341 /* Evaluating {skip} caused an error, break here. */
6342 curwin->w_cursor = save_cursor;
6343 retval = -1;
6344 break;
6345 }
6346 if (r)
6347 continue;
6348 }
6349
6350 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6351 {
6352 /* Found end when searching backwards or start when searching
6353 * forward: nested pair. */
6354 ++nest;
6355 pat = pat2; /* nested, don't search for middle */
6356 }
6357 else
6358 {
6359 /* Found end when searching forward or start when searching
6360 * backward: end of (nested) pair; or found middle in outer pair. */
6361 if (--nest == 1)
6362 pat = pat3; /* outer level, search for middle */
6363 }
6364
6365 if (nest == 0)
6366 {
6367 /* Found the match: return matchcount or line number. */
6368 if (flags & SP_RETCOUNT)
6369 ++retval;
6370 else
6371 retval = pos.lnum;
6372 if (flags & SP_SETPCMARK)
6373 setpcmark();
6374 curwin->w_cursor = pos;
6375 if (!(flags & SP_REPEAT))
6376 break;
6377 nest = 1; /* search for next unmatched */
6378 }
6379 }
6380
6381 if (match_pos != NULL)
6382 {
6383 /* Store the match cursor position */
6384 match_pos->lnum = curwin->w_cursor.lnum;
6385 match_pos->col = curwin->w_cursor.col + 1;
6386 }
6387
6388 /* If 'n' flag is used or search failed: restore cursor position. */
6389 if ((flags & SP_NOMOVE) || retval == 0)
6390 curwin->w_cursor = save_cursor;
6391
6392theend:
6393 vim_free(pat2);
6394 vim_free(pat3);
6395 if (p_cpo == empty_option)
6396 p_cpo = save_cpo;
6397 else
6398 /* Darn, evaluating the {skip} expression changed the value. */
6399 free_string_option(save_cpo);
6400
6401 return retval;
6402}
6403
6404/*
6405 * "searchpos()" function
6406 */
6407 static void
6408f_searchpos(typval_T *argvars, typval_T *rettv)
6409{
6410 pos_T match_pos;
6411 int lnum = 0;
6412 int col = 0;
6413 int n;
6414 int flags = 0;
6415
6416 if (rettv_list_alloc(rettv) == FAIL)
6417 return;
6418
6419 n = search_cmn(argvars, &match_pos, &flags);
6420 if (n > 0)
6421 {
6422 lnum = match_pos.lnum;
6423 col = match_pos.col;
6424 }
6425
6426 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6427 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6428 if (flags & SP_SUBPAT)
6429 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6430}
6431
6432 static void
6433f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6434{
6435#ifdef FEAT_CLIENTSERVER
6436 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006437 char_u *server = tv_get_string_chk(&argvars[0]);
6438 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006439
6440 rettv->vval.v_number = -1;
6441 if (server == NULL || reply == NULL)
6442 return;
6443 if (check_restricted() || check_secure())
6444 return;
6445# ifdef FEAT_X11
6446 if (check_connection() == FAIL)
6447 return;
6448# endif
6449
6450 if (serverSendReply(server, reply) < 0)
6451 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006452 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006453 return;
6454 }
6455 rettv->vval.v_number = 0;
6456#else
6457 rettv->vval.v_number = -1;
6458#endif
6459}
6460
6461 static void
6462f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6463{
6464 char_u *r = NULL;
6465
6466#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006467# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006468 r = serverGetVimNames();
6469# else
6470 make_connection();
6471 if (X_DISPLAY != NULL)
6472 r = serverGetVimNames(X_DISPLAY);
6473# endif
6474#endif
6475 rettv->v_type = VAR_STRING;
6476 rettv->vval.v_string = r;
6477}
6478
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006479 static void
6480f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6481{
6482 dict_T *d;
6483 dictitem_T *di;
6484 char_u *csearch;
6485
6486 if (argvars[0].v_type != VAR_DICT)
6487 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006488 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489 return;
6490 }
6491
6492 if ((d = argvars[0].vval.v_dict) != NULL)
6493 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006494 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006495 if (csearch != NULL)
6496 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006497 if (enc_utf8)
6498 {
6499 int pcc[MAX_MCO];
6500 int c = utfc_ptr2char(csearch, pcc);
6501
6502 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6503 }
6504 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006506 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507 }
6508
6509 di = dict_find(d, (char_u *)"forward", -1);
6510 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006511 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006512 ? FORWARD : BACKWARD);
6513
6514 di = dict_find(d, (char_u *)"until", -1);
6515 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006516 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006517 }
6518}
6519
6520/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006521 * "setenv()" function
6522 */
6523 static void
6524f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6525{
6526 char_u namebuf[NUMBUFLEN];
6527 char_u valbuf[NUMBUFLEN];
6528 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6529
6530 if (argvars[1].v_type == VAR_SPECIAL
6531 && argvars[1].vval.v_number == VVAL_NULL)
6532 vim_unsetenv(name);
6533 else
6534 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6535}
6536
6537/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006538 * "setfperm({fname}, {mode})" function
6539 */
6540 static void
6541f_setfperm(typval_T *argvars, typval_T *rettv)
6542{
6543 char_u *fname;
6544 char_u modebuf[NUMBUFLEN];
6545 char_u *mode_str;
6546 int i;
6547 int mask;
6548 int mode = 0;
6549
6550 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006551 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006552 if (fname == NULL)
6553 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006554 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006555 if (mode_str == NULL)
6556 return;
6557 if (STRLEN(mode_str) != 9)
6558 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006559 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560 return;
6561 }
6562
6563 mask = 1;
6564 for (i = 8; i >= 0; --i)
6565 {
6566 if (mode_str[i] != '-')
6567 mode |= mask;
6568 mask = mask << 1;
6569 }
6570 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6571}
6572
6573/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006574 * "setpos()" function
6575 */
6576 static void
6577f_setpos(typval_T *argvars, typval_T *rettv)
6578{
6579 pos_T pos;
6580 int fnum;
6581 char_u *name;
6582 colnr_T curswant = -1;
6583
6584 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006585 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006586 if (name != NULL)
6587 {
6588 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6589 {
6590 if (--pos.col < 0)
6591 pos.col = 0;
6592 if (name[0] == '.' && name[1] == NUL)
6593 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006594 /* set cursor; "fnum" is ignored */
6595 curwin->w_cursor = pos;
6596 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006597 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006598 curwin->w_curswant = curswant - 1;
6599 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006601 check_cursor();
6602 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006603 }
6604 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6605 {
6606 /* set mark */
6607 if (setmark_pos(name[1], &pos, fnum) == OK)
6608 rettv->vval.v_number = 0;
6609 }
6610 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006611 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006612 }
6613 }
6614}
6615
6616/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006617 * "setreg()" function
6618 */
6619 static void
6620f_setreg(typval_T *argvars, typval_T *rettv)
6621{
6622 int regname;
6623 char_u *strregname;
6624 char_u *stropt;
6625 char_u *strval;
6626 int append;
6627 char_u yank_type;
6628 long block_len;
6629
6630 block_len = -1;
6631 yank_type = MAUTO;
6632 append = FALSE;
6633
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006634 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006635 rettv->vval.v_number = 1; /* FAIL is default */
6636
6637 if (strregname == NULL)
6638 return; /* type error; errmsg already given */
6639 regname = *strregname;
6640 if (regname == 0 || regname == '@')
6641 regname = '"';
6642
6643 if (argvars[2].v_type != VAR_UNKNOWN)
6644 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006645 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006646 if (stropt == NULL)
6647 return; /* type error */
6648 for (; *stropt != NUL; ++stropt)
6649 switch (*stropt)
6650 {
6651 case 'a': case 'A': /* append */
6652 append = TRUE;
6653 break;
6654 case 'v': case 'c': /* character-wise selection */
6655 yank_type = MCHAR;
6656 break;
6657 case 'V': case 'l': /* line-wise selection */
6658 yank_type = MLINE;
6659 break;
6660 case 'b': case Ctrl_V: /* block-wise selection */
6661 yank_type = MBLOCK;
6662 if (VIM_ISDIGIT(stropt[1]))
6663 {
6664 ++stropt;
6665 block_len = getdigits(&stropt) - 1;
6666 --stropt;
6667 }
6668 break;
6669 }
6670 }
6671
6672 if (argvars[1].v_type == VAR_LIST)
6673 {
6674 char_u **lstval;
6675 char_u **allocval;
6676 char_u buf[NUMBUFLEN];
6677 char_u **curval;
6678 char_u **curallocval;
6679 list_T *ll = argvars[1].vval.v_list;
6680 listitem_T *li;
6681 int len;
6682
6683 /* If the list is NULL handle like an empty list. */
6684 len = ll == NULL ? 0 : ll->lv_len;
6685
6686 /* First half: use for pointers to result lines; second half: use for
6687 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006688 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 if (lstval == NULL)
6690 return;
6691 curval = lstval;
6692 allocval = lstval + len + 2;
6693 curallocval = allocval;
6694
6695 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6696 li = li->li_next)
6697 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006698 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006699 if (strval == NULL)
6700 goto free_lstval;
6701 if (strval == buf)
6702 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006703 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006704 * overwrite the string. */
6705 strval = vim_strsave(buf);
6706 if (strval == NULL)
6707 goto free_lstval;
6708 *curallocval++ = strval;
6709 }
6710 *curval++ = strval;
6711 }
6712 *curval++ = NULL;
6713
6714 write_reg_contents_lst(regname, lstval, -1,
6715 append, yank_type, block_len);
6716free_lstval:
6717 while (curallocval > allocval)
6718 vim_free(*--curallocval);
6719 vim_free(lstval);
6720 }
6721 else
6722 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006723 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006724 if (strval == NULL)
6725 return;
6726 write_reg_contents_ex(regname, strval, -1,
6727 append, yank_type, block_len);
6728 }
6729 rettv->vval.v_number = 0;
6730}
6731
6732/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006733 * "settagstack()" function
6734 */
6735 static void
6736f_settagstack(typval_T *argvars, typval_T *rettv)
6737{
6738 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6739 win_T *wp;
6740 dict_T *d;
6741 int action = 'r';
6742
6743 rettv->vval.v_number = -1;
6744
6745 // first argument: window number or id
6746 wp = find_win_by_nr_or_id(&argvars[0]);
6747 if (wp == NULL)
6748 return;
6749
6750 // second argument: dict with items to set in the tag stack
6751 if (argvars[1].v_type != VAR_DICT)
6752 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006753 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006754 return;
6755 }
6756 d = argvars[1].vval.v_dict;
6757 if (d == NULL)
6758 return;
6759
6760 // third argument: action - 'a' for append and 'r' for replace.
6761 // default is to replace the stack.
6762 if (argvars[2].v_type == VAR_UNKNOWN)
6763 action = 'r';
6764 else if (argvars[2].v_type == VAR_STRING)
6765 {
6766 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006767 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006768 if (actstr == NULL)
6769 return;
6770 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6771 action = *actstr;
6772 else
6773 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006774 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006775 return;
6776 }
6777 }
6778 else
6779 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006780 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006781 return;
6782 }
6783
6784 if (set_tagstack(wp, d, action) == OK)
6785 rettv->vval.v_number = 0;
6786}
6787
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006788#ifdef FEAT_CRYPT
6789/*
6790 * "sha256({string})" function
6791 */
6792 static void
6793f_sha256(typval_T *argvars, typval_T *rettv)
6794{
6795 char_u *p;
6796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006797 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006798 rettv->vval.v_string = vim_strsave(
6799 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6800 rettv->v_type = VAR_STRING;
6801}
6802#endif /* FEAT_CRYPT */
6803
6804/*
6805 * "shellescape({string})" function
6806 */
6807 static void
6808f_shellescape(typval_T *argvars, typval_T *rettv)
6809{
Bram Moolenaar20615522017-06-05 18:46:26 +02006810 int do_special = non_zero_arg(&argvars[1]);
6811
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006812 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006813 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006814 rettv->v_type = VAR_STRING;
6815}
6816
6817/*
6818 * shiftwidth() function
6819 */
6820 static void
6821f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6822{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006823 rettv->vval.v_number = 0;
6824
6825 if (argvars[0].v_type != VAR_UNKNOWN)
6826 {
6827 long col;
6828
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006829 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006830 if (col < 0)
6831 return; // type error; errmsg already given
6832#ifdef FEAT_VARTABS
6833 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6834 return;
6835#endif
6836 }
6837
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006838 rettv->vval.v_number = get_sw_value(curbuf);
6839}
6840
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006841#ifdef FEAT_FLOAT
6842/*
6843 * "sin()" function
6844 */
6845 static void
6846f_sin(typval_T *argvars, typval_T *rettv)
6847{
6848 float_T f = 0.0;
6849
6850 rettv->v_type = VAR_FLOAT;
6851 if (get_float_arg(argvars, &f) == OK)
6852 rettv->vval.v_float = sin(f);
6853 else
6854 rettv->vval.v_float = 0.0;
6855}
6856
6857/*
6858 * "sinh()" function
6859 */
6860 static void
6861f_sinh(typval_T *argvars, typval_T *rettv)
6862{
6863 float_T f = 0.0;
6864
6865 rettv->v_type = VAR_FLOAT;
6866 if (get_float_arg(argvars, &f) == OK)
6867 rettv->vval.v_float = sinh(f);
6868 else
6869 rettv->vval.v_float = 0.0;
6870}
6871#endif
6872
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006873/*
6874 * "soundfold({word})" function
6875 */
6876 static void
6877f_soundfold(typval_T *argvars, typval_T *rettv)
6878{
6879 char_u *s;
6880
6881 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006882 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883#ifdef FEAT_SPELL
6884 rettv->vval.v_string = eval_soundfold(s);
6885#else
6886 rettv->vval.v_string = vim_strsave(s);
6887#endif
6888}
6889
6890/*
6891 * "spellbadword()" function
6892 */
6893 static void
6894f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6895{
6896 char_u *word = (char_u *)"";
6897 hlf_T attr = HLF_COUNT;
6898 int len = 0;
6899
6900 if (rettv_list_alloc(rettv) == FAIL)
6901 return;
6902
6903#ifdef FEAT_SPELL
6904 if (argvars[0].v_type == VAR_UNKNOWN)
6905 {
6906 /* Find the start and length of the badly spelled word. */
6907 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
6908 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006909 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006910 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006911 curwin->w_set_curswant = TRUE;
6912 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006913 }
6914 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
6915 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006916 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006917 int capcol = -1;
6918
6919 if (str != NULL)
6920 {
6921 /* Check the argument for spelling. */
6922 while (*str != NUL)
6923 {
6924 len = spell_check(curwin, str, &attr, &capcol, FALSE);
6925 if (attr != HLF_COUNT)
6926 {
6927 word = str;
6928 break;
6929 }
6930 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02006931 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02006932 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006933 }
6934 }
6935 }
6936#endif
6937
6938 list_append_string(rettv->vval.v_list, word, len);
6939 list_append_string(rettv->vval.v_list, (char_u *)(
6940 attr == HLF_SPB ? "bad" :
6941 attr == HLF_SPR ? "rare" :
6942 attr == HLF_SPL ? "local" :
6943 attr == HLF_SPC ? "caps" :
6944 ""), -1);
6945}
6946
6947/*
6948 * "spellsuggest()" function
6949 */
6950 static void
6951f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
6952{
6953#ifdef FEAT_SPELL
6954 char_u *str;
6955 int typeerr = FALSE;
6956 int maxcount;
6957 garray_T ga;
6958 int i;
6959 listitem_T *li;
6960 int need_capital = FALSE;
6961#endif
6962
6963 if (rettv_list_alloc(rettv) == FAIL)
6964 return;
6965
6966#ifdef FEAT_SPELL
6967 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
6968 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006969 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 if (argvars[1].v_type != VAR_UNKNOWN)
6971 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006972 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006973 if (maxcount <= 0)
6974 return;
6975 if (argvars[2].v_type != VAR_UNKNOWN)
6976 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006977 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006978 if (typeerr)
6979 return;
6980 }
6981 }
6982 else
6983 maxcount = 25;
6984
6985 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
6986
6987 for (i = 0; i < ga.ga_len; ++i)
6988 {
6989 str = ((char_u **)ga.ga_data)[i];
6990
6991 li = listitem_alloc();
6992 if (li == NULL)
6993 vim_free(str);
6994 else
6995 {
6996 li->li_tv.v_type = VAR_STRING;
6997 li->li_tv.v_lock = 0;
6998 li->li_tv.vval.v_string = str;
6999 list_append(rettv->vval.v_list, li);
7000 }
7001 }
7002 ga_clear(&ga);
7003 }
7004#endif
7005}
7006
7007 static void
7008f_split(typval_T *argvars, typval_T *rettv)
7009{
7010 char_u *str;
7011 char_u *end;
7012 char_u *pat = NULL;
7013 regmatch_T regmatch;
7014 char_u patbuf[NUMBUFLEN];
7015 char_u *save_cpo;
7016 int match;
7017 colnr_T col = 0;
7018 int keepempty = FALSE;
7019 int typeerr = FALSE;
7020
7021 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7022 save_cpo = p_cpo;
7023 p_cpo = (char_u *)"";
7024
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007025 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007026 if (argvars[1].v_type != VAR_UNKNOWN)
7027 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007028 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007029 if (pat == NULL)
7030 typeerr = TRUE;
7031 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007032 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007033 }
7034 if (pat == NULL || *pat == NUL)
7035 pat = (char_u *)"[\\x01- ]\\+";
7036
7037 if (rettv_list_alloc(rettv) == FAIL)
7038 return;
7039 if (typeerr)
7040 return;
7041
7042 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7043 if (regmatch.regprog != NULL)
7044 {
7045 regmatch.rm_ic = FALSE;
7046 while (*str != NUL || keepempty)
7047 {
7048 if (*str == NUL)
7049 match = FALSE; /* empty item at the end */
7050 else
7051 match = vim_regexec_nl(&regmatch, str, col);
7052 if (match)
7053 end = regmatch.startp[0];
7054 else
7055 end = str + STRLEN(str);
7056 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7057 && *str != NUL && match && end < regmatch.endp[0]))
7058 {
7059 if (list_append_string(rettv->vval.v_list, str,
7060 (int)(end - str)) == FAIL)
7061 break;
7062 }
7063 if (!match)
7064 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007065 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007066 if (regmatch.endp[0] > str)
7067 col = 0;
7068 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007069 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007070 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071 str = regmatch.endp[0];
7072 }
7073
7074 vim_regfree(regmatch.regprog);
7075 }
7076
7077 p_cpo = save_cpo;
7078}
7079
7080#ifdef FEAT_FLOAT
7081/*
7082 * "sqrt()" function
7083 */
7084 static void
7085f_sqrt(typval_T *argvars, typval_T *rettv)
7086{
7087 float_T f = 0.0;
7088
7089 rettv->v_type = VAR_FLOAT;
7090 if (get_float_arg(argvars, &f) == OK)
7091 rettv->vval.v_float = sqrt(f);
7092 else
7093 rettv->vval.v_float = 0.0;
7094}
7095
7096/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007097 * "srand()" function
7098 */
7099 static void
7100f_srand(typval_T *argvars, typval_T *rettv)
7101{
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007102 static int dev_urandom_state = -1; // FAIL or OK once tried
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007103 UINT32_T x = 0, z;
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007104
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007105 if (rettv_list_alloc(rettv) == FAIL)
7106 return;
7107 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007108 {
7109 if (dev_urandom_state != FAIL)
7110 {
7111 int fd = open("/dev/urandom", O_RDONLY);
7112 struct {
7113 union {
7114 UINT32_T number;
7115 char bytes[sizeof(UINT32_T)];
7116 } cont;
7117 } buf;
7118
7119 // Attempt reading /dev/urandom.
7120 if (fd == -1)
7121 dev_urandom_state = FAIL;
7122 else
7123 {
7124 buf.cont.number = 0;
7125 if (read(fd, buf.cont.bytes, sizeof(UINT32_T))
7126 != sizeof(UINT32_T))
7127 dev_urandom_state = FAIL;
7128 else
7129 {
7130 dev_urandom_state = OK;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007131 x = buf.cont.number;
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007132 }
7133 close(fd);
7134 }
7135
7136 }
7137 if (dev_urandom_state != OK)
7138 // Reading /dev/urandom doesn't work, fall back to time().
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007139 x = vim_time();
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007140 }
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007141 else
7142 {
7143 int error = FALSE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007144
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007145 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007146 if (error)
7147 return;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007148 }
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007149
7150#define SPLITMIX32 ( \
7151 z = (x += 0x9e3779b9), \
7152 z = (z ^ (z >> 16)) * 0x85ebca6b, \
7153 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
7154 z ^ (z >> 16) \
7155 )
7156
7157 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7158 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7159 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7160 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007161}
7162
7163/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007164 * "str2float()" function
7165 */
7166 static void
7167f_str2float(typval_T *argvars, typval_T *rettv)
7168{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007169 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007170 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007171
Bram Moolenaar08243d22017-01-10 16:12:29 +01007172 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007173 p = skipwhite(p + 1);
7174 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007175 if (isneg)
7176 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007177 rettv->v_type = VAR_FLOAT;
7178}
7179#endif
7180
7181/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007182 * "str2list()" function
7183 */
7184 static void
7185f_str2list(typval_T *argvars, typval_T *rettv)
7186{
7187 char_u *p;
7188 int utf8 = FALSE;
7189
7190 if (rettv_list_alloc(rettv) == FAIL)
7191 return;
7192
7193 if (argvars[1].v_type != VAR_UNKNOWN)
7194 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7195
7196 p = tv_get_string(&argvars[0]);
7197
7198 if (has_mbyte || utf8)
7199 {
7200 int (*ptr2len)(char_u *);
7201 int (*ptr2char)(char_u *);
7202
7203 if (utf8 || enc_utf8)
7204 {
7205 ptr2len = utf_ptr2len;
7206 ptr2char = utf_ptr2char;
7207 }
7208 else
7209 {
7210 ptr2len = mb_ptr2len;
7211 ptr2char = mb_ptr2char;
7212 }
7213
7214 for ( ; *p != NUL; p += (*ptr2len)(p))
7215 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7216 }
7217 else
7218 for ( ; *p != NUL; ++p)
7219 list_append_number(rettv->vval.v_list, *p);
7220}
7221
7222/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007223 * "str2nr()" function
7224 */
7225 static void
7226f_str2nr(typval_T *argvars, typval_T *rettv)
7227{
7228 int base = 10;
7229 char_u *p;
7230 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007231 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007232 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233
7234 if (argvars[1].v_type != VAR_UNKNOWN)
7235 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007236 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007237 if (base != 2 && base != 8 && base != 10 && base != 16)
7238 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007239 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007240 return;
7241 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007242 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7243 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007244 }
7245
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007246 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007247 isneg = (*p == '-');
7248 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007249 p = skipwhite(p + 1);
7250 switch (base)
7251 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007252 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7253 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7254 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007255 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007256 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7257 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007258 if (isneg)
7259 rettv->vval.v_number = -n;
7260 else
7261 rettv->vval.v_number = n;
7262
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007263}
7264
7265#ifdef HAVE_STRFTIME
7266/*
7267 * "strftime({format}[, {time}])" function
7268 */
7269 static void
7270f_strftime(typval_T *argvars, typval_T *rettv)
7271{
7272 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007273 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007274 struct tm *curtime;
7275 time_t seconds;
7276 char_u *p;
7277
7278 rettv->v_type = VAR_STRING;
7279
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007280 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007281 if (argvars[1].v_type == VAR_UNKNOWN)
7282 seconds = time(NULL);
7283 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007284 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007285 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007286 /* MSVC returns NULL for an invalid value of seconds. */
7287 if (curtime == NULL)
7288 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7289 else
7290 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007291 vimconv_T conv;
7292 char_u *enc;
7293
7294 conv.vc_type = CONV_NONE;
7295 enc = enc_locale();
7296 convert_setup(&conv, p_enc, enc);
7297 if (conv.vc_type != CONV_NONE)
7298 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007299 if (p != NULL)
7300 (void)strftime((char *)result_buf, sizeof(result_buf),
7301 (char *)p, curtime);
7302 else
7303 result_buf[0] = NUL;
7304
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007305 if (conv.vc_type != CONV_NONE)
7306 vim_free(p);
7307 convert_setup(&conv, enc, p_enc);
7308 if (conv.vc_type != CONV_NONE)
7309 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7310 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007311 rettv->vval.v_string = vim_strsave(result_buf);
7312
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007313 /* Release conversion descriptors */
7314 convert_setup(&conv, NULL, NULL);
7315 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007316 }
7317}
7318#endif
7319
7320/*
7321 * "strgetchar()" function
7322 */
7323 static void
7324f_strgetchar(typval_T *argvars, typval_T *rettv)
7325{
7326 char_u *str;
7327 int len;
7328 int error = FALSE;
7329 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007330 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007331
7332 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007333 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007334 if (str == NULL)
7335 return;
7336 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007337 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007338 if (error)
7339 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007340
Bram Moolenaar13505972019-01-24 15:04:48 +01007341 while (charidx >= 0 && byteidx < len)
7342 {
7343 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007345 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7346 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007348 --charidx;
7349 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351}
7352
7353/*
7354 * "stridx()" function
7355 */
7356 static void
7357f_stridx(typval_T *argvars, typval_T *rettv)
7358{
7359 char_u buf[NUMBUFLEN];
7360 char_u *needle;
7361 char_u *haystack;
7362 char_u *save_haystack;
7363 char_u *pos;
7364 int start_idx;
7365
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007366 needle = tv_get_string_chk(&argvars[1]);
7367 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368 rettv->vval.v_number = -1;
7369 if (needle == NULL || haystack == NULL)
7370 return; /* type error; errmsg already given */
7371
7372 if (argvars[2].v_type != VAR_UNKNOWN)
7373 {
7374 int error = FALSE;
7375
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007376 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 if (error || start_idx >= (int)STRLEN(haystack))
7378 return;
7379 if (start_idx >= 0)
7380 haystack += start_idx;
7381 }
7382
7383 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7384 if (pos != NULL)
7385 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7386}
7387
7388/*
7389 * "string()" function
7390 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007391 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392f_string(typval_T *argvars, typval_T *rettv)
7393{
7394 char_u *tofree;
7395 char_u numbuf[NUMBUFLEN];
7396
7397 rettv->v_type = VAR_STRING;
7398 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7399 get_copyID());
7400 /* Make a copy if we have a value but it's not in allocated memory. */
7401 if (rettv->vval.v_string != NULL && tofree == NULL)
7402 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7403}
7404
7405/*
7406 * "strlen()" function
7407 */
7408 static void
7409f_strlen(typval_T *argvars, typval_T *rettv)
7410{
7411 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007412 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007413}
7414
7415/*
7416 * "strchars()" function
7417 */
7418 static void
7419f_strchars(typval_T *argvars, typval_T *rettv)
7420{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007421 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007422 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423 varnumber_T len = 0;
7424 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007425
7426 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007427 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007429 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007430 else
7431 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7433 while (*s != NUL)
7434 {
7435 func_mb_ptr2char_adv(&s);
7436 ++len;
7437 }
7438 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439 }
7440}
7441
7442/*
7443 * "strdisplaywidth()" function
7444 */
7445 static void
7446f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7447{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007448 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007449 int col = 0;
7450
7451 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007452 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007453
7454 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7455}
7456
7457/*
7458 * "strwidth()" function
7459 */
7460 static void
7461f_strwidth(typval_T *argvars, typval_T *rettv)
7462{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007463 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464
Bram Moolenaar13505972019-01-24 15:04:48 +01007465 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007466}
7467
7468/*
7469 * "strcharpart()" function
7470 */
7471 static void
7472f_strcharpart(typval_T *argvars, typval_T *rettv)
7473{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007474 char_u *p;
7475 int nchar;
7476 int nbyte = 0;
7477 int charlen;
7478 int len = 0;
7479 int slen;
7480 int error = FALSE;
7481
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007482 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007483 slen = (int)STRLEN(p);
7484
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007485 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007486 if (!error)
7487 {
7488 if (nchar > 0)
7489 while (nchar > 0 && nbyte < slen)
7490 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007491 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007492 --nchar;
7493 }
7494 else
7495 nbyte = nchar;
7496 if (argvars[2].v_type != VAR_UNKNOWN)
7497 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007498 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007499 while (charlen > 0 && nbyte + len < slen)
7500 {
7501 int off = nbyte + len;
7502
7503 if (off < 0)
7504 len += 1;
7505 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007506 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007507 --charlen;
7508 }
7509 }
7510 else
7511 len = slen - nbyte; /* default: all bytes that are available. */
7512 }
7513
7514 /*
7515 * Only return the overlap between the specified part and the actual
7516 * string.
7517 */
7518 if (nbyte < 0)
7519 {
7520 len += nbyte;
7521 nbyte = 0;
7522 }
7523 else if (nbyte > slen)
7524 nbyte = slen;
7525 if (len < 0)
7526 len = 0;
7527 else if (nbyte + len > slen)
7528 len = slen - nbyte;
7529
7530 rettv->v_type = VAR_STRING;
7531 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007532}
7533
7534/*
7535 * "strpart()" function
7536 */
7537 static void
7538f_strpart(typval_T *argvars, typval_T *rettv)
7539{
7540 char_u *p;
7541 int n;
7542 int len;
7543 int slen;
7544 int error = FALSE;
7545
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007546 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007547 slen = (int)STRLEN(p);
7548
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007549 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007550 if (error)
7551 len = 0;
7552 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007553 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554 else
7555 len = slen - n; /* default len: all bytes that are available. */
7556
7557 /*
7558 * Only return the overlap between the specified part and the actual
7559 * string.
7560 */
7561 if (n < 0)
7562 {
7563 len += n;
7564 n = 0;
7565 }
7566 else if (n > slen)
7567 n = slen;
7568 if (len < 0)
7569 len = 0;
7570 else if (n + len > slen)
7571 len = slen - n;
7572
7573 rettv->v_type = VAR_STRING;
7574 rettv->vval.v_string = vim_strnsave(p + n, len);
7575}
7576
Bram Moolenaar10455d42019-11-21 15:36:18 +01007577#ifdef HAVE_STRPTIME
7578/*
7579 * "strptime({format}, {timestring})" function
7580 */
7581 static void
7582f_strptime(typval_T *argvars, typval_T *rettv)
7583{
7584 struct tm tmval;
7585 char_u *fmt;
7586 char_u *str;
7587 vimconv_T conv;
7588 char_u *enc;
7589
7590 vim_memset(&tmval, NUL, sizeof(tmval));
7591 fmt = tv_get_string(&argvars[0]);
7592 str = tv_get_string(&argvars[1]);
7593
7594 conv.vc_type = CONV_NONE;
7595 enc = enc_locale();
7596 convert_setup(&conv, p_enc, enc);
7597 if (conv.vc_type != CONV_NONE)
7598 fmt = string_convert(&conv, fmt, NULL);
7599 if (fmt == NULL
7600 || strptime((char *)str, (char *)fmt, &tmval) == NULL
7601 || (rettv->vval.v_number = mktime(&tmval)) == -1)
7602 rettv->vval.v_number = 0;
7603
7604 if (conv.vc_type != CONV_NONE)
7605 vim_free(fmt);
7606 convert_setup(&conv, NULL, NULL);
7607 vim_free(enc);
7608}
7609#endif
7610
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007611/*
7612 * "strridx()" function
7613 */
7614 static void
7615f_strridx(typval_T *argvars, typval_T *rettv)
7616{
7617 char_u buf[NUMBUFLEN];
7618 char_u *needle;
7619 char_u *haystack;
7620 char_u *rest;
7621 char_u *lastmatch = NULL;
7622 int haystack_len, end_idx;
7623
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007624 needle = tv_get_string_chk(&argvars[1]);
7625 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626
7627 rettv->vval.v_number = -1;
7628 if (needle == NULL || haystack == NULL)
7629 return; /* type error; errmsg already given */
7630
7631 haystack_len = (int)STRLEN(haystack);
7632 if (argvars[2].v_type != VAR_UNKNOWN)
7633 {
7634 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007635 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007636 if (end_idx < 0)
7637 return; /* can never find a match */
7638 }
7639 else
7640 end_idx = haystack_len;
7641
7642 if (*needle == NUL)
7643 {
7644 /* Empty string matches past the end. */
7645 lastmatch = haystack + end_idx;
7646 }
7647 else
7648 {
7649 for (rest = haystack; *rest != '\0'; ++rest)
7650 {
7651 rest = (char_u *)strstr((char *)rest, (char *)needle);
7652 if (rest == NULL || rest > haystack + end_idx)
7653 break;
7654 lastmatch = rest;
7655 }
7656 }
7657
7658 if (lastmatch == NULL)
7659 rettv->vval.v_number = -1;
7660 else
7661 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7662}
7663
7664/*
7665 * "strtrans()" function
7666 */
7667 static void
7668f_strtrans(typval_T *argvars, typval_T *rettv)
7669{
7670 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007671 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007672}
7673
7674/*
7675 * "submatch()" function
7676 */
7677 static void
7678f_submatch(typval_T *argvars, typval_T *rettv)
7679{
7680 int error = FALSE;
7681 int no;
7682 int retList = 0;
7683
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007684 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007685 if (error)
7686 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007687 if (no < 0 || no >= NSUBEXP)
7688 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007689 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007690 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007691 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007692 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007693 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007694 if (error)
7695 return;
7696
7697 if (retList == 0)
7698 {
7699 rettv->v_type = VAR_STRING;
7700 rettv->vval.v_string = reg_submatch(no);
7701 }
7702 else
7703 {
7704 rettv->v_type = VAR_LIST;
7705 rettv->vval.v_list = reg_submatch_list(no);
7706 }
7707}
7708
7709/*
7710 * "substitute()" function
7711 */
7712 static void
7713f_substitute(typval_T *argvars, typval_T *rettv)
7714{
7715 char_u patbuf[NUMBUFLEN];
7716 char_u subbuf[NUMBUFLEN];
7717 char_u flagsbuf[NUMBUFLEN];
7718
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007719 char_u *str = tv_get_string_chk(&argvars[0]);
7720 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007721 char_u *sub = NULL;
7722 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007723 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007724
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007725 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7726 expr = &argvars[2];
7727 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007728 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007729
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007730 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007731 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7732 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007733 rettv->vval.v_string = NULL;
7734 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007735 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007736}
7737
7738/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007739 * "swapinfo(swap_filename)" function
7740 */
7741 static void
7742f_swapinfo(typval_T *argvars, typval_T *rettv)
7743{
7744 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007745 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007746}
7747
7748/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007749 * "swapname(expr)" function
7750 */
7751 static void
7752f_swapname(typval_T *argvars, typval_T *rettv)
7753{
7754 buf_T *buf;
7755
7756 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007757 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007758 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7759 || buf->b_ml.ml_mfp->mf_fname == NULL)
7760 rettv->vval.v_string = NULL;
7761 else
7762 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7763}
7764
7765/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007766 * "synID(lnum, col, trans)" function
7767 */
7768 static void
7769f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7770{
7771 int id = 0;
7772#ifdef FEAT_SYN_HL
7773 linenr_T lnum;
7774 colnr_T col;
7775 int trans;
7776 int transerr = FALSE;
7777
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007778 lnum = tv_get_lnum(argvars); /* -1 on type error */
7779 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7780 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007781
7782 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7783 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7784 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7785#endif
7786
7787 rettv->vval.v_number = id;
7788}
7789
7790/*
7791 * "synIDattr(id, what [, mode])" function
7792 */
7793 static void
7794f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7795{
7796 char_u *p = NULL;
7797#ifdef FEAT_SYN_HL
7798 int id;
7799 char_u *what;
7800 char_u *mode;
7801 char_u modebuf[NUMBUFLEN];
7802 int modec;
7803
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007804 id = (int)tv_get_number(&argvars[0]);
7805 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007806 if (argvars[2].v_type != VAR_UNKNOWN)
7807 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007808 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007809 modec = TOLOWER_ASC(mode[0]);
7810 if (modec != 't' && modec != 'c' && modec != 'g')
7811 modec = 0; /* replace invalid with current */
7812 }
7813 else
7814 {
7815#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7816 if (USE_24BIT)
7817 modec = 'g';
7818 else
7819#endif
7820 if (t_colors > 1)
7821 modec = 'c';
7822 else
7823 modec = 't';
7824 }
7825
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 switch (TOLOWER_ASC(what[0]))
7827 {
7828 case 'b':
7829 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7830 p = highlight_color(id, what, modec);
7831 else /* bold */
7832 p = highlight_has_attr(id, HL_BOLD, modec);
7833 break;
7834
7835 case 'f': /* fg[#] or font */
7836 p = highlight_color(id, what, modec);
7837 break;
7838
7839 case 'i':
7840 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7841 p = highlight_has_attr(id, HL_INVERSE, modec);
7842 else /* italic */
7843 p = highlight_has_attr(id, HL_ITALIC, modec);
7844 break;
7845
7846 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007847 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848 break;
7849
7850 case 'r': /* reverse */
7851 p = highlight_has_attr(id, HL_INVERSE, modec);
7852 break;
7853
7854 case 's':
7855 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7856 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007857 /* strikeout */
7858 else if (TOLOWER_ASC(what[1]) == 't' &&
7859 TOLOWER_ASC(what[2]) == 'r')
7860 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 else /* standout */
7862 p = highlight_has_attr(id, HL_STANDOUT, modec);
7863 break;
7864
7865 case 'u':
7866 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7867 /* underline */
7868 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7869 else
7870 /* undercurl */
7871 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7872 break;
7873 }
7874
7875 if (p != NULL)
7876 p = vim_strsave(p);
7877#endif
7878 rettv->v_type = VAR_STRING;
7879 rettv->vval.v_string = p;
7880}
7881
7882/*
7883 * "synIDtrans(id)" function
7884 */
7885 static void
7886f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7887{
7888 int id;
7889
7890#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007891 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007892
7893 if (id > 0)
7894 id = syn_get_final_id(id);
7895 else
7896#endif
7897 id = 0;
7898
7899 rettv->vval.v_number = id;
7900}
7901
7902/*
7903 * "synconcealed(lnum, col)" function
7904 */
7905 static void
7906f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7907{
7908#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7909 linenr_T lnum;
7910 colnr_T col;
7911 int syntax_flags = 0;
7912 int cchar;
7913 int matchid = 0;
7914 char_u str[NUMBUFLEN];
7915#endif
7916
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007917 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918
7919#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007920 lnum = tv_get_lnum(argvars); /* -1 on type error */
7921 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007922
7923 vim_memset(str, NUL, sizeof(str));
7924
7925 if (rettv_list_alloc(rettv) != FAIL)
7926 {
7927 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7928 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7929 && curwin->w_p_cole > 0)
7930 {
7931 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7932 syntax_flags = get_syntax_info(&matchid);
7933
7934 /* get the conceal character */
7935 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7936 {
7937 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007938 if (cchar == NUL && curwin->w_p_cole == 1)
7939 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007940 if (cchar != NUL)
7941 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942 if (has_mbyte)
7943 (*mb_char2bytes)(cchar, str);
7944 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007945 str[0] = cchar;
7946 }
7947 }
7948 }
7949
7950 list_append_number(rettv->vval.v_list,
7951 (syntax_flags & HL_CONCEAL) != 0);
7952 /* -1 to auto-determine strlen */
7953 list_append_string(rettv->vval.v_list, str, -1);
7954 list_append_number(rettv->vval.v_list, matchid);
7955 }
7956#endif
7957}
7958
7959/*
7960 * "synstack(lnum, col)" function
7961 */
7962 static void
7963f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7964{
7965#ifdef FEAT_SYN_HL
7966 linenr_T lnum;
7967 colnr_T col;
7968 int i;
7969 int id;
7970#endif
7971
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007972 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007973
7974#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007975 lnum = tv_get_lnum(argvars); /* -1 on type error */
7976 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007977
7978 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7979 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7980 && rettv_list_alloc(rettv) != FAIL)
7981 {
7982 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
7983 for (i = 0; ; ++i)
7984 {
7985 id = syn_get_stack_item(i);
7986 if (id < 0)
7987 break;
7988 if (list_append_number(rettv->vval.v_list, id) == FAIL)
7989 break;
7990 }
7991 }
7992#endif
7993}
7994
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995/*
7996 * "tabpagebuflist()" function
7997 */
7998 static void
7999f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8000{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008001 tabpage_T *tp;
8002 win_T *wp = NULL;
8003
8004 if (argvars[0].v_type == VAR_UNKNOWN)
8005 wp = firstwin;
8006 else
8007 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008008 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009 if (tp != NULL)
8010 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8011 }
8012 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8013 {
8014 for (; wp != NULL; wp = wp->w_next)
8015 if (list_append_number(rettv->vval.v_list,
8016 wp->w_buffer->b_fnum) == FAIL)
8017 break;
8018 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019}
8020
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008021/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008022 * "tagfiles()" function
8023 */
8024 static void
8025f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8026{
8027 char_u *fname;
8028 tagname_T tn;
8029 int first;
8030
8031 if (rettv_list_alloc(rettv) == FAIL)
8032 return;
8033 fname = alloc(MAXPATHL);
8034 if (fname == NULL)
8035 return;
8036
8037 for (first = TRUE; ; first = FALSE)
8038 if (get_tagfname(&tn, first, fname) == FAIL
8039 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8040 break;
8041 tagname_free(&tn);
8042 vim_free(fname);
8043}
8044
8045/*
8046 * "taglist()" function
8047 */
8048 static void
8049f_taglist(typval_T *argvars, typval_T *rettv)
8050{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008051 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008052 char_u *tag_pattern;
8053
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008054 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008055
8056 rettv->vval.v_number = FALSE;
8057 if (*tag_pattern == NUL)
8058 return;
8059
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008060 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008061 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008062 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008063 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008064}
8065
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066#ifdef FEAT_FLOAT
8067/*
8068 * "tan()" function
8069 */
8070 static void
8071f_tan(typval_T *argvars, typval_T *rettv)
8072{
8073 float_T f = 0.0;
8074
8075 rettv->v_type = VAR_FLOAT;
8076 if (get_float_arg(argvars, &f) == OK)
8077 rettv->vval.v_float = tan(f);
8078 else
8079 rettv->vval.v_float = 0.0;
8080}
8081
8082/*
8083 * "tanh()" function
8084 */
8085 static void
8086f_tanh(typval_T *argvars, typval_T *rettv)
8087{
8088 float_T f = 0.0;
8089
8090 rettv->v_type = VAR_FLOAT;
8091 if (get_float_arg(argvars, &f) == OK)
8092 rettv->vval.v_float = tanh(f);
8093 else
8094 rettv->vval.v_float = 0.0;
8095}
8096#endif
8097
8098/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008099 * "tolower(string)" function
8100 */
8101 static void
8102f_tolower(typval_T *argvars, typval_T *rettv)
8103{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008104 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008105 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008106}
8107
8108/*
8109 * "toupper(string)" function
8110 */
8111 static void
8112f_toupper(typval_T *argvars, typval_T *rettv)
8113{
8114 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008115 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116}
8117
8118/*
8119 * "tr(string, fromstr, tostr)" function
8120 */
8121 static void
8122f_tr(typval_T *argvars, typval_T *rettv)
8123{
8124 char_u *in_str;
8125 char_u *fromstr;
8126 char_u *tostr;
8127 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128 int inlen;
8129 int fromlen;
8130 int tolen;
8131 int idx;
8132 char_u *cpstr;
8133 int cplen;
8134 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008135 char_u buf[NUMBUFLEN];
8136 char_u buf2[NUMBUFLEN];
8137 garray_T ga;
8138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008139 in_str = tv_get_string(&argvars[0]);
8140 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8141 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008142
8143 /* Default return value: empty string. */
8144 rettv->v_type = VAR_STRING;
8145 rettv->vval.v_string = NULL;
8146 if (fromstr == NULL || tostr == NULL)
8147 return; /* type error; errmsg already given */
8148 ga_init2(&ga, (int)sizeof(char), 80);
8149
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008150 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008151 /* not multi-byte: fromstr and tostr must be the same length */
8152 if (STRLEN(fromstr) != STRLEN(tostr))
8153 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008154error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008155 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008156 ga_clear(&ga);
8157 return;
8158 }
8159
8160 /* fromstr and tostr have to contain the same number of chars */
8161 while (*in_str != NUL)
8162 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163 if (has_mbyte)
8164 {
8165 inlen = (*mb_ptr2len)(in_str);
8166 cpstr = in_str;
8167 cplen = inlen;
8168 idx = 0;
8169 for (p = fromstr; *p != NUL; p += fromlen)
8170 {
8171 fromlen = (*mb_ptr2len)(p);
8172 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8173 {
8174 for (p = tostr; *p != NUL; p += tolen)
8175 {
8176 tolen = (*mb_ptr2len)(p);
8177 if (idx-- == 0)
8178 {
8179 cplen = tolen;
8180 cpstr = p;
8181 break;
8182 }
8183 }
8184 if (*p == NUL) /* tostr is shorter than fromstr */
8185 goto error;
8186 break;
8187 }
8188 ++idx;
8189 }
8190
8191 if (first && cpstr == in_str)
8192 {
8193 /* Check that fromstr and tostr have the same number of
8194 * (multi-byte) characters. Done only once when a character
8195 * of in_str doesn't appear in fromstr. */
8196 first = FALSE;
8197 for (p = tostr; *p != NUL; p += tolen)
8198 {
8199 tolen = (*mb_ptr2len)(p);
8200 --idx;
8201 }
8202 if (idx != 0)
8203 goto error;
8204 }
8205
8206 (void)ga_grow(&ga, cplen);
8207 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8208 ga.ga_len += cplen;
8209
8210 in_str += inlen;
8211 }
8212 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213 {
8214 /* When not using multi-byte chars we can do it faster. */
8215 p = vim_strchr(fromstr, *in_str);
8216 if (p != NULL)
8217 ga_append(&ga, tostr[p - fromstr]);
8218 else
8219 ga_append(&ga, *in_str);
8220 ++in_str;
8221 }
8222 }
8223
8224 /* add a terminating NUL */
8225 (void)ga_grow(&ga, 1);
8226 ga_append(&ga, NUL);
8227
8228 rettv->vval.v_string = ga.ga_data;
8229}
8230
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008231/*
8232 * "trim({expr})" function
8233 */
8234 static void
8235f_trim(typval_T *argvars, typval_T *rettv)
8236{
8237 char_u buf1[NUMBUFLEN];
8238 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008239 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008240 char_u *mask = NULL;
8241 char_u *tail;
8242 char_u *prev;
8243 char_u *p;
8244 int c1;
8245
8246 rettv->v_type = VAR_STRING;
8247 if (head == NULL)
8248 {
8249 rettv->vval.v_string = NULL;
8250 return;
8251 }
8252
8253 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008254 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008255
8256 while (*head != NUL)
8257 {
8258 c1 = PTR2CHAR(head);
8259 if (mask == NULL)
8260 {
8261 if (c1 > ' ' && c1 != 0xa0)
8262 break;
8263 }
8264 else
8265 {
8266 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8267 if (c1 == PTR2CHAR(p))
8268 break;
8269 if (*p == NUL)
8270 break;
8271 }
8272 MB_PTR_ADV(head);
8273 }
8274
8275 for (tail = head + STRLEN(head); tail > head; tail = prev)
8276 {
8277 prev = tail;
8278 MB_PTR_BACK(head, prev);
8279 c1 = PTR2CHAR(prev);
8280 if (mask == NULL)
8281 {
8282 if (c1 > ' ' && c1 != 0xa0)
8283 break;
8284 }
8285 else
8286 {
8287 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8288 if (c1 == PTR2CHAR(p))
8289 break;
8290 if (*p == NUL)
8291 break;
8292 }
8293 }
8294 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8295}
8296
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008297#ifdef FEAT_FLOAT
8298/*
8299 * "trunc({float})" function
8300 */
8301 static void
8302f_trunc(typval_T *argvars, typval_T *rettv)
8303{
8304 float_T f = 0.0;
8305
8306 rettv->v_type = VAR_FLOAT;
8307 if (get_float_arg(argvars, &f) == OK)
8308 /* trunc() is not in C90, use floor() or ceil() instead. */
8309 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8310 else
8311 rettv->vval.v_float = 0.0;
8312}
8313#endif
8314
8315/*
8316 * "type(expr)" function
8317 */
8318 static void
8319f_type(typval_T *argvars, typval_T *rettv)
8320{
8321 int n = -1;
8322
8323 switch (argvars[0].v_type)
8324 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008325 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8326 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008327 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008328 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8329 case VAR_LIST: n = VAR_TYPE_LIST; break;
8330 case VAR_DICT: n = VAR_TYPE_DICT; break;
8331 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008332 case VAR_SPECIAL:
8333 if (argvars[0].vval.v_number == VVAL_FALSE
8334 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008335 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008336 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008337 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008338 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008339 case VAR_JOB: n = VAR_TYPE_JOB; break;
8340 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008341 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008342 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008343 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008344 n = -1;
8345 break;
8346 }
8347 rettv->vval.v_number = n;
8348}
8349
8350/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008351 * "virtcol(string)" function
8352 */
8353 static void
8354f_virtcol(typval_T *argvars, typval_T *rettv)
8355{
8356 colnr_T vcol = 0;
8357 pos_T *fp;
8358 int fnum = curbuf->b_fnum;
8359
8360 fp = var2fpos(&argvars[0], FALSE, &fnum);
8361 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8362 && fnum == curbuf->b_fnum)
8363 {
8364 getvvcol(curwin, fp, NULL, NULL, &vcol);
8365 ++vcol;
8366 }
8367
8368 rettv->vval.v_number = vcol;
8369}
8370
8371/*
8372 * "visualmode()" function
8373 */
8374 static void
8375f_visualmode(typval_T *argvars, typval_T *rettv)
8376{
8377 char_u str[2];
8378
8379 rettv->v_type = VAR_STRING;
8380 str[0] = curbuf->b_visual_mode_eval;
8381 str[1] = NUL;
8382 rettv->vval.v_string = vim_strsave(str);
8383
8384 /* A non-zero number or non-empty string argument: reset mode. */
8385 if (non_zero_arg(&argvars[0]))
8386 curbuf->b_visual_mode_eval = NUL;
8387}
8388
8389/*
8390 * "wildmenumode()" function
8391 */
8392 static void
8393f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8394{
8395#ifdef FEAT_WILDMENU
8396 if (wild_menu_showing)
8397 rettv->vval.v_number = 1;
8398#endif
8399}
8400
8401/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008402 * "wordcount()" function
8403 */
8404 static void
8405f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8406{
8407 if (rettv_dict_alloc(rettv) == FAIL)
8408 return;
8409 cursor_pos_info(rettv->vval.v_dict);
8410}
8411
8412/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008413 * "xor(expr, expr)" function
8414 */
8415 static void
8416f_xor(typval_T *argvars, typval_T *rettv)
8417{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008418 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8419 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008420}
8421
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008422#endif /* FEAT_EVAL */