blob: a3e5b3e380bd0ef6058e778cc542c99517d02cef [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;
5142 UINT32_T x, y, z, w, t;
5143 static int rand_seed_initialized = FALSE;
5144 static UINT32_T xyzw[4] = {123456789, 362436069, 521288629, 88675123};
5145
5146#define SHUFFLE_XORSHIFT128 \
5147 t = x ^ (x << 11); \
5148 x = y; y = z; z = w; \
5149 w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
5150
5151 if (argvars[0].v_type == VAR_UNKNOWN)
5152 {
5153 // When argument is not given, return random number initialized
5154 // statically.
5155 if (!rand_seed_initialized)
5156 {
5157 xyzw[0] = (varnumber_T)time(NULL);
5158 rand_seed_initialized = TRUE;
5159 }
5160
5161 x = xyzw[0];
5162 y = xyzw[1];
5163 z = xyzw[2];
5164 w = xyzw[3];
5165 SHUFFLE_XORSHIFT128;
5166 xyzw[0] = x;
5167 xyzw[1] = y;
5168 xyzw[2] = z;
5169 xyzw[3] = w;
5170 }
5171 else if (argvars[0].v_type == VAR_LIST)
5172 {
5173 listitem_T *lx, *ly, *lz, *lw;
5174
5175 l = argvars[0].vval.v_list;
5176 if (list_len(l) != 4)
5177 goto theend;
5178
5179 lx = list_find(l, 0L);
5180 ly = list_find(l, 1L);
5181 lz = list_find(l, 2L);
5182 lw = list_find(l, 3L);
5183 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5184 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5185 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5186 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5187 x = (UINT32_T)lx->li_tv.vval.v_number;
5188 y = (UINT32_T)ly->li_tv.vval.v_number;
5189 z = (UINT32_T)lz->li_tv.vval.v_number;
5190 w = (UINT32_T)lw->li_tv.vval.v_number;
5191 SHUFFLE_XORSHIFT128;
5192 lx->li_tv.vval.v_number = (varnumber_T)x;
5193 ly->li_tv.vval.v_number = (varnumber_T)y;
5194 lz->li_tv.vval.v_number = (varnumber_T)z;
5195 lw->li_tv.vval.v_number = (varnumber_T)w;
5196 }
5197 else
5198 goto theend;
5199
5200 rettv->v_type = VAR_NUMBER;
5201 rettv->vval.v_number = (varnumber_T)w;
5202 return;
5203
5204theend:
5205 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
5206}
5207
5208/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209 * "range()" function
5210 */
5211 static void
5212f_range(typval_T *argvars, typval_T *rettv)
5213{
5214 varnumber_T start;
5215 varnumber_T end;
5216 varnumber_T stride = 1;
5217 varnumber_T i;
5218 int error = FALSE;
5219
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005220 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005221 if (argvars[1].v_type == VAR_UNKNOWN)
5222 {
5223 end = start - 1;
5224 start = 0;
5225 }
5226 else
5227 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005228 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005229 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005230 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005231 }
5232
5233 if (error)
5234 return; /* type error; errmsg already given */
5235 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005236 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005237 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005238 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005239 else
5240 {
5241 if (rettv_list_alloc(rettv) == OK)
5242 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5243 if (list_append_number(rettv->vval.v_list,
5244 (varnumber_T)i) == FAIL)
5245 break;
5246 }
5247}
5248
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005249 static void
5250return_register(int regname, typval_T *rettv)
5251{
5252 char_u buf[2] = {0, 0};
5253
5254 buf[0] = (char_u)regname;
5255 rettv->v_type = VAR_STRING;
5256 rettv->vval.v_string = vim_strsave(buf);
5257}
5258
5259/*
5260 * "reg_executing()" function
5261 */
5262 static void
5263f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5264{
5265 return_register(reg_executing, rettv);
5266}
5267
5268/*
5269 * "reg_recording()" function
5270 */
5271 static void
5272f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5273{
5274 return_register(reg_recording, rettv);
5275}
5276
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005277#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005278/*
5279 * Convert a List to proftime_T.
5280 * Return FAIL when there is something wrong.
5281 */
5282 static int
5283list2proftime(typval_T *arg, proftime_T *tm)
5284{
5285 long n1, n2;
5286 int error = FALSE;
5287
5288 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5289 || arg->vval.v_list->lv_len != 2)
5290 return FAIL;
5291 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5292 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005293# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005294 tm->HighPart = n1;
5295 tm->LowPart = n2;
5296# else
5297 tm->tv_sec = n1;
5298 tm->tv_usec = n2;
5299# endif
5300 return error ? FAIL : OK;
5301}
5302#endif /* FEAT_RELTIME */
5303
5304/*
5305 * "reltime()" function
5306 */
5307 static void
5308f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5309{
5310#ifdef FEAT_RELTIME
5311 proftime_T res;
5312 proftime_T start;
5313
5314 if (argvars[0].v_type == VAR_UNKNOWN)
5315 {
5316 /* No arguments: get current time. */
5317 profile_start(&res);
5318 }
5319 else if (argvars[1].v_type == VAR_UNKNOWN)
5320 {
5321 if (list2proftime(&argvars[0], &res) == FAIL)
5322 return;
5323 profile_end(&res);
5324 }
5325 else
5326 {
5327 /* Two arguments: compute the difference. */
5328 if (list2proftime(&argvars[0], &start) == FAIL
5329 || list2proftime(&argvars[1], &res) == FAIL)
5330 return;
5331 profile_sub(&res, &start);
5332 }
5333
5334 if (rettv_list_alloc(rettv) == OK)
5335 {
5336 long n1, n2;
5337
Bram Moolenaar4f974752019-02-17 17:44:42 +01005338# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005339 n1 = res.HighPart;
5340 n2 = res.LowPart;
5341# else
5342 n1 = res.tv_sec;
5343 n2 = res.tv_usec;
5344# endif
5345 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5346 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5347 }
5348#endif
5349}
5350
5351#ifdef FEAT_FLOAT
5352/*
5353 * "reltimefloat()" function
5354 */
5355 static void
5356f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5357{
5358# ifdef FEAT_RELTIME
5359 proftime_T tm;
5360# endif
5361
5362 rettv->v_type = VAR_FLOAT;
5363 rettv->vval.v_float = 0;
5364# ifdef FEAT_RELTIME
5365 if (list2proftime(&argvars[0], &tm) == OK)
5366 rettv->vval.v_float = profile_float(&tm);
5367# endif
5368}
5369#endif
5370
5371/*
5372 * "reltimestr()" function
5373 */
5374 static void
5375f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5376{
5377#ifdef FEAT_RELTIME
5378 proftime_T tm;
5379#endif
5380
5381 rettv->v_type = VAR_STRING;
5382 rettv->vval.v_string = NULL;
5383#ifdef FEAT_RELTIME
5384 if (list2proftime(&argvars[0], &tm) == OK)
5385 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5386#endif
5387}
5388
5389#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005390 static void
5391make_connection(void)
5392{
5393 if (X_DISPLAY == NULL
5394# ifdef FEAT_GUI
5395 && !gui.in_use
5396# endif
5397 )
5398 {
5399 x_force_connect = TRUE;
5400 setup_term_clip();
5401 x_force_connect = FALSE;
5402 }
5403}
5404
5405 static int
5406check_connection(void)
5407{
5408 make_connection();
5409 if (X_DISPLAY == NULL)
5410 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005411 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005412 return FAIL;
5413 }
5414 return OK;
5415}
5416#endif
5417
5418#ifdef FEAT_CLIENTSERVER
5419 static void
5420remote_common(typval_T *argvars, typval_T *rettv, int expr)
5421{
5422 char_u *server_name;
5423 char_u *keys;
5424 char_u *r = NULL;
5425 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005426 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005427# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005428 HWND w;
5429# else
5430 Window w;
5431# endif
5432
5433 if (check_restricted() || check_secure())
5434 return;
5435
5436# ifdef FEAT_X11
5437 if (check_connection() == FAIL)
5438 return;
5439# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005440 if (argvars[2].v_type != VAR_UNKNOWN
5441 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005442 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005443
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005444 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005445 if (server_name == NULL)
5446 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005447 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005448# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005449 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005450# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005451 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5452 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005453# endif
5454 {
5455 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005456 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005457 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005458 vim_free(r);
5459 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005460 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005461 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005462 return;
5463 }
5464
5465 rettv->vval.v_string = r;
5466
5467 if (argvars[2].v_type != VAR_UNKNOWN)
5468 {
5469 dictitem_T v;
5470 char_u str[30];
5471 char_u *idvar;
5472
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005473 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005474 if (idvar != NULL && *idvar != NUL)
5475 {
5476 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5477 v.di_tv.v_type = VAR_STRING;
5478 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005479 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005480 vim_free(v.di_tv.vval.v_string);
5481 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005482 }
5483}
5484#endif
5485
5486/*
5487 * "remote_expr()" function
5488 */
5489 static void
5490f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5491{
5492 rettv->v_type = VAR_STRING;
5493 rettv->vval.v_string = NULL;
5494#ifdef FEAT_CLIENTSERVER
5495 remote_common(argvars, rettv, TRUE);
5496#endif
5497}
5498
5499/*
5500 * "remote_foreground()" function
5501 */
5502 static void
5503f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5504{
5505#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005506# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005507 /* On Win32 it's done in this application. */
5508 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005509 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005510
5511 if (server_name != NULL)
5512 serverForeground(server_name);
5513 }
5514# else
5515 /* Send a foreground() expression to the server. */
5516 argvars[1].v_type = VAR_STRING;
5517 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5518 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005519 rettv->v_type = VAR_STRING;
5520 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005521 remote_common(argvars, rettv, TRUE);
5522 vim_free(argvars[1].vval.v_string);
5523# endif
5524#endif
5525}
5526
5527 static void
5528f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5529{
5530#ifdef FEAT_CLIENTSERVER
5531 dictitem_T v;
5532 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005533# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005534 long_u n = 0;
5535# endif
5536 char_u *serverid;
5537
5538 if (check_restricted() || check_secure())
5539 {
5540 rettv->vval.v_number = -1;
5541 return;
5542 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005543 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544 if (serverid == NULL)
5545 {
5546 rettv->vval.v_number = -1;
5547 return; /* type error; errmsg already given */
5548 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005549# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005550 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5551 if (n == 0)
5552 rettv->vval.v_number = -1;
5553 else
5554 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005555 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005556 rettv->vval.v_number = (s != NULL);
5557 }
5558# else
5559 if (check_connection() == FAIL)
5560 return;
5561
5562 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5563 serverStrToWin(serverid), &s);
5564# endif
5565
5566 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5567 {
5568 char_u *retvar;
5569
5570 v.di_tv.v_type = VAR_STRING;
5571 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005572 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005573 if (retvar != NULL)
5574 set_var(retvar, &v.di_tv, FALSE);
5575 vim_free(v.di_tv.vval.v_string);
5576 }
5577#else
5578 rettv->vval.v_number = -1;
5579#endif
5580}
5581
5582 static void
5583f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5584{
5585 char_u *r = NULL;
5586
5587#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005588 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005589
5590 if (serverid != NULL && !check_restricted() && !check_secure())
5591 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005592 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005593# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005594 /* The server's HWND is encoded in the 'id' parameter */
5595 long_u n = 0;
5596# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005597
5598 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005599 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005600
Bram Moolenaar4f974752019-02-17 17:44:42 +01005601# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005602 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5603 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005604 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005605 if (r == NULL)
5606# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005607 if (check_connection() == FAIL
5608 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5609 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005610# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005611 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005612 }
5613#endif
5614 rettv->v_type = VAR_STRING;
5615 rettv->vval.v_string = r;
5616}
5617
5618/*
5619 * "remote_send()" function
5620 */
5621 static void
5622f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5623{
5624 rettv->v_type = VAR_STRING;
5625 rettv->vval.v_string = NULL;
5626#ifdef FEAT_CLIENTSERVER
5627 remote_common(argvars, rettv, FALSE);
5628#endif
5629}
5630
5631/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005632 * "remote_startserver()" function
5633 */
5634 static void
5635f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5636{
5637#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005638 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005639
5640 if (server == NULL)
5641 return; /* type error; errmsg already given */
5642 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005643 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005644 else
5645 {
5646# ifdef FEAT_X11
5647 if (check_connection() == OK)
5648 serverRegisterName(X_DISPLAY, server);
5649# else
5650 serverSetName(server);
5651# endif
5652 }
5653#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005654 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005655#endif
5656}
5657
5658/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 * "rename({from}, {to})" function
5660 */
5661 static void
5662f_rename(typval_T *argvars, typval_T *rettv)
5663{
5664 char_u buf[NUMBUFLEN];
5665
5666 if (check_restricted() || check_secure())
5667 rettv->vval.v_number = -1;
5668 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005669 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5670 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005671}
5672
5673/*
5674 * "repeat()" function
5675 */
5676 static void
5677f_repeat(typval_T *argvars, typval_T *rettv)
5678{
5679 char_u *p;
5680 int n;
5681 int slen;
5682 int len;
5683 char_u *r;
5684 int i;
5685
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005686 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005687 if (argvars[0].v_type == VAR_LIST)
5688 {
5689 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5690 while (n-- > 0)
5691 if (list_extend(rettv->vval.v_list,
5692 argvars[0].vval.v_list, NULL) == FAIL)
5693 break;
5694 }
5695 else
5696 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005697 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005698 rettv->v_type = VAR_STRING;
5699 rettv->vval.v_string = NULL;
5700
5701 slen = (int)STRLEN(p);
5702 len = slen * n;
5703 if (len <= 0)
5704 return;
5705
5706 r = alloc(len + 1);
5707 if (r != NULL)
5708 {
5709 for (i = 0; i < n; i++)
5710 mch_memmove(r + i * slen, p, (size_t)slen);
5711 r[len] = NUL;
5712 }
5713
5714 rettv->vval.v_string = r;
5715 }
5716}
5717
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005718#define SP_NOMOVE 0x01 /* don't move cursor */
5719#define SP_REPEAT 0x02 /* repeat to find outer pair */
5720#define SP_RETCOUNT 0x04 /* return matchcount */
5721#define SP_SETPCMARK 0x08 /* set previous context mark */
5722#define SP_START 0x10 /* accept match at start position */
5723#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5724#define SP_END 0x40 /* leave cursor at end of match */
5725#define SP_COLUMN 0x80 /* start at cursor column */
5726
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005727/*
5728 * Get flags for a search function.
5729 * Possibly sets "p_ws".
5730 * Returns BACKWARD, FORWARD or zero (for an error).
5731 */
5732 static int
5733get_search_arg(typval_T *varp, int *flagsp)
5734{
5735 int dir = FORWARD;
5736 char_u *flags;
5737 char_u nbuf[NUMBUFLEN];
5738 int mask;
5739
5740 if (varp->v_type != VAR_UNKNOWN)
5741 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005742 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005743 if (flags == NULL)
5744 return 0; /* type error; errmsg already given */
5745 while (*flags != NUL)
5746 {
5747 switch (*flags)
5748 {
5749 case 'b': dir = BACKWARD; break;
5750 case 'w': p_ws = TRUE; break;
5751 case 'W': p_ws = FALSE; break;
5752 default: mask = 0;
5753 if (flagsp != NULL)
5754 switch (*flags)
5755 {
5756 case 'c': mask = SP_START; break;
5757 case 'e': mask = SP_END; break;
5758 case 'm': mask = SP_RETCOUNT; break;
5759 case 'n': mask = SP_NOMOVE; break;
5760 case 'p': mask = SP_SUBPAT; break;
5761 case 'r': mask = SP_REPEAT; break;
5762 case 's': mask = SP_SETPCMARK; break;
5763 case 'z': mask = SP_COLUMN; break;
5764 }
5765 if (mask == 0)
5766 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005767 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005768 dir = 0;
5769 }
5770 else
5771 *flagsp |= mask;
5772 }
5773 if (dir == 0)
5774 break;
5775 ++flags;
5776 }
5777 }
5778 return dir;
5779}
5780
5781/*
5782 * Shared by search() and searchpos() functions.
5783 */
5784 static int
5785search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5786{
5787 int flags;
5788 char_u *pat;
5789 pos_T pos;
5790 pos_T save_cursor;
5791 int save_p_ws = p_ws;
5792 int dir;
5793 int retval = 0; /* default: FAIL */
5794 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005795#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005796 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005797 long time_limit = 0;
5798#endif
5799 int options = SEARCH_KEEP;
5800 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005801 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005802
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005803 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005804 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5805 if (dir == 0)
5806 goto theend;
5807 flags = *flagsp;
5808 if (flags & SP_START)
5809 options |= SEARCH_START;
5810 if (flags & SP_END)
5811 options |= SEARCH_END;
5812 if (flags & SP_COLUMN)
5813 options |= SEARCH_COL;
5814
5815 /* Optional arguments: line number to stop searching and timeout. */
5816 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5817 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005818 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005819 if (lnum_stop < 0)
5820 goto theend;
5821#ifdef FEAT_RELTIME
5822 if (argvars[3].v_type != VAR_UNKNOWN)
5823 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005824 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005825 if (time_limit < 0)
5826 goto theend;
5827 }
5828#endif
5829 }
5830
5831#ifdef FEAT_RELTIME
5832 /* Set the time limit, if there is one. */
5833 profile_setlimit(time_limit, &tm);
5834#endif
5835
5836 /*
5837 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5838 * Check to make sure only those flags are set.
5839 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5840 * flags cannot be set. Check for that condition also.
5841 */
5842 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5843 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5844 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005845 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005846 goto theend;
5847 }
5848
5849 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005850 vim_memset(&sia, 0, sizeof(sia));
5851 sia.sa_stop_lnum = (linenr_T)lnum_stop;
5852#ifdef FEAT_RELTIME
5853 sia.sa_tm = &tm;
5854#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005855 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005856 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005857 if (subpatnum != FAIL)
5858 {
5859 if (flags & SP_SUBPAT)
5860 retval = subpatnum;
5861 else
5862 retval = pos.lnum;
5863 if (flags & SP_SETPCMARK)
5864 setpcmark();
5865 curwin->w_cursor = pos;
5866 if (match_pos != NULL)
5867 {
5868 /* Store the match cursor position */
5869 match_pos->lnum = pos.lnum;
5870 match_pos->col = pos.col + 1;
5871 }
5872 /* "/$" will put the cursor after the end of the line, may need to
5873 * correct that here */
5874 check_cursor();
5875 }
5876
5877 /* If 'n' flag is used: restore cursor position. */
5878 if (flags & SP_NOMOVE)
5879 curwin->w_cursor = save_cursor;
5880 else
5881 curwin->w_set_curswant = TRUE;
5882theend:
5883 p_ws = save_p_ws;
5884
5885 return retval;
5886}
5887
5888#ifdef FEAT_FLOAT
5889
5890/*
5891 * round() is not in C90, use ceil() or floor() instead.
5892 */
5893 float_T
5894vim_round(float_T f)
5895{
5896 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
5897}
5898
5899/*
5900 * "round({float})" function
5901 */
5902 static void
5903f_round(typval_T *argvars, typval_T *rettv)
5904{
5905 float_T f = 0.0;
5906
5907 rettv->v_type = VAR_FLOAT;
5908 if (get_float_arg(argvars, &f) == OK)
5909 rettv->vval.v_float = vim_round(f);
5910 else
5911 rettv->vval.v_float = 0.0;
5912}
5913#endif
5914
Bram Moolenaare99be0e2019-03-26 22:51:09 +01005915#ifdef FEAT_RUBY
5916/*
5917 * "rubyeval()" function
5918 */
5919 static void
5920f_rubyeval(typval_T *argvars, typval_T *rettv)
5921{
5922 char_u *str;
5923 char_u buf[NUMBUFLEN];
5924
5925 str = tv_get_string_buf(&argvars[0], buf);
5926 do_rubyeval(str, rettv);
5927}
5928#endif
5929
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005930/*
5931 * "screenattr()" function
5932 */
5933 static void
5934f_screenattr(typval_T *argvars, typval_T *rettv)
5935{
5936 int row;
5937 int col;
5938 int c;
5939
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005940 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5941 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005942 if (row < 0 || row >= screen_Rows
5943 || col < 0 || col >= screen_Columns)
5944 c = -1;
5945 else
5946 c = ScreenAttrs[LineOffset[row] + col];
5947 rettv->vval.v_number = c;
5948}
5949
5950/*
5951 * "screenchar()" function
5952 */
5953 static void
5954f_screenchar(typval_T *argvars, typval_T *rettv)
5955{
5956 int row;
5957 int col;
5958 int off;
5959 int c;
5960
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005961 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5962 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005963 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005964 c = -1;
5965 else
5966 {
5967 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005968 if (enc_utf8 && ScreenLinesUC[off] != 0)
5969 c = ScreenLinesUC[off];
5970 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005971 c = ScreenLines[off];
5972 }
5973 rettv->vval.v_number = c;
5974}
5975
5976/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005977 * "screenchars()" function
5978 */
5979 static void
5980f_screenchars(typval_T *argvars, typval_T *rettv)
5981{
5982 int row;
5983 int col;
5984 int off;
5985 int c;
5986 int i;
5987
5988 if (rettv_list_alloc(rettv) == FAIL)
5989 return;
5990 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5991 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5992 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5993 return;
5994
5995 off = LineOffset[row] + col;
5996 if (enc_utf8 && ScreenLinesUC[off] != 0)
5997 c = ScreenLinesUC[off];
5998 else
5999 c = ScreenLines[off];
6000 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6001
6002 if (enc_utf8)
6003
6004 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6005 list_append_number(rettv->vval.v_list,
6006 (varnumber_T)ScreenLinesC[i][off]);
6007}
6008
6009/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006010 * "screencol()" function
6011 *
6012 * First column is 1 to be consistent with virtcol().
6013 */
6014 static void
6015f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6016{
6017 rettv->vval.v_number = screen_screencol() + 1;
6018}
6019
6020/*
6021 * "screenrow()" function
6022 */
6023 static void
6024f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6025{
6026 rettv->vval.v_number = screen_screenrow() + 1;
6027}
6028
6029/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006030 * "screenstring()" function
6031 */
6032 static void
6033f_screenstring(typval_T *argvars, typval_T *rettv)
6034{
6035 int row;
6036 int col;
6037 int off;
6038 int c;
6039 int i;
6040 char_u buf[MB_MAXBYTES + 1];
6041 int buflen = 0;
6042
6043 rettv->vval.v_string = NULL;
6044 rettv->v_type = VAR_STRING;
6045
6046 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6047 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6048 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6049 return;
6050
6051 off = LineOffset[row] + col;
6052 if (enc_utf8 && ScreenLinesUC[off] != 0)
6053 c = ScreenLinesUC[off];
6054 else
6055 c = ScreenLines[off];
6056 buflen += mb_char2bytes(c, buf);
6057
6058 if (enc_utf8)
6059 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6060 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6061
6062 buf[buflen] = NUL;
6063 rettv->vval.v_string = vim_strsave(buf);
6064}
6065
6066/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006067 * "search()" function
6068 */
6069 static void
6070f_search(typval_T *argvars, typval_T *rettv)
6071{
6072 int flags = 0;
6073
6074 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6075}
6076
6077/*
6078 * "searchdecl()" function
6079 */
6080 static void
6081f_searchdecl(typval_T *argvars, typval_T *rettv)
6082{
6083 int locally = 1;
6084 int thisblock = 0;
6085 int error = FALSE;
6086 char_u *name;
6087
6088 rettv->vval.v_number = 1; /* default: FAIL */
6089
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006090 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006091 if (argvars[1].v_type != VAR_UNKNOWN)
6092 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006093 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006094 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006095 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006096 }
6097 if (!error && name != NULL)
6098 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6099 locally, thisblock, SEARCH_KEEP) == FAIL;
6100}
6101
6102/*
6103 * Used by searchpair() and searchpairpos()
6104 */
6105 static int
6106searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6107{
6108 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006109 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006110 int save_p_ws = p_ws;
6111 int dir;
6112 int flags = 0;
6113 char_u nbuf1[NUMBUFLEN];
6114 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006115 int retval = 0; /* default: FAIL */
6116 long lnum_stop = 0;
6117 long time_limit = 0;
6118
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006119 /* Get the three pattern arguments: start, middle, end. Will result in an
6120 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006121 spat = tv_get_string_chk(&argvars[0]);
6122 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6123 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006124 if (spat == NULL || mpat == NULL || epat == NULL)
6125 goto theend; /* type error */
6126
6127 /* Handle the optional fourth argument: flags */
6128 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6129 if (dir == 0)
6130 goto theend;
6131
6132 /* Don't accept SP_END or SP_SUBPAT.
6133 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6134 */
6135 if ((flags & (SP_END | SP_SUBPAT)) != 0
6136 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6137 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006138 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006139 goto theend;
6140 }
6141
6142 /* Using 'r' implies 'W', otherwise it doesn't work. */
6143 if (flags & SP_REPEAT)
6144 p_ws = FALSE;
6145
6146 /* Optional fifth argument: skip expression */
6147 if (argvars[3].v_type == VAR_UNKNOWN
6148 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006149 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006150 else
6151 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006152 skip = &argvars[4];
6153 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6154 && skip->v_type != VAR_STRING)
6155 {
6156 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006157 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006158 goto theend;
6159 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006160 if (argvars[5].v_type != VAR_UNKNOWN)
6161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006162 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006163 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006164 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006165 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006166 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006167 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006168#ifdef FEAT_RELTIME
6169 if (argvars[6].v_type != VAR_UNKNOWN)
6170 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006171 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006172 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006173 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006174 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006175 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006176 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006177 }
6178#endif
6179 }
6180 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006181
6182 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6183 match_pos, lnum_stop, time_limit);
6184
6185theend:
6186 p_ws = save_p_ws;
6187
6188 return retval;
6189}
6190
6191/*
6192 * "searchpair()" function
6193 */
6194 static void
6195f_searchpair(typval_T *argvars, typval_T *rettv)
6196{
6197 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6198}
6199
6200/*
6201 * "searchpairpos()" function
6202 */
6203 static void
6204f_searchpairpos(typval_T *argvars, typval_T *rettv)
6205{
6206 pos_T match_pos;
6207 int lnum = 0;
6208 int col = 0;
6209
6210 if (rettv_list_alloc(rettv) == FAIL)
6211 return;
6212
6213 if (searchpair_cmn(argvars, &match_pos) > 0)
6214 {
6215 lnum = match_pos.lnum;
6216 col = match_pos.col;
6217 }
6218
6219 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6220 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6221}
6222
6223/*
6224 * Search for a start/middle/end thing.
6225 * Used by searchpair(), see its documentation for the details.
6226 * Returns 0 or -1 for no match,
6227 */
6228 long
6229do_searchpair(
6230 char_u *spat, /* start pattern */
6231 char_u *mpat, /* middle pattern */
6232 char_u *epat, /* end pattern */
6233 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006234 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006235 int flags, /* SP_SETPCMARK and other SP_ values */
6236 pos_T *match_pos,
6237 linenr_T lnum_stop, /* stop at this line if not zero */
6238 long time_limit UNUSED) /* stop after this many msec */
6239{
6240 char_u *save_cpo;
6241 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6242 long retval = 0;
6243 pos_T pos;
6244 pos_T firstpos;
6245 pos_T foundpos;
6246 pos_T save_cursor;
6247 pos_T save_pos;
6248 int n;
6249 int r;
6250 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006251 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006252 int err;
6253 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006254#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006255 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006256#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006257
6258 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6259 save_cpo = p_cpo;
6260 p_cpo = empty_option;
6261
6262#ifdef FEAT_RELTIME
6263 /* Set the time limit, if there is one. */
6264 profile_setlimit(time_limit, &tm);
6265#endif
6266
6267 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6268 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006269 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6270 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006271 if (pat2 == NULL || pat3 == NULL)
6272 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006273 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006274 if (*mpat == NUL)
6275 STRCPY(pat3, pat2);
6276 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006277 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006278 spat, epat, mpat);
6279 if (flags & SP_START)
6280 options |= SEARCH_START;
6281
Bram Moolenaar48570482017-10-30 21:48:41 +01006282 if (skip != NULL)
6283 {
6284 /* Empty string means to not use the skip expression. */
6285 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6286 use_skip = skip->vval.v_string != NULL
6287 && *skip->vval.v_string != NUL;
6288 }
6289
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 save_cursor = curwin->w_cursor;
6291 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006292 CLEAR_POS(&firstpos);
6293 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006294 pat = pat3;
6295 for (;;)
6296 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006297 searchit_arg_T sia;
6298
6299 vim_memset(&sia, 0, sizeof(sia));
6300 sia.sa_stop_lnum = lnum_stop;
6301#ifdef FEAT_RELTIME
6302 sia.sa_tm = &tm;
6303#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006304 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006305 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006306 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307 /* didn't find it or found the first match again: FAIL */
6308 break;
6309
6310 if (firstpos.lnum == 0)
6311 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006312 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313 {
6314 /* Found the same position again. Can happen with a pattern that
6315 * has "\zs" at the end and searching backwards. Advance one
6316 * character and try again. */
6317 if (dir == BACKWARD)
6318 decl(&pos);
6319 else
6320 incl(&pos);
6321 }
6322 foundpos = pos;
6323
6324 /* clear the start flag to avoid getting stuck here */
6325 options &= ~SEARCH_START;
6326
6327 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006328 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006329 {
6330 save_pos = curwin->w_cursor;
6331 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006332 err = FALSE;
6333 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006334 curwin->w_cursor = save_pos;
6335 if (err)
6336 {
6337 /* Evaluating {skip} caused an error, break here. */
6338 curwin->w_cursor = save_cursor;
6339 retval = -1;
6340 break;
6341 }
6342 if (r)
6343 continue;
6344 }
6345
6346 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6347 {
6348 /* Found end when searching backwards or start when searching
6349 * forward: nested pair. */
6350 ++nest;
6351 pat = pat2; /* nested, don't search for middle */
6352 }
6353 else
6354 {
6355 /* Found end when searching forward or start when searching
6356 * backward: end of (nested) pair; or found middle in outer pair. */
6357 if (--nest == 1)
6358 pat = pat3; /* outer level, search for middle */
6359 }
6360
6361 if (nest == 0)
6362 {
6363 /* Found the match: return matchcount or line number. */
6364 if (flags & SP_RETCOUNT)
6365 ++retval;
6366 else
6367 retval = pos.lnum;
6368 if (flags & SP_SETPCMARK)
6369 setpcmark();
6370 curwin->w_cursor = pos;
6371 if (!(flags & SP_REPEAT))
6372 break;
6373 nest = 1; /* search for next unmatched */
6374 }
6375 }
6376
6377 if (match_pos != NULL)
6378 {
6379 /* Store the match cursor position */
6380 match_pos->lnum = curwin->w_cursor.lnum;
6381 match_pos->col = curwin->w_cursor.col + 1;
6382 }
6383
6384 /* If 'n' flag is used or search failed: restore cursor position. */
6385 if ((flags & SP_NOMOVE) || retval == 0)
6386 curwin->w_cursor = save_cursor;
6387
6388theend:
6389 vim_free(pat2);
6390 vim_free(pat3);
6391 if (p_cpo == empty_option)
6392 p_cpo = save_cpo;
6393 else
6394 /* Darn, evaluating the {skip} expression changed the value. */
6395 free_string_option(save_cpo);
6396
6397 return retval;
6398}
6399
6400/*
6401 * "searchpos()" function
6402 */
6403 static void
6404f_searchpos(typval_T *argvars, typval_T *rettv)
6405{
6406 pos_T match_pos;
6407 int lnum = 0;
6408 int col = 0;
6409 int n;
6410 int flags = 0;
6411
6412 if (rettv_list_alloc(rettv) == FAIL)
6413 return;
6414
6415 n = search_cmn(argvars, &match_pos, &flags);
6416 if (n > 0)
6417 {
6418 lnum = match_pos.lnum;
6419 col = match_pos.col;
6420 }
6421
6422 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6423 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6424 if (flags & SP_SUBPAT)
6425 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6426}
6427
6428 static void
6429f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6430{
6431#ifdef FEAT_CLIENTSERVER
6432 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006433 char_u *server = tv_get_string_chk(&argvars[0]);
6434 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006435
6436 rettv->vval.v_number = -1;
6437 if (server == NULL || reply == NULL)
6438 return;
6439 if (check_restricted() || check_secure())
6440 return;
6441# ifdef FEAT_X11
6442 if (check_connection() == FAIL)
6443 return;
6444# endif
6445
6446 if (serverSendReply(server, reply) < 0)
6447 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006448 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006449 return;
6450 }
6451 rettv->vval.v_number = 0;
6452#else
6453 rettv->vval.v_number = -1;
6454#endif
6455}
6456
6457 static void
6458f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6459{
6460 char_u *r = NULL;
6461
6462#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006463# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006464 r = serverGetVimNames();
6465# else
6466 make_connection();
6467 if (X_DISPLAY != NULL)
6468 r = serverGetVimNames(X_DISPLAY);
6469# endif
6470#endif
6471 rettv->v_type = VAR_STRING;
6472 rettv->vval.v_string = r;
6473}
6474
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475 static void
6476f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6477{
6478 dict_T *d;
6479 dictitem_T *di;
6480 char_u *csearch;
6481
6482 if (argvars[0].v_type != VAR_DICT)
6483 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006484 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006485 return;
6486 }
6487
6488 if ((d = argvars[0].vval.v_dict) != NULL)
6489 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006490 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006491 if (csearch != NULL)
6492 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006493 if (enc_utf8)
6494 {
6495 int pcc[MAX_MCO];
6496 int c = utfc_ptr2char(csearch, pcc);
6497
6498 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6499 }
6500 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006502 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503 }
6504
6505 di = dict_find(d, (char_u *)"forward", -1);
6506 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006507 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508 ? FORWARD : BACKWARD);
6509
6510 di = dict_find(d, (char_u *)"until", -1);
6511 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006512 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006513 }
6514}
6515
6516/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006517 * "setenv()" function
6518 */
6519 static void
6520f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6521{
6522 char_u namebuf[NUMBUFLEN];
6523 char_u valbuf[NUMBUFLEN];
6524 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6525
6526 if (argvars[1].v_type == VAR_SPECIAL
6527 && argvars[1].vval.v_number == VVAL_NULL)
6528 vim_unsetenv(name);
6529 else
6530 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6531}
6532
6533/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006534 * "setfperm({fname}, {mode})" function
6535 */
6536 static void
6537f_setfperm(typval_T *argvars, typval_T *rettv)
6538{
6539 char_u *fname;
6540 char_u modebuf[NUMBUFLEN];
6541 char_u *mode_str;
6542 int i;
6543 int mask;
6544 int mode = 0;
6545
6546 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006547 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006548 if (fname == NULL)
6549 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006550 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006551 if (mode_str == NULL)
6552 return;
6553 if (STRLEN(mode_str) != 9)
6554 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006555 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006556 return;
6557 }
6558
6559 mask = 1;
6560 for (i = 8; i >= 0; --i)
6561 {
6562 if (mode_str[i] != '-')
6563 mode |= mask;
6564 mask = mask << 1;
6565 }
6566 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6567}
6568
6569/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 * "setpos()" function
6571 */
6572 static void
6573f_setpos(typval_T *argvars, typval_T *rettv)
6574{
6575 pos_T pos;
6576 int fnum;
6577 char_u *name;
6578 colnr_T curswant = -1;
6579
6580 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006581 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006582 if (name != NULL)
6583 {
6584 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6585 {
6586 if (--pos.col < 0)
6587 pos.col = 0;
6588 if (name[0] == '.' && name[1] == NUL)
6589 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006590 /* set cursor; "fnum" is ignored */
6591 curwin->w_cursor = pos;
6592 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006593 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006594 curwin->w_curswant = curswant - 1;
6595 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006596 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006597 check_cursor();
6598 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006599 }
6600 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6601 {
6602 /* set mark */
6603 if (setmark_pos(name[1], &pos, fnum) == OK)
6604 rettv->vval.v_number = 0;
6605 }
6606 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006607 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006608 }
6609 }
6610}
6611
6612/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006613 * "setreg()" function
6614 */
6615 static void
6616f_setreg(typval_T *argvars, typval_T *rettv)
6617{
6618 int regname;
6619 char_u *strregname;
6620 char_u *stropt;
6621 char_u *strval;
6622 int append;
6623 char_u yank_type;
6624 long block_len;
6625
6626 block_len = -1;
6627 yank_type = MAUTO;
6628 append = FALSE;
6629
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006630 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006631 rettv->vval.v_number = 1; /* FAIL is default */
6632
6633 if (strregname == NULL)
6634 return; /* type error; errmsg already given */
6635 regname = *strregname;
6636 if (regname == 0 || regname == '@')
6637 regname = '"';
6638
6639 if (argvars[2].v_type != VAR_UNKNOWN)
6640 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006641 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006642 if (stropt == NULL)
6643 return; /* type error */
6644 for (; *stropt != NUL; ++stropt)
6645 switch (*stropt)
6646 {
6647 case 'a': case 'A': /* append */
6648 append = TRUE;
6649 break;
6650 case 'v': case 'c': /* character-wise selection */
6651 yank_type = MCHAR;
6652 break;
6653 case 'V': case 'l': /* line-wise selection */
6654 yank_type = MLINE;
6655 break;
6656 case 'b': case Ctrl_V: /* block-wise selection */
6657 yank_type = MBLOCK;
6658 if (VIM_ISDIGIT(stropt[1]))
6659 {
6660 ++stropt;
6661 block_len = getdigits(&stropt) - 1;
6662 --stropt;
6663 }
6664 break;
6665 }
6666 }
6667
6668 if (argvars[1].v_type == VAR_LIST)
6669 {
6670 char_u **lstval;
6671 char_u **allocval;
6672 char_u buf[NUMBUFLEN];
6673 char_u **curval;
6674 char_u **curallocval;
6675 list_T *ll = argvars[1].vval.v_list;
6676 listitem_T *li;
6677 int len;
6678
6679 /* If the list is NULL handle like an empty list. */
6680 len = ll == NULL ? 0 : ll->lv_len;
6681
6682 /* First half: use for pointers to result lines; second half: use for
6683 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006684 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685 if (lstval == NULL)
6686 return;
6687 curval = lstval;
6688 allocval = lstval + len + 2;
6689 curallocval = allocval;
6690
6691 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6692 li = li->li_next)
6693 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006694 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006695 if (strval == NULL)
6696 goto free_lstval;
6697 if (strval == buf)
6698 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006699 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006700 * overwrite the string. */
6701 strval = vim_strsave(buf);
6702 if (strval == NULL)
6703 goto free_lstval;
6704 *curallocval++ = strval;
6705 }
6706 *curval++ = strval;
6707 }
6708 *curval++ = NULL;
6709
6710 write_reg_contents_lst(regname, lstval, -1,
6711 append, yank_type, block_len);
6712free_lstval:
6713 while (curallocval > allocval)
6714 vim_free(*--curallocval);
6715 vim_free(lstval);
6716 }
6717 else
6718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006719 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006720 if (strval == NULL)
6721 return;
6722 write_reg_contents_ex(regname, strval, -1,
6723 append, yank_type, block_len);
6724 }
6725 rettv->vval.v_number = 0;
6726}
6727
6728/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006729 * "settagstack()" function
6730 */
6731 static void
6732f_settagstack(typval_T *argvars, typval_T *rettv)
6733{
6734 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6735 win_T *wp;
6736 dict_T *d;
6737 int action = 'r';
6738
6739 rettv->vval.v_number = -1;
6740
6741 // first argument: window number or id
6742 wp = find_win_by_nr_or_id(&argvars[0]);
6743 if (wp == NULL)
6744 return;
6745
6746 // second argument: dict with items to set in the tag stack
6747 if (argvars[1].v_type != VAR_DICT)
6748 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006749 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006750 return;
6751 }
6752 d = argvars[1].vval.v_dict;
6753 if (d == NULL)
6754 return;
6755
6756 // third argument: action - 'a' for append and 'r' for replace.
6757 // default is to replace the stack.
6758 if (argvars[2].v_type == VAR_UNKNOWN)
6759 action = 'r';
6760 else if (argvars[2].v_type == VAR_STRING)
6761 {
6762 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006763 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006764 if (actstr == NULL)
6765 return;
6766 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6767 action = *actstr;
6768 else
6769 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006770 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006771 return;
6772 }
6773 }
6774 else
6775 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006776 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006777 return;
6778 }
6779
6780 if (set_tagstack(wp, d, action) == OK)
6781 rettv->vval.v_number = 0;
6782}
6783
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006784#ifdef FEAT_CRYPT
6785/*
6786 * "sha256({string})" function
6787 */
6788 static void
6789f_sha256(typval_T *argvars, typval_T *rettv)
6790{
6791 char_u *p;
6792
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006793 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794 rettv->vval.v_string = vim_strsave(
6795 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6796 rettv->v_type = VAR_STRING;
6797}
6798#endif /* FEAT_CRYPT */
6799
6800/*
6801 * "shellescape({string})" function
6802 */
6803 static void
6804f_shellescape(typval_T *argvars, typval_T *rettv)
6805{
Bram Moolenaar20615522017-06-05 18:46:26 +02006806 int do_special = non_zero_arg(&argvars[1]);
6807
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006808 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006809 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006810 rettv->v_type = VAR_STRING;
6811}
6812
6813/*
6814 * shiftwidth() function
6815 */
6816 static void
6817f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6818{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006819 rettv->vval.v_number = 0;
6820
6821 if (argvars[0].v_type != VAR_UNKNOWN)
6822 {
6823 long col;
6824
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006825 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006826 if (col < 0)
6827 return; // type error; errmsg already given
6828#ifdef FEAT_VARTABS
6829 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6830 return;
6831#endif
6832 }
6833
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006834 rettv->vval.v_number = get_sw_value(curbuf);
6835}
6836
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006837#ifdef FEAT_FLOAT
6838/*
6839 * "sin()" function
6840 */
6841 static void
6842f_sin(typval_T *argvars, typval_T *rettv)
6843{
6844 float_T f = 0.0;
6845
6846 rettv->v_type = VAR_FLOAT;
6847 if (get_float_arg(argvars, &f) == OK)
6848 rettv->vval.v_float = sin(f);
6849 else
6850 rettv->vval.v_float = 0.0;
6851}
6852
6853/*
6854 * "sinh()" function
6855 */
6856 static void
6857f_sinh(typval_T *argvars, typval_T *rettv)
6858{
6859 float_T f = 0.0;
6860
6861 rettv->v_type = VAR_FLOAT;
6862 if (get_float_arg(argvars, &f) == OK)
6863 rettv->vval.v_float = sinh(f);
6864 else
6865 rettv->vval.v_float = 0.0;
6866}
6867#endif
6868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869/*
6870 * "soundfold({word})" function
6871 */
6872 static void
6873f_soundfold(typval_T *argvars, typval_T *rettv)
6874{
6875 char_u *s;
6876
6877 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006878 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006879#ifdef FEAT_SPELL
6880 rettv->vval.v_string = eval_soundfold(s);
6881#else
6882 rettv->vval.v_string = vim_strsave(s);
6883#endif
6884}
6885
6886/*
6887 * "spellbadword()" function
6888 */
6889 static void
6890f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6891{
6892 char_u *word = (char_u *)"";
6893 hlf_T attr = HLF_COUNT;
6894 int len = 0;
6895
6896 if (rettv_list_alloc(rettv) == FAIL)
6897 return;
6898
6899#ifdef FEAT_SPELL
6900 if (argvars[0].v_type == VAR_UNKNOWN)
6901 {
6902 /* Find the start and length of the badly spelled word. */
6903 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
6904 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006905 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006906 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006907 curwin->w_set_curswant = TRUE;
6908 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006909 }
6910 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
6911 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006912 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006913 int capcol = -1;
6914
6915 if (str != NULL)
6916 {
6917 /* Check the argument for spelling. */
6918 while (*str != NUL)
6919 {
6920 len = spell_check(curwin, str, &attr, &capcol, FALSE);
6921 if (attr != HLF_COUNT)
6922 {
6923 word = str;
6924 break;
6925 }
6926 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02006927 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02006928 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006929 }
6930 }
6931 }
6932#endif
6933
6934 list_append_string(rettv->vval.v_list, word, len);
6935 list_append_string(rettv->vval.v_list, (char_u *)(
6936 attr == HLF_SPB ? "bad" :
6937 attr == HLF_SPR ? "rare" :
6938 attr == HLF_SPL ? "local" :
6939 attr == HLF_SPC ? "caps" :
6940 ""), -1);
6941}
6942
6943/*
6944 * "spellsuggest()" function
6945 */
6946 static void
6947f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
6948{
6949#ifdef FEAT_SPELL
6950 char_u *str;
6951 int typeerr = FALSE;
6952 int maxcount;
6953 garray_T ga;
6954 int i;
6955 listitem_T *li;
6956 int need_capital = FALSE;
6957#endif
6958
6959 if (rettv_list_alloc(rettv) == FAIL)
6960 return;
6961
6962#ifdef FEAT_SPELL
6963 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
6964 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006965 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006966 if (argvars[1].v_type != VAR_UNKNOWN)
6967 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006968 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006969 if (maxcount <= 0)
6970 return;
6971 if (argvars[2].v_type != VAR_UNKNOWN)
6972 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006973 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006974 if (typeerr)
6975 return;
6976 }
6977 }
6978 else
6979 maxcount = 25;
6980
6981 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
6982
6983 for (i = 0; i < ga.ga_len; ++i)
6984 {
6985 str = ((char_u **)ga.ga_data)[i];
6986
6987 li = listitem_alloc();
6988 if (li == NULL)
6989 vim_free(str);
6990 else
6991 {
6992 li->li_tv.v_type = VAR_STRING;
6993 li->li_tv.v_lock = 0;
6994 li->li_tv.vval.v_string = str;
6995 list_append(rettv->vval.v_list, li);
6996 }
6997 }
6998 ga_clear(&ga);
6999 }
7000#endif
7001}
7002
7003 static void
7004f_split(typval_T *argvars, typval_T *rettv)
7005{
7006 char_u *str;
7007 char_u *end;
7008 char_u *pat = NULL;
7009 regmatch_T regmatch;
7010 char_u patbuf[NUMBUFLEN];
7011 char_u *save_cpo;
7012 int match;
7013 colnr_T col = 0;
7014 int keepempty = FALSE;
7015 int typeerr = FALSE;
7016
7017 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7018 save_cpo = p_cpo;
7019 p_cpo = (char_u *)"";
7020
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007021 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007022 if (argvars[1].v_type != VAR_UNKNOWN)
7023 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007024 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007025 if (pat == NULL)
7026 typeerr = TRUE;
7027 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007028 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007029 }
7030 if (pat == NULL || *pat == NUL)
7031 pat = (char_u *)"[\\x01- ]\\+";
7032
7033 if (rettv_list_alloc(rettv) == FAIL)
7034 return;
7035 if (typeerr)
7036 return;
7037
7038 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7039 if (regmatch.regprog != NULL)
7040 {
7041 regmatch.rm_ic = FALSE;
7042 while (*str != NUL || keepempty)
7043 {
7044 if (*str == NUL)
7045 match = FALSE; /* empty item at the end */
7046 else
7047 match = vim_regexec_nl(&regmatch, str, col);
7048 if (match)
7049 end = regmatch.startp[0];
7050 else
7051 end = str + STRLEN(str);
7052 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7053 && *str != NUL && match && end < regmatch.endp[0]))
7054 {
7055 if (list_append_string(rettv->vval.v_list, str,
7056 (int)(end - str)) == FAIL)
7057 break;
7058 }
7059 if (!match)
7060 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007061 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007062 if (regmatch.endp[0] > str)
7063 col = 0;
7064 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007065 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007066 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007067 str = regmatch.endp[0];
7068 }
7069
7070 vim_regfree(regmatch.regprog);
7071 }
7072
7073 p_cpo = save_cpo;
7074}
7075
7076#ifdef FEAT_FLOAT
7077/*
7078 * "sqrt()" function
7079 */
7080 static void
7081f_sqrt(typval_T *argvars, typval_T *rettv)
7082{
7083 float_T f = 0.0;
7084
7085 rettv->v_type = VAR_FLOAT;
7086 if (get_float_arg(argvars, &f) == OK)
7087 rettv->vval.v_float = sqrt(f);
7088 else
7089 rettv->vval.v_float = 0.0;
7090}
7091
7092/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007093 * "srand()" function
7094 */
7095 static void
7096f_srand(typval_T *argvars, typval_T *rettv)
7097{
7098 if (rettv_list_alloc(rettv) == FAIL)
7099 return;
7100 if (argvars[0].v_type == VAR_UNKNOWN)
7101 list_append_number(rettv->vval.v_list, (varnumber_T)vim_time());
7102 else
7103 {
7104 int error = FALSE;
7105 UINT32_T x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
7106
7107 if (error)
7108 return;
7109
7110 list_append_number(rettv->vval.v_list, x);
7111 }
7112 list_append_number(rettv->vval.v_list, 362436069);
7113 list_append_number(rettv->vval.v_list, 521288629);
7114 list_append_number(rettv->vval.v_list, 88675123);
7115}
7116
7117/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 * "str2float()" function
7119 */
7120 static void
7121f_str2float(typval_T *argvars, typval_T *rettv)
7122{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007123 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007124 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007125
Bram Moolenaar08243d22017-01-10 16:12:29 +01007126 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007127 p = skipwhite(p + 1);
7128 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007129 if (isneg)
7130 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131 rettv->v_type = VAR_FLOAT;
7132}
7133#endif
7134
7135/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007136 * "str2list()" function
7137 */
7138 static void
7139f_str2list(typval_T *argvars, typval_T *rettv)
7140{
7141 char_u *p;
7142 int utf8 = FALSE;
7143
7144 if (rettv_list_alloc(rettv) == FAIL)
7145 return;
7146
7147 if (argvars[1].v_type != VAR_UNKNOWN)
7148 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7149
7150 p = tv_get_string(&argvars[0]);
7151
7152 if (has_mbyte || utf8)
7153 {
7154 int (*ptr2len)(char_u *);
7155 int (*ptr2char)(char_u *);
7156
7157 if (utf8 || enc_utf8)
7158 {
7159 ptr2len = utf_ptr2len;
7160 ptr2char = utf_ptr2char;
7161 }
7162 else
7163 {
7164 ptr2len = mb_ptr2len;
7165 ptr2char = mb_ptr2char;
7166 }
7167
7168 for ( ; *p != NUL; p += (*ptr2len)(p))
7169 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7170 }
7171 else
7172 for ( ; *p != NUL; ++p)
7173 list_append_number(rettv->vval.v_list, *p);
7174}
7175
7176/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007177 * "str2nr()" function
7178 */
7179 static void
7180f_str2nr(typval_T *argvars, typval_T *rettv)
7181{
7182 int base = 10;
7183 char_u *p;
7184 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007185 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007186 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007187
7188 if (argvars[1].v_type != VAR_UNKNOWN)
7189 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007190 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007191 if (base != 2 && base != 8 && base != 10 && base != 16)
7192 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007193 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007194 return;
7195 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007196 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7197 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007198 }
7199
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007200 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007201 isneg = (*p == '-');
7202 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007203 p = skipwhite(p + 1);
7204 switch (base)
7205 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007206 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7207 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7208 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007209 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007210 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7211 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007212 if (isneg)
7213 rettv->vval.v_number = -n;
7214 else
7215 rettv->vval.v_number = n;
7216
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007217}
7218
7219#ifdef HAVE_STRFTIME
7220/*
7221 * "strftime({format}[, {time}])" function
7222 */
7223 static void
7224f_strftime(typval_T *argvars, typval_T *rettv)
7225{
7226 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007227 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007228 struct tm *curtime;
7229 time_t seconds;
7230 char_u *p;
7231
7232 rettv->v_type = VAR_STRING;
7233
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007234 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007235 if (argvars[1].v_type == VAR_UNKNOWN)
7236 seconds = time(NULL);
7237 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007238 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007239 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007240 /* MSVC returns NULL for an invalid value of seconds. */
7241 if (curtime == NULL)
7242 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7243 else
7244 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007245 vimconv_T conv;
7246 char_u *enc;
7247
7248 conv.vc_type = CONV_NONE;
7249 enc = enc_locale();
7250 convert_setup(&conv, p_enc, enc);
7251 if (conv.vc_type != CONV_NONE)
7252 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007253 if (p != NULL)
7254 (void)strftime((char *)result_buf, sizeof(result_buf),
7255 (char *)p, curtime);
7256 else
7257 result_buf[0] = NUL;
7258
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007259 if (conv.vc_type != CONV_NONE)
7260 vim_free(p);
7261 convert_setup(&conv, enc, p_enc);
7262 if (conv.vc_type != CONV_NONE)
7263 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7264 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007265 rettv->vval.v_string = vim_strsave(result_buf);
7266
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267 /* Release conversion descriptors */
7268 convert_setup(&conv, NULL, NULL);
7269 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007270 }
7271}
7272#endif
7273
7274/*
7275 * "strgetchar()" function
7276 */
7277 static void
7278f_strgetchar(typval_T *argvars, typval_T *rettv)
7279{
7280 char_u *str;
7281 int len;
7282 int error = FALSE;
7283 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007284 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285
7286 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007287 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 if (str == NULL)
7289 return;
7290 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007291 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007292 if (error)
7293 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294
Bram Moolenaar13505972019-01-24 15:04:48 +01007295 while (charidx >= 0 && byteidx < len)
7296 {
7297 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007298 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007299 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7300 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007301 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007302 --charidx;
7303 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007304 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007305}
7306
7307/*
7308 * "stridx()" function
7309 */
7310 static void
7311f_stridx(typval_T *argvars, typval_T *rettv)
7312{
7313 char_u buf[NUMBUFLEN];
7314 char_u *needle;
7315 char_u *haystack;
7316 char_u *save_haystack;
7317 char_u *pos;
7318 int start_idx;
7319
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007320 needle = tv_get_string_chk(&argvars[1]);
7321 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007322 rettv->vval.v_number = -1;
7323 if (needle == NULL || haystack == NULL)
7324 return; /* type error; errmsg already given */
7325
7326 if (argvars[2].v_type != VAR_UNKNOWN)
7327 {
7328 int error = FALSE;
7329
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007330 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007331 if (error || start_idx >= (int)STRLEN(haystack))
7332 return;
7333 if (start_idx >= 0)
7334 haystack += start_idx;
7335 }
7336
7337 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7338 if (pos != NULL)
7339 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7340}
7341
7342/*
7343 * "string()" function
7344 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007345 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007346f_string(typval_T *argvars, typval_T *rettv)
7347{
7348 char_u *tofree;
7349 char_u numbuf[NUMBUFLEN];
7350
7351 rettv->v_type = VAR_STRING;
7352 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7353 get_copyID());
7354 /* Make a copy if we have a value but it's not in allocated memory. */
7355 if (rettv->vval.v_string != NULL && tofree == NULL)
7356 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7357}
7358
7359/*
7360 * "strlen()" function
7361 */
7362 static void
7363f_strlen(typval_T *argvars, typval_T *rettv)
7364{
7365 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007366 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007367}
7368
7369/*
7370 * "strchars()" function
7371 */
7372 static void
7373f_strchars(typval_T *argvars, typval_T *rettv)
7374{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007375 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007376 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377 varnumber_T len = 0;
7378 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007379
7380 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007381 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007383 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007384 else
7385 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007386 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7387 while (*s != NUL)
7388 {
7389 func_mb_ptr2char_adv(&s);
7390 ++len;
7391 }
7392 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007393 }
7394}
7395
7396/*
7397 * "strdisplaywidth()" function
7398 */
7399 static void
7400f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7401{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007402 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007403 int col = 0;
7404
7405 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007406 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407
7408 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7409}
7410
7411/*
7412 * "strwidth()" function
7413 */
7414 static void
7415f_strwidth(typval_T *argvars, typval_T *rettv)
7416{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007417 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007418
Bram Moolenaar13505972019-01-24 15:04:48 +01007419 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007420}
7421
7422/*
7423 * "strcharpart()" function
7424 */
7425 static void
7426f_strcharpart(typval_T *argvars, typval_T *rettv)
7427{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428 char_u *p;
7429 int nchar;
7430 int nbyte = 0;
7431 int charlen;
7432 int len = 0;
7433 int slen;
7434 int error = FALSE;
7435
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007436 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007437 slen = (int)STRLEN(p);
7438
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007439 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 if (!error)
7441 {
7442 if (nchar > 0)
7443 while (nchar > 0 && nbyte < slen)
7444 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007445 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007446 --nchar;
7447 }
7448 else
7449 nbyte = nchar;
7450 if (argvars[2].v_type != VAR_UNKNOWN)
7451 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007452 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007453 while (charlen > 0 && nbyte + len < slen)
7454 {
7455 int off = nbyte + len;
7456
7457 if (off < 0)
7458 len += 1;
7459 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007460 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007461 --charlen;
7462 }
7463 }
7464 else
7465 len = slen - nbyte; /* default: all bytes that are available. */
7466 }
7467
7468 /*
7469 * Only return the overlap between the specified part and the actual
7470 * string.
7471 */
7472 if (nbyte < 0)
7473 {
7474 len += nbyte;
7475 nbyte = 0;
7476 }
7477 else if (nbyte > slen)
7478 nbyte = slen;
7479 if (len < 0)
7480 len = 0;
7481 else if (nbyte + len > slen)
7482 len = slen - nbyte;
7483
7484 rettv->v_type = VAR_STRING;
7485 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007486}
7487
7488/*
7489 * "strpart()" function
7490 */
7491 static void
7492f_strpart(typval_T *argvars, typval_T *rettv)
7493{
7494 char_u *p;
7495 int n;
7496 int len;
7497 int slen;
7498 int error = FALSE;
7499
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007500 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501 slen = (int)STRLEN(p);
7502
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007503 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007504 if (error)
7505 len = 0;
7506 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007507 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007508 else
7509 len = slen - n; /* default len: all bytes that are available. */
7510
7511 /*
7512 * Only return the overlap between the specified part and the actual
7513 * string.
7514 */
7515 if (n < 0)
7516 {
7517 len += n;
7518 n = 0;
7519 }
7520 else if (n > slen)
7521 n = slen;
7522 if (len < 0)
7523 len = 0;
7524 else if (n + len > slen)
7525 len = slen - n;
7526
7527 rettv->v_type = VAR_STRING;
7528 rettv->vval.v_string = vim_strnsave(p + n, len);
7529}
7530
Bram Moolenaar10455d42019-11-21 15:36:18 +01007531#ifdef HAVE_STRPTIME
7532/*
7533 * "strptime({format}, {timestring})" function
7534 */
7535 static void
7536f_strptime(typval_T *argvars, typval_T *rettv)
7537{
7538 struct tm tmval;
7539 char_u *fmt;
7540 char_u *str;
7541 vimconv_T conv;
7542 char_u *enc;
7543
7544 vim_memset(&tmval, NUL, sizeof(tmval));
7545 fmt = tv_get_string(&argvars[0]);
7546 str = tv_get_string(&argvars[1]);
7547
7548 conv.vc_type = CONV_NONE;
7549 enc = enc_locale();
7550 convert_setup(&conv, p_enc, enc);
7551 if (conv.vc_type != CONV_NONE)
7552 fmt = string_convert(&conv, fmt, NULL);
7553 if (fmt == NULL
7554 || strptime((char *)str, (char *)fmt, &tmval) == NULL
7555 || (rettv->vval.v_number = mktime(&tmval)) == -1)
7556 rettv->vval.v_number = 0;
7557
7558 if (conv.vc_type != CONV_NONE)
7559 vim_free(fmt);
7560 convert_setup(&conv, NULL, NULL);
7561 vim_free(enc);
7562}
7563#endif
7564
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007565/*
7566 * "strridx()" function
7567 */
7568 static void
7569f_strridx(typval_T *argvars, typval_T *rettv)
7570{
7571 char_u buf[NUMBUFLEN];
7572 char_u *needle;
7573 char_u *haystack;
7574 char_u *rest;
7575 char_u *lastmatch = NULL;
7576 int haystack_len, end_idx;
7577
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007578 needle = tv_get_string_chk(&argvars[1]);
7579 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007580
7581 rettv->vval.v_number = -1;
7582 if (needle == NULL || haystack == NULL)
7583 return; /* type error; errmsg already given */
7584
7585 haystack_len = (int)STRLEN(haystack);
7586 if (argvars[2].v_type != VAR_UNKNOWN)
7587 {
7588 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007589 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007590 if (end_idx < 0)
7591 return; /* can never find a match */
7592 }
7593 else
7594 end_idx = haystack_len;
7595
7596 if (*needle == NUL)
7597 {
7598 /* Empty string matches past the end. */
7599 lastmatch = haystack + end_idx;
7600 }
7601 else
7602 {
7603 for (rest = haystack; *rest != '\0'; ++rest)
7604 {
7605 rest = (char_u *)strstr((char *)rest, (char *)needle);
7606 if (rest == NULL || rest > haystack + end_idx)
7607 break;
7608 lastmatch = rest;
7609 }
7610 }
7611
7612 if (lastmatch == NULL)
7613 rettv->vval.v_number = -1;
7614 else
7615 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7616}
7617
7618/*
7619 * "strtrans()" function
7620 */
7621 static void
7622f_strtrans(typval_T *argvars, typval_T *rettv)
7623{
7624 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007625 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626}
7627
7628/*
7629 * "submatch()" function
7630 */
7631 static void
7632f_submatch(typval_T *argvars, typval_T *rettv)
7633{
7634 int error = FALSE;
7635 int no;
7636 int retList = 0;
7637
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007638 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007639 if (error)
7640 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007641 if (no < 0 || no >= NSUBEXP)
7642 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007643 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007644 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007645 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007646 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007647 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007648 if (error)
7649 return;
7650
7651 if (retList == 0)
7652 {
7653 rettv->v_type = VAR_STRING;
7654 rettv->vval.v_string = reg_submatch(no);
7655 }
7656 else
7657 {
7658 rettv->v_type = VAR_LIST;
7659 rettv->vval.v_list = reg_submatch_list(no);
7660 }
7661}
7662
7663/*
7664 * "substitute()" function
7665 */
7666 static void
7667f_substitute(typval_T *argvars, typval_T *rettv)
7668{
7669 char_u patbuf[NUMBUFLEN];
7670 char_u subbuf[NUMBUFLEN];
7671 char_u flagsbuf[NUMBUFLEN];
7672
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007673 char_u *str = tv_get_string_chk(&argvars[0]);
7674 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007675 char_u *sub = NULL;
7676 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007677 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007679 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7680 expr = &argvars[2];
7681 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007682 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007683
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007684 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007685 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7686 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007687 rettv->vval.v_string = NULL;
7688 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007689 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007690}
7691
7692/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007693 * "swapinfo(swap_filename)" function
7694 */
7695 static void
7696f_swapinfo(typval_T *argvars, typval_T *rettv)
7697{
7698 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007699 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007700}
7701
7702/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007703 * "swapname(expr)" function
7704 */
7705 static void
7706f_swapname(typval_T *argvars, typval_T *rettv)
7707{
7708 buf_T *buf;
7709
7710 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007711 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007712 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7713 || buf->b_ml.ml_mfp->mf_fname == NULL)
7714 rettv->vval.v_string = NULL;
7715 else
7716 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7717}
7718
7719/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007720 * "synID(lnum, col, trans)" function
7721 */
7722 static void
7723f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7724{
7725 int id = 0;
7726#ifdef FEAT_SYN_HL
7727 linenr_T lnum;
7728 colnr_T col;
7729 int trans;
7730 int transerr = FALSE;
7731
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007732 lnum = tv_get_lnum(argvars); /* -1 on type error */
7733 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7734 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007735
7736 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7737 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7738 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7739#endif
7740
7741 rettv->vval.v_number = id;
7742}
7743
7744/*
7745 * "synIDattr(id, what [, mode])" function
7746 */
7747 static void
7748f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7749{
7750 char_u *p = NULL;
7751#ifdef FEAT_SYN_HL
7752 int id;
7753 char_u *what;
7754 char_u *mode;
7755 char_u modebuf[NUMBUFLEN];
7756 int modec;
7757
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007758 id = (int)tv_get_number(&argvars[0]);
7759 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007760 if (argvars[2].v_type != VAR_UNKNOWN)
7761 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007762 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007763 modec = TOLOWER_ASC(mode[0]);
7764 if (modec != 't' && modec != 'c' && modec != 'g')
7765 modec = 0; /* replace invalid with current */
7766 }
7767 else
7768 {
7769#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7770 if (USE_24BIT)
7771 modec = 'g';
7772 else
7773#endif
7774 if (t_colors > 1)
7775 modec = 'c';
7776 else
7777 modec = 't';
7778 }
7779
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780 switch (TOLOWER_ASC(what[0]))
7781 {
7782 case 'b':
7783 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7784 p = highlight_color(id, what, modec);
7785 else /* bold */
7786 p = highlight_has_attr(id, HL_BOLD, modec);
7787 break;
7788
7789 case 'f': /* fg[#] or font */
7790 p = highlight_color(id, what, modec);
7791 break;
7792
7793 case 'i':
7794 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7795 p = highlight_has_attr(id, HL_INVERSE, modec);
7796 else /* italic */
7797 p = highlight_has_attr(id, HL_ITALIC, modec);
7798 break;
7799
7800 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007801 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007802 break;
7803
7804 case 'r': /* reverse */
7805 p = highlight_has_attr(id, HL_INVERSE, modec);
7806 break;
7807
7808 case 's':
7809 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7810 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007811 /* strikeout */
7812 else if (TOLOWER_ASC(what[1]) == 't' &&
7813 TOLOWER_ASC(what[2]) == 'r')
7814 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007815 else /* standout */
7816 p = highlight_has_attr(id, HL_STANDOUT, modec);
7817 break;
7818
7819 case 'u':
7820 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7821 /* underline */
7822 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7823 else
7824 /* undercurl */
7825 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7826 break;
7827 }
7828
7829 if (p != NULL)
7830 p = vim_strsave(p);
7831#endif
7832 rettv->v_type = VAR_STRING;
7833 rettv->vval.v_string = p;
7834}
7835
7836/*
7837 * "synIDtrans(id)" function
7838 */
7839 static void
7840f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7841{
7842 int id;
7843
7844#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007845 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846
7847 if (id > 0)
7848 id = syn_get_final_id(id);
7849 else
7850#endif
7851 id = 0;
7852
7853 rettv->vval.v_number = id;
7854}
7855
7856/*
7857 * "synconcealed(lnum, col)" function
7858 */
7859 static void
7860f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7861{
7862#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7863 linenr_T lnum;
7864 colnr_T col;
7865 int syntax_flags = 0;
7866 int cchar;
7867 int matchid = 0;
7868 char_u str[NUMBUFLEN];
7869#endif
7870
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007871 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007872
7873#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007874 lnum = tv_get_lnum(argvars); /* -1 on type error */
7875 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007876
7877 vim_memset(str, NUL, sizeof(str));
7878
7879 if (rettv_list_alloc(rettv) != FAIL)
7880 {
7881 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7882 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7883 && curwin->w_p_cole > 0)
7884 {
7885 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7886 syntax_flags = get_syntax_info(&matchid);
7887
7888 /* get the conceal character */
7889 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7890 {
7891 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007892 if (cchar == NUL && curwin->w_p_cole == 1)
7893 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007894 if (cchar != NUL)
7895 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007896 if (has_mbyte)
7897 (*mb_char2bytes)(cchar, str);
7898 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007899 str[0] = cchar;
7900 }
7901 }
7902 }
7903
7904 list_append_number(rettv->vval.v_list,
7905 (syntax_flags & HL_CONCEAL) != 0);
7906 /* -1 to auto-determine strlen */
7907 list_append_string(rettv->vval.v_list, str, -1);
7908 list_append_number(rettv->vval.v_list, matchid);
7909 }
7910#endif
7911}
7912
7913/*
7914 * "synstack(lnum, col)" function
7915 */
7916 static void
7917f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7918{
7919#ifdef FEAT_SYN_HL
7920 linenr_T lnum;
7921 colnr_T col;
7922 int i;
7923 int id;
7924#endif
7925
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007926 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007927
7928#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007929 lnum = tv_get_lnum(argvars); /* -1 on type error */
7930 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931
7932 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7933 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7934 && rettv_list_alloc(rettv) != FAIL)
7935 {
7936 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
7937 for (i = 0; ; ++i)
7938 {
7939 id = syn_get_stack_item(i);
7940 if (id < 0)
7941 break;
7942 if (list_append_number(rettv->vval.v_list, id) == FAIL)
7943 break;
7944 }
7945 }
7946#endif
7947}
7948
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007949/*
7950 * "tabpagebuflist()" function
7951 */
7952 static void
7953f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7954{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007955 tabpage_T *tp;
7956 win_T *wp = NULL;
7957
7958 if (argvars[0].v_type == VAR_UNKNOWN)
7959 wp = firstwin;
7960 else
7961 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007962 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007963 if (tp != NULL)
7964 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
7965 }
7966 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
7967 {
7968 for (; wp != NULL; wp = wp->w_next)
7969 if (list_append_number(rettv->vval.v_list,
7970 wp->w_buffer->b_fnum) == FAIL)
7971 break;
7972 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007973}
7974
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007975/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976 * "tagfiles()" function
7977 */
7978 static void
7979f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
7980{
7981 char_u *fname;
7982 tagname_T tn;
7983 int first;
7984
7985 if (rettv_list_alloc(rettv) == FAIL)
7986 return;
7987 fname = alloc(MAXPATHL);
7988 if (fname == NULL)
7989 return;
7990
7991 for (first = TRUE; ; first = FALSE)
7992 if (get_tagfname(&tn, first, fname) == FAIL
7993 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
7994 break;
7995 tagname_free(&tn);
7996 vim_free(fname);
7997}
7998
7999/*
8000 * "taglist()" function
8001 */
8002 static void
8003f_taglist(typval_T *argvars, typval_T *rettv)
8004{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008005 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008006 char_u *tag_pattern;
8007
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008008 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009
8010 rettv->vval.v_number = FALSE;
8011 if (*tag_pattern == NUL)
8012 return;
8013
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008014 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008015 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008016 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008017 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008018}
8019
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008020#ifdef FEAT_FLOAT
8021/*
8022 * "tan()" function
8023 */
8024 static void
8025f_tan(typval_T *argvars, typval_T *rettv)
8026{
8027 float_T f = 0.0;
8028
8029 rettv->v_type = VAR_FLOAT;
8030 if (get_float_arg(argvars, &f) == OK)
8031 rettv->vval.v_float = tan(f);
8032 else
8033 rettv->vval.v_float = 0.0;
8034}
8035
8036/*
8037 * "tanh()" function
8038 */
8039 static void
8040f_tanh(typval_T *argvars, typval_T *rettv)
8041{
8042 float_T f = 0.0;
8043
8044 rettv->v_type = VAR_FLOAT;
8045 if (get_float_arg(argvars, &f) == OK)
8046 rettv->vval.v_float = tanh(f);
8047 else
8048 rettv->vval.v_float = 0.0;
8049}
8050#endif
8051
8052/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053 * "tolower(string)" function
8054 */
8055 static void
8056f_tolower(typval_T *argvars, typval_T *rettv)
8057{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008058 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008059 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008060}
8061
8062/*
8063 * "toupper(string)" function
8064 */
8065 static void
8066f_toupper(typval_T *argvars, typval_T *rettv)
8067{
8068 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008069 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070}
8071
8072/*
8073 * "tr(string, fromstr, tostr)" function
8074 */
8075 static void
8076f_tr(typval_T *argvars, typval_T *rettv)
8077{
8078 char_u *in_str;
8079 char_u *fromstr;
8080 char_u *tostr;
8081 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082 int inlen;
8083 int fromlen;
8084 int tolen;
8085 int idx;
8086 char_u *cpstr;
8087 int cplen;
8088 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008089 char_u buf[NUMBUFLEN];
8090 char_u buf2[NUMBUFLEN];
8091 garray_T ga;
8092
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008093 in_str = tv_get_string(&argvars[0]);
8094 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8095 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008096
8097 /* Default return value: empty string. */
8098 rettv->v_type = VAR_STRING;
8099 rettv->vval.v_string = NULL;
8100 if (fromstr == NULL || tostr == NULL)
8101 return; /* type error; errmsg already given */
8102 ga_init2(&ga, (int)sizeof(char), 80);
8103
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008104 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008105 /* not multi-byte: fromstr and tostr must be the same length */
8106 if (STRLEN(fromstr) != STRLEN(tostr))
8107 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008108error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008109 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008110 ga_clear(&ga);
8111 return;
8112 }
8113
8114 /* fromstr and tostr have to contain the same number of chars */
8115 while (*in_str != NUL)
8116 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008117 if (has_mbyte)
8118 {
8119 inlen = (*mb_ptr2len)(in_str);
8120 cpstr = in_str;
8121 cplen = inlen;
8122 idx = 0;
8123 for (p = fromstr; *p != NUL; p += fromlen)
8124 {
8125 fromlen = (*mb_ptr2len)(p);
8126 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8127 {
8128 for (p = tostr; *p != NUL; p += tolen)
8129 {
8130 tolen = (*mb_ptr2len)(p);
8131 if (idx-- == 0)
8132 {
8133 cplen = tolen;
8134 cpstr = p;
8135 break;
8136 }
8137 }
8138 if (*p == NUL) /* tostr is shorter than fromstr */
8139 goto error;
8140 break;
8141 }
8142 ++idx;
8143 }
8144
8145 if (first && cpstr == in_str)
8146 {
8147 /* Check that fromstr and tostr have the same number of
8148 * (multi-byte) characters. Done only once when a character
8149 * of in_str doesn't appear in fromstr. */
8150 first = FALSE;
8151 for (p = tostr; *p != NUL; p += tolen)
8152 {
8153 tolen = (*mb_ptr2len)(p);
8154 --idx;
8155 }
8156 if (idx != 0)
8157 goto error;
8158 }
8159
8160 (void)ga_grow(&ga, cplen);
8161 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8162 ga.ga_len += cplen;
8163
8164 in_str += inlen;
8165 }
8166 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008167 {
8168 /* When not using multi-byte chars we can do it faster. */
8169 p = vim_strchr(fromstr, *in_str);
8170 if (p != NULL)
8171 ga_append(&ga, tostr[p - fromstr]);
8172 else
8173 ga_append(&ga, *in_str);
8174 ++in_str;
8175 }
8176 }
8177
8178 /* add a terminating NUL */
8179 (void)ga_grow(&ga, 1);
8180 ga_append(&ga, NUL);
8181
8182 rettv->vval.v_string = ga.ga_data;
8183}
8184
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008185/*
8186 * "trim({expr})" function
8187 */
8188 static void
8189f_trim(typval_T *argvars, typval_T *rettv)
8190{
8191 char_u buf1[NUMBUFLEN];
8192 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008193 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008194 char_u *mask = NULL;
8195 char_u *tail;
8196 char_u *prev;
8197 char_u *p;
8198 int c1;
8199
8200 rettv->v_type = VAR_STRING;
8201 if (head == NULL)
8202 {
8203 rettv->vval.v_string = NULL;
8204 return;
8205 }
8206
8207 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008208 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008209
8210 while (*head != NUL)
8211 {
8212 c1 = PTR2CHAR(head);
8213 if (mask == NULL)
8214 {
8215 if (c1 > ' ' && c1 != 0xa0)
8216 break;
8217 }
8218 else
8219 {
8220 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8221 if (c1 == PTR2CHAR(p))
8222 break;
8223 if (*p == NUL)
8224 break;
8225 }
8226 MB_PTR_ADV(head);
8227 }
8228
8229 for (tail = head + STRLEN(head); tail > head; tail = prev)
8230 {
8231 prev = tail;
8232 MB_PTR_BACK(head, prev);
8233 c1 = PTR2CHAR(prev);
8234 if (mask == NULL)
8235 {
8236 if (c1 > ' ' && c1 != 0xa0)
8237 break;
8238 }
8239 else
8240 {
8241 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8242 if (c1 == PTR2CHAR(p))
8243 break;
8244 if (*p == NUL)
8245 break;
8246 }
8247 }
8248 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8249}
8250
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008251#ifdef FEAT_FLOAT
8252/*
8253 * "trunc({float})" function
8254 */
8255 static void
8256f_trunc(typval_T *argvars, typval_T *rettv)
8257{
8258 float_T f = 0.0;
8259
8260 rettv->v_type = VAR_FLOAT;
8261 if (get_float_arg(argvars, &f) == OK)
8262 /* trunc() is not in C90, use floor() or ceil() instead. */
8263 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8264 else
8265 rettv->vval.v_float = 0.0;
8266}
8267#endif
8268
8269/*
8270 * "type(expr)" function
8271 */
8272 static void
8273f_type(typval_T *argvars, typval_T *rettv)
8274{
8275 int n = -1;
8276
8277 switch (argvars[0].v_type)
8278 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008279 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8280 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008281 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008282 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8283 case VAR_LIST: n = VAR_TYPE_LIST; break;
8284 case VAR_DICT: n = VAR_TYPE_DICT; break;
8285 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008286 case VAR_SPECIAL:
8287 if (argvars[0].vval.v_number == VVAL_FALSE
8288 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008289 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008290 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008291 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008292 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008293 case VAR_JOB: n = VAR_TYPE_JOB; break;
8294 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008295 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008296 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008297 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008298 n = -1;
8299 break;
8300 }
8301 rettv->vval.v_number = n;
8302}
8303
8304/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008305 * "virtcol(string)" function
8306 */
8307 static void
8308f_virtcol(typval_T *argvars, typval_T *rettv)
8309{
8310 colnr_T vcol = 0;
8311 pos_T *fp;
8312 int fnum = curbuf->b_fnum;
8313
8314 fp = var2fpos(&argvars[0], FALSE, &fnum);
8315 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8316 && fnum == curbuf->b_fnum)
8317 {
8318 getvvcol(curwin, fp, NULL, NULL, &vcol);
8319 ++vcol;
8320 }
8321
8322 rettv->vval.v_number = vcol;
8323}
8324
8325/*
8326 * "visualmode()" function
8327 */
8328 static void
8329f_visualmode(typval_T *argvars, typval_T *rettv)
8330{
8331 char_u str[2];
8332
8333 rettv->v_type = VAR_STRING;
8334 str[0] = curbuf->b_visual_mode_eval;
8335 str[1] = NUL;
8336 rettv->vval.v_string = vim_strsave(str);
8337
8338 /* A non-zero number or non-empty string argument: reset mode. */
8339 if (non_zero_arg(&argvars[0]))
8340 curbuf->b_visual_mode_eval = NUL;
8341}
8342
8343/*
8344 * "wildmenumode()" function
8345 */
8346 static void
8347f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8348{
8349#ifdef FEAT_WILDMENU
8350 if (wild_menu_showing)
8351 rettv->vval.v_number = 1;
8352#endif
8353}
8354
8355/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008356 * "wordcount()" function
8357 */
8358 static void
8359f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8360{
8361 if (rettv_dict_alloc(rettv) == FAIL)
8362 return;
8363 cursor_pos_info(rettv->vval.v_dict);
8364}
8365
8366/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008367 * "xor(expr, expr)" function
8368 */
8369 static void
8370f_xor(typval_T *argvars, typval_T *rettv)
8371{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008372 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8373 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008374}
8375
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008376#endif /* FEAT_EVAL */