blob: 5365227612550cc4a10575c610730208603ce924 [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 Moolenaar0387cae2019-11-29 21:07:58 +0100229#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100230static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100231#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200232static void f_str2float(typval_T *argvars, typval_T *rettv);
233#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200234static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200235static void f_str2nr(typval_T *argvars, typval_T *rettv);
236static void f_strchars(typval_T *argvars, typval_T *rettv);
237#ifdef HAVE_STRFTIME
238static void f_strftime(typval_T *argvars, typval_T *rettv);
239#endif
240static void f_strgetchar(typval_T *argvars, typval_T *rettv);
241static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200242static void f_strlen(typval_T *argvars, typval_T *rettv);
243static void f_strcharpart(typval_T *argvars, typval_T *rettv);
244static void f_strpart(typval_T *argvars, typval_T *rettv);
Bram Moolenaar10455d42019-11-21 15:36:18 +0100245#ifdef HAVE_STRPTIME
246static void f_strptime(typval_T *argvars, typval_T *rettv);
247#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248static void f_strridx(typval_T *argvars, typval_T *rettv);
249static void f_strtrans(typval_T *argvars, typval_T *rettv);
250static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
251static void f_strwidth(typval_T *argvars, typval_T *rettv);
252static void f_submatch(typval_T *argvars, typval_T *rettv);
253static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200254static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200255static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256static void f_synID(typval_T *argvars, typval_T *rettv);
257static void f_synIDattr(typval_T *argvars, typval_T *rettv);
258static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
259static void f_synstack(typval_T *argvars, typval_T *rettv);
260static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200262static void f_taglist(typval_T *argvars, typval_T *rettv);
263static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264#ifdef FEAT_FLOAT
265static void f_tan(typval_T *argvars, typval_T *rettv);
266static void f_tanh(typval_T *argvars, typval_T *rettv);
267#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200268static void f_tolower(typval_T *argvars, typval_T *rettv);
269static void f_toupper(typval_T *argvars, typval_T *rettv);
270static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100271static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200272#ifdef FEAT_FLOAT
273static void f_trunc(typval_T *argvars, typval_T *rettv);
274#endif
275static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200276static void f_virtcol(typval_T *argvars, typval_T *rettv);
277static void f_visualmode(typval_T *argvars, typval_T *rettv);
278static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100279static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200280static void f_wordcount(typval_T *argvars, typval_T *rettv);
281static void f_xor(typval_T *argvars, typval_T *rettv);
282
283/*
284 * Array with names and number of arguments of all internal functions
285 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
286 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200287typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200288{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200289 char *f_name; // function name
290 char f_min_argc; // minimal number of arguments
291 char f_max_argc; // maximal number of arguments
292 char f_argtype; // for method: FEARG_ values
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100293 type_T *f_rettype; // return type
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200294 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200295 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200296} funcentry_T;
297
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200298// values for f_argtype; zero means it cannot be used as a method
299#define FEARG_1 1 // base is the first argument
300#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200301#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200302#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200303#define FEARG_LAST 9 // base is the last argument
304
Bram Moolenaarac92e252019-08-03 21:58:38 +0200305static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200306{
307#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100308 {"abs", 1, 1, FEARG_1, &t_any, f_abs},
309 {"acos", 1, 1, FEARG_1, &t_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200310#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100311 {"add", 2, 2, FEARG_1, &t_any, f_add},
312 {"and", 2, 2, FEARG_1, &t_number, f_and},
313 {"append", 2, 2, FEARG_LAST, &t_number, f_append},
314 {"appendbufline", 3, 3, FEARG_LAST, &t_number, f_appendbufline},
315 {"argc", 0, 1, 0, &t_number, f_argc},
316 {"argidx", 0, 0, 0, &t_number, f_argidx},
317 {"arglistid", 0, 2, 0, &t_number, f_arglistid},
318 {"argv", 0, 2, 0, &t_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200319#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100320 {"asin", 1, 1, FEARG_1, &t_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200321#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100322 {"assert_beeps", 1, 2, FEARG_1, &t_number, f_assert_beeps},
323 {"assert_equal", 2, 3, FEARG_2, &t_number, f_assert_equal},
324 {"assert_equalfile", 2, 2, FEARG_1, &t_number, f_assert_equalfile},
325 {"assert_exception", 1, 2, 0, &t_number, f_assert_exception},
326 {"assert_fails", 1, 3, FEARG_1, &t_number, f_assert_fails},
327 {"assert_false", 1, 2, FEARG_1, &t_number, f_assert_false},
328 {"assert_inrange", 3, 4, FEARG_3, &t_number, f_assert_inrange},
329 {"assert_match", 2, 3, FEARG_2, &t_number, f_assert_match},
330 {"assert_notequal", 2, 3, FEARG_2, &t_number, f_assert_notequal},
331 {"assert_notmatch", 2, 3, FEARG_2, &t_number, f_assert_notmatch},
332 {"assert_report", 1, 1, FEARG_1, &t_number, f_assert_report},
333 {"assert_true", 1, 2, FEARG_1, &t_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200334#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100335 {"atan", 1, 1, FEARG_1, &t_float, f_atan},
336 {"atan2", 2, 2, FEARG_1, &t_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200337#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100338#ifdef FEAT_BEVAL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100339 {"balloon_gettext", 0, 0, 0, &t_string, f_balloon_gettext},
340 {"balloon_show", 1, 1, FEARG_1, &t_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100341# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100342 {"balloon_split", 1, 1, FEARG_1, &t_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100343# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100344#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100345 {"browse", 4, 4, 0, &t_string, f_browse},
346 {"browsedir", 2, 2, 0, &t_string, f_browsedir},
347 {"bufadd", 1, 1, FEARG_1, &t_number, f_bufadd},
348 {"bufexists", 1, 1, FEARG_1, &t_number, f_bufexists},
349 {"buffer_exists", 1, 1, FEARG_1, &t_number, f_bufexists}, // obsolete
350 {"buffer_name", 0, 1, FEARG_1, &t_string, f_bufname}, // obsolete
351 {"buffer_number", 0, 1, FEARG_1, &t_number, f_bufnr}, // obsolete
352 {"buflisted", 1, 1, FEARG_1, &t_number, f_buflisted},
353 {"bufload", 1, 1, FEARG_1, &t_void, f_bufload},
354 {"bufloaded", 1, 1, FEARG_1, &t_number, f_bufloaded},
355 {"bufname", 0, 1, FEARG_1, &t_string, f_bufname},
356 {"bufnr", 0, 2, FEARG_1, &t_number, f_bufnr},
357 {"bufwinid", 1, 1, FEARG_1, &t_number, f_bufwinid},
358 {"bufwinnr", 1, 1, FEARG_1, &t_number, f_bufwinnr},
359 {"byte2line", 1, 1, FEARG_1, &t_number, f_byte2line},
360 {"byteidx", 2, 2, FEARG_1, &t_number, f_byteidx},
361 {"byteidxcomp", 2, 2, FEARG_1, &t_number, f_byteidxcomp},
362 {"call", 2, 3, FEARG_1, &t_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200363#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100364 {"ceil", 1, 1, FEARG_1, &t_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200365#endif
366#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100367 {"ch_canread", 1, 1, FEARG_1, &t_number, f_ch_canread},
368 {"ch_close", 1, 1, FEARG_1, &t_void, f_ch_close},
369 {"ch_close_in", 1, 1, FEARG_1, &t_void, f_ch_close_in},
370 {"ch_evalexpr", 2, 3, FEARG_1, &t_any, f_ch_evalexpr},
371 {"ch_evalraw", 2, 3, FEARG_1, &t_any, f_ch_evalraw},
372 {"ch_getbufnr", 2, 2, FEARG_1, &t_number, f_ch_getbufnr},
373 {"ch_getjob", 1, 1, FEARG_1, &t_job, f_ch_getjob},
374 {"ch_info", 1, 1, FEARG_1, &t_dict_any, f_ch_info},
375 {"ch_log", 1, 2, FEARG_1, &t_void, f_ch_log},
376 {"ch_logfile", 1, 2, FEARG_1, &t_void, f_ch_logfile},
377 {"ch_open", 1, 2, FEARG_1, &t_channel, f_ch_open},
378 {"ch_read", 1, 2, FEARG_1, &t_string, f_ch_read},
379 {"ch_readblob", 1, 2, FEARG_1, &t_blob, f_ch_readblob},
380 {"ch_readraw", 1, 2, FEARG_1, &t_string, f_ch_readraw},
381 {"ch_sendexpr", 2, 3, FEARG_1, &t_void, f_ch_sendexpr},
382 {"ch_sendraw", 2, 3, FEARG_1, &t_void, f_ch_sendraw},
383 {"ch_setoptions", 2, 2, FEARG_1, &t_void, f_ch_setoptions},
384 {"ch_status", 1, 2, FEARG_1, &t_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200385#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100386 {"changenr", 0, 0, 0, &t_number, f_changenr},
387 {"char2nr", 1, 2, FEARG_1, &t_number, f_char2nr},
388 {"chdir", 1, 1, FEARG_1, &t_string, f_chdir},
389 {"cindent", 1, 1, FEARG_1, &t_number, f_cindent},
390 {"clearmatches", 0, 1, FEARG_1, &t_void, f_clearmatches},
391 {"col", 1, 1, FEARG_1, &t_number, f_col},
392 {"complete", 2, 2, FEARG_2, &t_void, f_complete},
393 {"complete_add", 1, 1, FEARG_1, &t_number, f_complete_add},
394 {"complete_check", 0, 0, 0, &t_number, f_complete_check},
395 {"complete_info", 0, 1, FEARG_1, &t_dict_any, f_complete_info},
396 {"confirm", 1, 4, FEARG_1, &t_number, f_confirm},
397 {"copy", 1, 1, FEARG_1, &t_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200398#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100399 {"cos", 1, 1, FEARG_1, &t_float, f_cos},
400 {"cosh", 1, 1, FEARG_1, &t_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200401#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100402 {"count", 2, 4, FEARG_1, &t_number, f_count},
403 {"cscope_connection",0,3, 0, &t_number, f_cscope_connection},
404 {"cursor", 1, 3, FEARG_1, &t_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100405#ifdef MSWIN
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100406 {"debugbreak", 1, 1, FEARG_1, &t_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200407#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100408 {"deepcopy", 1, 2, FEARG_1, &t_any, f_deepcopy},
409 {"delete", 1, 2, FEARG_1, &t_number, f_delete},
410 {"deletebufline", 2, 3, FEARG_1, &t_number, f_deletebufline},
411 {"did_filetype", 0, 0, 0, &t_number, f_did_filetype},
412 {"diff_filler", 1, 1, FEARG_1, &t_number, f_diff_filler},
413 {"diff_hlID", 2, 2, FEARG_1, &t_number, f_diff_hlID},
414 {"empty", 1, 1, FEARG_1, &t_number, f_empty},
415 {"environ", 0, 0, 0, &t_dict_string, f_environ},
416 {"escape", 2, 2, FEARG_1, &t_string, f_escape},
417 {"eval", 1, 1, FEARG_1, &t_any, f_eval},
418 {"eventhandler", 0, 0, 0, &t_number, f_eventhandler},
419 {"executable", 1, 1, FEARG_1, &t_number, f_executable},
420 {"execute", 1, 2, FEARG_1, &t_string, f_execute},
421 {"exepath", 1, 1, FEARG_1, &t_string, f_exepath},
422 {"exists", 1, 1, FEARG_1, &t_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200423#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100424 {"exp", 1, 1, FEARG_1, &t_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200425#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100426 {"expand", 1, 3, FEARG_1, &t_any, f_expand},
427 {"expandcmd", 1, 1, FEARG_1, &t_string, f_expandcmd},
428 {"extend", 2, 3, FEARG_1, &t_any, f_extend},
429 {"feedkeys", 1, 2, FEARG_1, &t_void, f_feedkeys},
430 {"file_readable", 1, 1, FEARG_1, &t_number, f_filereadable}, // obsolete
431 {"filereadable", 1, 1, FEARG_1, &t_number, f_filereadable},
432 {"filewritable", 1, 1, FEARG_1, &t_number, f_filewritable},
433 {"filter", 2, 2, FEARG_1, &t_any, f_filter},
434 {"finddir", 1, 3, FEARG_1, &t_string, f_finddir},
435 {"findfile", 1, 3, FEARG_1, &t_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200436#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100437 {"float2nr", 1, 1, FEARG_1, &t_number, f_float2nr},
438 {"floor", 1, 1, FEARG_1, &t_float, f_floor},
439 {"fmod", 2, 2, FEARG_1, &t_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200440#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100441 {"fnameescape", 1, 1, FEARG_1, &t_string, f_fnameescape},
442 {"fnamemodify", 2, 2, FEARG_1, &t_string, f_fnamemodify},
443 {"foldclosed", 1, 1, FEARG_1, &t_number, f_foldclosed},
444 {"foldclosedend", 1, 1, FEARG_1, &t_number, f_foldclosedend},
445 {"foldlevel", 1, 1, FEARG_1, &t_number, f_foldlevel},
446 {"foldtext", 0, 0, 0, &t_string, f_foldtext},
447 {"foldtextresult", 1, 1, FEARG_1, &t_string, f_foldtextresult},
448 {"foreground", 0, 0, 0, &t_void, f_foreground},
449 {"funcref", 1, 3, FEARG_1, &t_any, f_funcref},
450 {"function", 1, 3, FEARG_1, &t_any, f_function},
451 {"garbagecollect", 0, 1, 0, &t_void, f_garbagecollect},
452 {"get", 2, 3, FEARG_1, &t_any, f_get},
453 {"getbufinfo", 0, 1, 0, &t_list_dict_any, f_getbufinfo},
454 {"getbufline", 2, 3, FEARG_1, &t_list_string, f_getbufline},
455 {"getbufvar", 2, 3, FEARG_1, &t_any, f_getbufvar},
456 {"getchangelist", 0, 1, FEARG_1, &t_list_any, f_getchangelist},
457 {"getchar", 0, 1, 0, &t_number, f_getchar},
458 {"getcharmod", 0, 0, 0, &t_number, f_getcharmod},
459 {"getcharsearch", 0, 0, 0, &t_dict_any, f_getcharsearch},
460 {"getcmdline", 0, 0, 0, &t_string, f_getcmdline},
461 {"getcmdpos", 0, 0, 0, &t_number, f_getcmdpos},
462 {"getcmdtype", 0, 0, 0, &t_string, f_getcmdtype},
463 {"getcmdwintype", 0, 0, 0, &t_string, f_getcmdwintype},
464 {"getcompletion", 2, 3, FEARG_1, &t_list_string, f_getcompletion},
465 {"getcurpos", 0, 0, 0, &t_list_number, f_getcurpos},
466 {"getcwd", 0, 2, FEARG_1, &t_string, f_getcwd},
467 {"getenv", 1, 1, FEARG_1, &t_string, f_getenv},
468 {"getfontname", 0, 1, 0, &t_string, f_getfontname},
469 {"getfperm", 1, 1, FEARG_1, &t_string, f_getfperm},
470 {"getfsize", 1, 1, FEARG_1, &t_number, f_getfsize},
471 {"getftime", 1, 1, FEARG_1, &t_number, f_getftime},
472 {"getftype", 1, 1, FEARG_1, &t_string, f_getftype},
473 {"getimstatus", 0, 0, 0, &t_number, f_getimstatus},
474 {"getjumplist", 0, 2, FEARG_1, &t_list_any, f_getjumplist},
475 {"getline", 1, 2, FEARG_1, &t_string, f_getline},
476 {"getloclist", 1, 2, 0, &t_list_dict_any, f_getloclist},
477 {"getmatches", 0, 1, 0, &t_list_dict_any, f_getmatches},
478 {"getmousepos", 0, 0, 0, &t_dict_number, f_getmousepos},
479 {"getpid", 0, 0, 0, &t_number, f_getpid},
480 {"getpos", 1, 1, FEARG_1, &t_list_number, f_getpos},
481 {"getqflist", 0, 1, 0, &t_list_dict_any, f_getqflist},
482 {"getreg", 0, 3, FEARG_1, &t_string, f_getreg},
483 {"getregtype", 0, 1, FEARG_1, &t_string, f_getregtype},
484 {"gettabinfo", 0, 1, FEARG_1, &t_list_dict_any, f_gettabinfo},
485 {"gettabvar", 2, 3, FEARG_1, &t_any, f_gettabvar},
486 {"gettabwinvar", 3, 4, FEARG_1, &t_any, f_gettabwinvar},
487 {"gettagstack", 0, 1, FEARG_1, &t_dict_any, f_gettagstack},
488 {"getwininfo", 0, 1, FEARG_1, &t_list_dict_any, f_getwininfo},
489 {"getwinpos", 0, 1, FEARG_1, &t_list_number, f_getwinpos},
490 {"getwinposx", 0, 0, 0, &t_number, f_getwinposx},
491 {"getwinposy", 0, 0, 0, &t_number, f_getwinposy},
492 {"getwinvar", 2, 3, FEARG_1, &t_any, f_getwinvar},
493 {"glob", 1, 4, FEARG_1, &t_any, f_glob},
494 {"glob2regpat", 1, 1, FEARG_1, &t_string, f_glob2regpat},
495 {"globpath", 2, 5, FEARG_2, &t_any, f_globpath},
496 {"has", 1, 1, 0, &t_number, f_has},
497 {"has_key", 2, 2, FEARG_1, &t_number, f_has_key},
498 {"haslocaldir", 0, 2, FEARG_1, &t_number, f_haslocaldir},
499 {"hasmapto", 1, 3, FEARG_1, &t_number, f_hasmapto},
500 {"highlightID", 1, 1, FEARG_1, &t_number, f_hlID}, // obsolete
501 {"highlight_exists",1, 1, FEARG_1, &t_number, f_hlexists}, // obsolete
502 {"histadd", 2, 2, FEARG_2, &t_number, f_histadd},
503 {"histdel", 1, 2, FEARG_1, &t_number, f_histdel},
504 {"histget", 1, 2, FEARG_1, &t_string, f_histget},
505 {"histnr", 1, 1, FEARG_1, &t_number, f_histnr},
506 {"hlID", 1, 1, FEARG_1, &t_number, f_hlID},
507 {"hlexists", 1, 1, FEARG_1, &t_number, f_hlexists},
508 {"hostname", 0, 0, 0, &t_string, f_hostname},
509 {"iconv", 3, 3, FEARG_1, &t_string, f_iconv},
510 {"indent", 1, 1, FEARG_1, &t_number, f_indent},
511 {"index", 2, 4, FEARG_1, &t_number, f_index},
512 {"input", 1, 3, FEARG_1, &t_string, f_input},
513 {"inputdialog", 1, 3, FEARG_1, &t_string, f_inputdialog},
514 {"inputlist", 1, 1, FEARG_1, &t_number, f_inputlist},
515 {"inputrestore", 0, 0, 0, &t_number, f_inputrestore},
516 {"inputsave", 0, 0, 0, &t_number, f_inputsave},
517 {"inputsecret", 1, 2, FEARG_1, &t_string, f_inputsecret},
518 {"insert", 2, 3, FEARG_1, &t_any, f_insert},
519 {"interrupt", 0, 0, 0, &t_void, f_interrupt},
520 {"invert", 1, 1, FEARG_1, &t_number, f_invert},
521 {"isdirectory", 1, 1, FEARG_1, &t_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200522#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100523 {"isinf", 1, 1, FEARG_1, &t_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200524#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100525 {"islocked", 1, 1, FEARG_1, &t_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100527 {"isnan", 1, 1, FEARG_1, &t_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100529 {"items", 1, 1, FEARG_1, &t_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200530#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100531 {"job_getchannel", 1, 1, FEARG_1, &t_channel, f_job_getchannel},
532 {"job_info", 0, 1, FEARG_1, &t_dict_any, f_job_info},
533 {"job_setoptions", 2, 2, FEARG_1, &t_void, f_job_setoptions},
534 {"job_start", 1, 2, FEARG_1, &t_job, f_job_start},
535 {"job_status", 1, 1, FEARG_1, &t_string, f_job_status},
536 {"job_stop", 1, 2, FEARG_1, &t_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100538 {"join", 1, 2, FEARG_1, &t_string, f_join},
539 {"js_decode", 1, 1, FEARG_1, &t_any, f_js_decode},
540 {"js_encode", 1, 1, FEARG_1, &t_string, f_js_encode},
541 {"json_decode", 1, 1, FEARG_1, &t_any, f_json_decode},
542 {"json_encode", 1, 1, FEARG_1, &t_string, f_json_encode},
543 {"keys", 1, 1, FEARG_1, &t_list_any, f_keys},
544 {"last_buffer_nr", 0, 0, 0, &t_number, f_last_buffer_nr}, // obsolete
545 {"len", 1, 1, FEARG_1, &t_number, f_len},
546 {"libcall", 3, 3, FEARG_3, &t_string, f_libcall},
547 {"libcallnr", 3, 3, FEARG_3, &t_number, f_libcallnr},
548 {"line", 1, 2, FEARG_1, &t_number, f_line},
549 {"line2byte", 1, 1, FEARG_1, &t_number, f_line2byte},
550 {"lispindent", 1, 1, FEARG_1, &t_number, f_lispindent},
551 {"list2str", 1, 2, FEARG_1, &t_string, f_list2str},
552 {"listener_add", 1, 2, FEARG_2, &t_number, f_listener_add},
553 {"listener_flush", 0, 1, FEARG_1, &t_void, f_listener_flush},
554 {"listener_remove", 1, 1, FEARG_1, &t_number, f_listener_remove},
555 {"localtime", 0, 0, 0, &t_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200556#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100557 {"log", 1, 1, FEARG_1, &t_float, f_log},
558 {"log10", 1, 1, FEARG_1, &t_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200559#endif
560#ifdef FEAT_LUA
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100561 {"luaeval", 1, 2, FEARG_1, &t_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200562#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100563 {"map", 2, 2, FEARG_1, &t_any, f_map},
564 {"maparg", 1, 4, FEARG_1, &t_string, f_maparg},
565 {"mapcheck", 1, 3, FEARG_1, &t_string, f_mapcheck},
566 {"match", 2, 4, FEARG_1, &t_any, f_match},
567 {"matchadd", 2, 5, FEARG_1, &t_number, f_matchadd},
568 {"matchaddpos", 2, 5, FEARG_1, &t_number, f_matchaddpos},
569 {"matcharg", 1, 1, FEARG_1, &t_list_string, f_matcharg},
570 {"matchdelete", 1, 2, FEARG_1, &t_number, f_matchdelete},
571 {"matchend", 2, 4, FEARG_1, &t_number, f_matchend},
572 {"matchlist", 2, 4, FEARG_1, &t_list_any, f_matchlist},
573 {"matchstr", 2, 4, FEARG_1, &t_string, f_matchstr},
574 {"matchstrpos", 2, 4, FEARG_1, &t_list_any, f_matchstrpos},
575 {"max", 1, 1, FEARG_1, &t_any, f_max},
576 {"min", 1, 1, FEARG_1, &t_any, f_min},
577 {"mkdir", 1, 3, FEARG_1, &t_number, f_mkdir},
578 {"mode", 0, 1, FEARG_1, &t_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200579#ifdef FEAT_MZSCHEME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100580 {"mzeval", 1, 1, FEARG_1, &t_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200581#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100582 {"nextnonblank", 1, 1, FEARG_1, &t_number, f_nextnonblank},
583 {"nr2char", 1, 2, FEARG_1, &t_string, f_nr2char},
584 {"or", 2, 2, FEARG_1, &t_number, f_or},
585 {"pathshorten", 1, 1, FEARG_1, &t_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200586#ifdef FEAT_PERL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100587 {"perleval", 1, 1, FEARG_1, &t_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200588#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100589#ifdef FEAT_PROP_POPUP
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100590 {"popup_atcursor", 2, 2, FEARG_1, &t_number, f_popup_atcursor},
591 {"popup_beval", 2, 2, FEARG_1, &t_number, f_popup_beval},
592 {"popup_clear", 0, 0, 0, &t_void, f_popup_clear},
593 {"popup_close", 1, 2, FEARG_1, &t_void, f_popup_close},
594 {"popup_create", 2, 2, FEARG_1, &t_number, f_popup_create},
595 {"popup_dialog", 2, 2, FEARG_1, &t_number, f_popup_dialog},
596 {"popup_filter_menu", 2, 2, 0, &t_number, f_popup_filter_menu},
597 {"popup_filter_yesno", 2, 2, 0, &t_number, f_popup_filter_yesno},
598 {"popup_findinfo", 0, 0, 0, &t_number, f_popup_findinfo},
599 {"popup_findpreview", 0, 0, 0, &t_number, f_popup_findpreview},
600 {"popup_getoptions", 1, 1, FEARG_1, &t_dict_any, f_popup_getoptions},
601 {"popup_getpos", 1, 1, FEARG_1, &t_dict_any, f_popup_getpos},
602 {"popup_hide", 1, 1, FEARG_1, &t_void, f_popup_hide},
603 {"popup_locate", 2, 2, 0, &t_number, f_popup_locate},
604 {"popup_menu", 2, 2, FEARG_1, &t_number, f_popup_menu},
605 {"popup_move", 2, 2, FEARG_1, &t_void, f_popup_move},
606 {"popup_notification", 2, 2, FEARG_1, &t_number, f_popup_notification},
607 {"popup_setoptions", 2, 2, FEARG_1, &t_void, f_popup_setoptions},
608 {"popup_settext", 2, 2, FEARG_1, &t_void, f_popup_settext},
609 {"popup_show", 1, 1, FEARG_1, &t_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200610#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200611#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100612 {"pow", 2, 2, FEARG_1, &t_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200613#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100614 {"prevnonblank", 1, 1, FEARG_1, &t_number, f_prevnonblank},
615 {"printf", 1, 19, FEARG_2, &t_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200616#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100617 {"prompt_setcallback", 2, 2, FEARG_1, &t_void, f_prompt_setcallback},
618 {"prompt_setinterrupt", 2, 2, FEARG_1,&t_void, f_prompt_setinterrupt},
619 {"prompt_setprompt", 2, 2, FEARG_1, &t_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200620#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100621#ifdef FEAT_PROP_POPUP
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100622 {"prop_add", 3, 3, FEARG_1, &t_void, f_prop_add},
623 {"prop_clear", 1, 3, FEARG_1, &t_void, f_prop_clear},
624 {"prop_find", 1, 2, FEARG_1, &t_dict_any, f_prop_find},
625 {"prop_list", 1, 2, FEARG_1, &t_list_any, f_prop_list},
626 {"prop_remove", 1, 3, FEARG_1, &t_number, f_prop_remove},
627 {"prop_type_add", 2, 2, FEARG_1, &t_void, f_prop_type_add},
628 {"prop_type_change", 2, 2, FEARG_1, &t_void, f_prop_type_change},
629 {"prop_type_delete", 1, 2, FEARG_1, &t_void, f_prop_type_delete},
630 {"prop_type_get", 1, 2, FEARG_1, &t_dict_any, f_prop_type_get},
631 {"prop_type_list", 0, 1, FEARG_1, &t_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100632#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100633 {"pum_getpos", 0, 0, 0, &t_dict_number, f_pum_getpos},
634 {"pumvisible", 0, 0, 0, &t_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#ifdef FEAT_PYTHON3
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100636 {"py3eval", 1, 1, FEARG_1, &t_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637#endif
638#ifdef FEAT_PYTHON
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100639 {"pyeval", 1, 1, FEARG_1, &t_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100641#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100642 {"pyxeval", 1, 1, FEARG_1, &t_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100643#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100644 {"rand", 0, 1, FEARG_1, &t_number, f_rand},
645 {"range", 1, 3, FEARG_1, &t_list_number, f_range},
646 {"readdir", 1, 2, FEARG_1, &t_list_string, f_readdir},
647 {"readfile", 1, 3, FEARG_1, &t_any, f_readfile},
648 {"reg_executing", 0, 0, 0, &t_string, f_reg_executing},
649 {"reg_recording", 0, 0, 0, &t_string, f_reg_recording},
650 {"reltime", 0, 2, FEARG_1, &t_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200651#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100652 {"reltimefloat", 1, 1, FEARG_1, &t_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100654 {"reltimestr", 1, 1, FEARG_1, &t_string, f_reltimestr},
655 {"remote_expr", 2, 4, FEARG_1, &t_string, f_remote_expr},
656 {"remote_foreground", 1, 1, FEARG_1, &t_string, f_remote_foreground},
657 {"remote_peek", 1, 2, FEARG_1, &t_number, f_remote_peek},
658 {"remote_read", 1, 2, FEARG_1, &t_string, f_remote_read},
659 {"remote_send", 2, 3, FEARG_1, &t_string, f_remote_send},
660 {"remote_startserver", 1, 1, FEARG_1, &t_void, f_remote_startserver},
661 {"remove", 2, 3, FEARG_1, &t_any, f_remove},
662 {"rename", 2, 2, FEARG_1, &t_number, f_rename},
663 {"repeat", 2, 2, FEARG_1, &t_any, f_repeat},
664 {"resolve", 1, 1, FEARG_1, &t_string, f_resolve},
665 {"reverse", 1, 1, FEARG_1, &t_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100667 {"round", 1, 1, FEARG_1, &t_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200668#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100669#ifdef FEAT_RUBY
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100670 {"rubyeval", 1, 1, FEARG_1, &t_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100671#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100672 {"screenattr", 2, 2, FEARG_1, &t_number, f_screenattr},
673 {"screenchar", 2, 2, FEARG_1, &t_number, f_screenchar},
674 {"screenchars", 2, 2, FEARG_1, &t_list_number, f_screenchars},
675 {"screencol", 0, 0, 0, &t_number, f_screencol},
676 {"screenpos", 3, 3, FEARG_1, &t_dict_number, f_screenpos},
677 {"screenrow", 0, 0, 0, &t_number, f_screenrow},
678 {"screenstring", 2, 2, FEARG_1, &t_string, f_screenstring},
679 {"search", 1, 4, FEARG_1, &t_number, f_search},
680 {"searchdecl", 1, 3, FEARG_1, &t_number, f_searchdecl},
681 {"searchpair", 3, 7, 0, &t_number, f_searchpair},
682 {"searchpairpos", 3, 7, 0, &t_list_number, f_searchpairpos},
683 {"searchpos", 1, 4, FEARG_1, &t_list_number, f_searchpos},
684 {"server2client", 2, 2, FEARG_1, &t_number, f_server2client},
685 {"serverlist", 0, 0, 0, &t_string, f_serverlist},
686 {"setbufline", 3, 3, FEARG_3, &t_number, f_setbufline},
687 {"setbufvar", 3, 3, FEARG_3, &t_void, f_setbufvar},
688 {"setcharsearch", 1, 1, FEARG_1, &t_void, f_setcharsearch},
689 {"setcmdpos", 1, 1, FEARG_1, &t_number, f_setcmdpos},
690 {"setenv", 2, 2, FEARG_2, &t_void, f_setenv},
691 {"setfperm", 2, 2, FEARG_1, &t_number, f_setfperm},
692 {"setline", 2, 2, FEARG_2, &t_number, f_setline},
693 {"setloclist", 2, 4, FEARG_2, &t_number, f_setloclist},
694 {"setmatches", 1, 2, FEARG_1, &t_number, f_setmatches},
695 {"setpos", 2, 2, FEARG_2, &t_number, f_setpos},
696 {"setqflist", 1, 3, FEARG_1, &t_number, f_setqflist},
697 {"setreg", 2, 3, FEARG_2, &t_number, f_setreg},
698 {"settabvar", 3, 3, FEARG_3, &t_void, f_settabvar},
699 {"settabwinvar", 4, 4, FEARG_4, &t_void, f_settabwinvar},
700 {"settagstack", 2, 3, FEARG_2, &t_number, f_settagstack},
701 {"setwinvar", 3, 3, FEARG_3, &t_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200702#ifdef FEAT_CRYPT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100703 {"sha256", 1, 1, FEARG_1, &t_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200704#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100705 {"shellescape", 1, 2, FEARG_1, &t_string, f_shellescape},
706 {"shiftwidth", 0, 1, FEARG_1, &t_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100707#ifdef FEAT_SIGNS
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100708 {"sign_define", 1, 2, FEARG_1, &t_any, f_sign_define},
709 {"sign_getdefined", 0, 1, FEARG_1, &t_list_dict_any, f_sign_getdefined},
710 {"sign_getplaced", 0, 2, FEARG_1, &t_list_dict_any, f_sign_getplaced},
711 {"sign_jump", 3, 3, FEARG_1, &t_number, f_sign_jump},
712 {"sign_place", 4, 5, FEARG_1, &t_number, f_sign_place},
713 {"sign_placelist", 1, 1, FEARG_1, &t_list_number, f_sign_placelist},
714 {"sign_undefine", 0, 1, FEARG_1, &t_number, f_sign_undefine},
715 {"sign_unplace", 1, 2, FEARG_1, &t_number, f_sign_unplace},
716 {"sign_unplacelist", 1, 2, FEARG_1, &t_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100717#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100718 {"simplify", 1, 1, 0, &t_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200719#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100720 {"sin", 1, 1, FEARG_1, &t_float, f_sin},
721 {"sinh", 1, 1, FEARG_1, &t_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200722#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100723 {"sort", 1, 3, FEARG_1, &t_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200724#ifdef FEAT_SOUND
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100725 {"sound_clear", 0, 0, 0, &t_void, f_sound_clear},
726 {"sound_playevent", 1, 2, FEARG_1, &t_number, f_sound_playevent},
727 {"sound_playfile", 1, 2, FEARG_1, &t_number, f_sound_playfile},
728 {"sound_stop", 1, 1, FEARG_1, &t_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200729#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100730 {"soundfold", 1, 1, FEARG_1, &t_string, f_soundfold},
731 {"spellbadword", 0, 1, FEARG_1, &t_list_string, f_spellbadword},
732 {"spellsuggest", 1, 3, FEARG_1, &t_list_string, f_spellsuggest},
733 {"split", 1, 3, FEARG_1, &t_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200734#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100735 {"sqrt", 1, 1, FEARG_1, &t_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200736#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100737 {"srand", 0, 1, FEARG_1, &t_list_number, f_srand},
738 {"state", 0, 1, FEARG_1, &t_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200739#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100740 {"str2float", 1, 1, FEARG_1, &t_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200741#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100742 {"str2list", 1, 2, FEARG_1, &t_list_number, f_str2list},
743 {"str2nr", 1, 3, FEARG_1, &t_number, f_str2nr},
744 {"strcharpart", 2, 3, FEARG_1, &t_string, f_strcharpart},
745 {"strchars", 1, 2, FEARG_1, &t_number, f_strchars},
746 {"strdisplaywidth", 1, 2, FEARG_1, &t_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200747#ifdef HAVE_STRFTIME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100748 {"strftime", 1, 2, FEARG_1, &t_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200749#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100750 {"strgetchar", 2, 2, FEARG_1, &t_number, f_strgetchar},
751 {"stridx", 2, 3, FEARG_1, &t_number, f_stridx},
752 {"string", 1, 1, FEARG_1, &t_string, f_string},
753 {"strlen", 1, 1, FEARG_1, &t_number, f_strlen},
754 {"strpart", 2, 3, FEARG_1, &t_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100755#ifdef HAVE_STRPTIME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100756 {"strptime", 2, 2, FEARG_1, &t_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100757#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100758 {"strridx", 2, 3, FEARG_1, &t_number, f_strridx},
759 {"strtrans", 1, 1, FEARG_1, &t_string, f_strtrans},
760 {"strwidth", 1, 1, FEARG_1, &t_number, f_strwidth},
761 {"submatch", 1, 2, FEARG_1, &t_string, f_submatch},
762 {"substitute", 4, 4, FEARG_1, &t_string, f_substitute},
763 {"swapinfo", 1, 1, FEARG_1, &t_dict_any, f_swapinfo},
764 {"swapname", 1, 1, FEARG_1, &t_string, f_swapname},
765 {"synID", 3, 3, 0, &t_number, f_synID},
766 {"synIDattr", 2, 3, FEARG_1, &t_string, f_synIDattr},
767 {"synIDtrans", 1, 1, FEARG_1, &t_number, f_synIDtrans},
768 {"synconcealed", 2, 2, 0, &t_list_any, f_synconcealed},
769 {"synstack", 2, 2, 0, &t_list_number, f_synstack},
770 {"system", 1, 2, FEARG_1, &t_string, f_system},
771 {"systemlist", 1, 2, FEARG_1, &t_list_string, f_systemlist},
772 {"tabpagebuflist", 0, 1, FEARG_1, &t_list_number, f_tabpagebuflist},
773 {"tabpagenr", 0, 1, 0, &t_number, f_tabpagenr},
774 {"tabpagewinnr", 1, 2, FEARG_1, &t_number, f_tabpagewinnr},
775 {"tagfiles", 0, 0, 0, &t_list_string, f_tagfiles},
776 {"taglist", 1, 2, FEARG_1, &t_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200777#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100778 {"tan", 1, 1, FEARG_1, &t_float, f_tan},
779 {"tanh", 1, 1, FEARG_1, &t_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200780#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100781 {"tempname", 0, 0, 0, &t_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200782#ifdef FEAT_TERMINAL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100783 {"term_dumpdiff", 2, 3, FEARG_1, &t_number, f_term_dumpdiff},
784 {"term_dumpload", 1, 2, FEARG_1, &t_number, f_term_dumpload},
785 {"term_dumpwrite", 2, 3, FEARG_2, &t_void, f_term_dumpwrite},
786 {"term_getaltscreen", 1, 1, FEARG_1, &t_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200787# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100788 {"term_getansicolors", 1, 1, FEARG_1, &t_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200789# endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100790 {"term_getattr", 2, 2, FEARG_1, &t_number, f_term_getattr},
791 {"term_getcursor", 1, 1, FEARG_1, &t_list_any, f_term_getcursor},
792 {"term_getjob", 1, 1, FEARG_1, &t_job, f_term_getjob},
793 {"term_getline", 2, 2, FEARG_1, &t_string, f_term_getline},
794 {"term_getscrolled", 1, 1, FEARG_1, &t_number, f_term_getscrolled},
795 {"term_getsize", 1, 1, FEARG_1, &t_list_number, f_term_getsize},
796 {"term_getstatus", 1, 1, FEARG_1, &t_string, f_term_getstatus},
797 {"term_gettitle", 1, 1, FEARG_1, &t_string, f_term_gettitle},
798 {"term_gettty", 1, 2, FEARG_1, &t_string, f_term_gettty},
799 {"term_list", 0, 0, 0, &t_list_number, f_term_list},
800 {"term_scrape", 2, 2, FEARG_1, &t_list_dict_any, f_term_scrape},
801 {"term_sendkeys", 2, 2, FEARG_1, &t_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200802# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100803 {"term_setansicolors", 2, 2, FEARG_1, &t_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200804# endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100805 {"term_setapi", 2, 2, FEARG_1, &t_void, f_term_setapi},
806 {"term_setkill", 2, 2, FEARG_1, &t_void, f_term_setkill},
807 {"term_setrestore", 2, 2, FEARG_1, &t_void, f_term_setrestore},
808 {"term_setsize", 3, 3, FEARG_1, &t_void, f_term_setsize},
809 {"term_start", 1, 2, FEARG_1, &t_number, f_term_start},
810 {"term_wait", 1, 2, FEARG_1, &t_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200811#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100812 {"test_alloc_fail", 3, 3, FEARG_1, &t_void, f_test_alloc_fail},
813 {"test_autochdir", 0, 0, 0, &t_void, f_test_autochdir},
814 {"test_feedinput", 1, 1, FEARG_1, &t_void, f_test_feedinput},
815 {"test_garbagecollect_now", 0, 0, 0, &t_void, f_test_garbagecollect_now},
816 {"test_garbagecollect_soon", 0, 0, 0, &t_void, f_test_garbagecollect_soon},
817 {"test_getvalue", 1, 1, FEARG_1, &t_number, f_test_getvalue},
818 {"test_ignore_error", 1, 1, FEARG_1, &t_void, f_test_ignore_error},
819 {"test_null_blob", 0, 0, 0, &t_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100821 {"test_null_channel", 0, 0, 0, &t_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100823 {"test_null_dict", 0, 0, 0, &t_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100825 {"test_null_job", 0, 0, 0, &t_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200826#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100827 {"test_null_list", 0, 0, 0, &t_list_any, f_test_null_list},
828 {"test_null_partial", 0, 0, 0, &t_partial_void, f_test_null_partial},
829 {"test_null_string", 0, 0, 0, &t_string, f_test_null_string},
830 {"test_option_not_set", 1, 1, FEARG_1,&t_void, f_test_option_not_set},
831 {"test_override", 2, 2, FEARG_2, &t_void, f_test_override},
832 {"test_refcount", 1, 1, FEARG_1, &t_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200833#ifdef FEAT_GUI
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100834 {"test_scrollbar", 3, 3, FEARG_2, &t_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200835#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100836 {"test_setmouse", 2, 2, 0, &t_void, f_test_setmouse},
837 {"test_settime", 1, 1, FEARG_1, &t_void, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200838#ifdef FEAT_TIMERS
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100839 {"timer_info", 0, 1, FEARG_1, &t_list_dict_any, f_timer_info},
840 {"timer_pause", 2, 2, FEARG_1, &t_void, f_timer_pause},
841 {"timer_start", 2, 3, FEARG_1, &t_number, f_timer_start},
842 {"timer_stop", 1, 1, FEARG_1, &t_void, f_timer_stop},
843 {"timer_stopall", 0, 0, 0, &t_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200844#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100845 {"tolower", 1, 1, FEARG_1, &t_string, f_tolower},
846 {"toupper", 1, 1, FEARG_1, &t_string, f_toupper},
847 {"tr", 3, 3, FEARG_1, &t_string, f_tr},
848 {"trim", 1, 2, FEARG_1, &t_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100850 {"trunc", 1, 1, FEARG_1, &t_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200851#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100852 {"type", 1, 1, FEARG_1, &t_number, f_type},
853 {"undofile", 1, 1, FEARG_1, &t_string, f_undofile},
854 {"undotree", 0, 0, 0, &t_dict_any, f_undotree},
855 {"uniq", 1, 3, FEARG_1, &t_list_any, f_uniq},
856 {"values", 1, 1, FEARG_1, &t_list_any, f_values},
857 {"virtcol", 1, 1, FEARG_1, &t_number, f_virtcol},
858 {"visualmode", 0, 1, 0, &t_string, f_visualmode},
859 {"wildmenumode", 0, 0, 0, &t_number, f_wildmenumode},
860 {"win_execute", 2, 3, FEARG_2, &t_string, f_win_execute},
861 {"win_findbuf", 1, 1, FEARG_1, &t_list_number, f_win_findbuf},
862 {"win_getid", 0, 2, FEARG_1, &t_number, f_win_getid},
863 {"win_gotoid", 1, 1, FEARG_1, &t_number, f_win_gotoid},
864 {"win_id2tabwin", 1, 1, FEARG_1, &t_list_number, f_win_id2tabwin},
865 {"win_id2win", 1, 1, FEARG_1, &t_number, f_win_id2win},
866 {"win_screenpos", 1, 1, FEARG_1, &t_list_number, f_win_screenpos},
867 {"win_splitmove", 2, 3, FEARG_1, &t_number, f_win_splitmove},
868 {"winbufnr", 1, 1, FEARG_1, &t_number, f_winbufnr},
869 {"wincol", 0, 0, 0, &t_number, f_wincol},
870 {"windowsversion", 0, 0, 0, &t_string, f_windowsversion},
871 {"winheight", 1, 1, FEARG_1, &t_number, f_winheight},
872 {"winlayout", 0, 1, FEARG_1, &t_list_any, f_winlayout},
873 {"winline", 0, 0, 0, &t_number, f_winline},
874 {"winnr", 0, 1, FEARG_1, &t_number, f_winnr},
875 {"winrestcmd", 0, 0, 0, &t_string, f_winrestcmd},
876 {"winrestview", 1, 1, FEARG_1, &t_void, f_winrestview},
877 {"winsaveview", 0, 0, 0, &t_dict_any, f_winsaveview},
878 {"winwidth", 1, 1, FEARG_1, &t_number, f_winwidth},
879 {"wordcount", 0, 0, 0, &t_dict_number, f_wordcount},
880 {"writefile", 2, 3, FEARG_1, &t_number, f_writefile},
881 {"xor", 2, 2, FEARG_1, &t_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200882};
883
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200884/*
885 * Function given to ExpandGeneric() to obtain the list of internal
886 * or user defined function names.
887 */
888 char_u *
889get_function_name(expand_T *xp, int idx)
890{
891 static int intidx = -1;
892 char_u *name;
893
894 if (idx == 0)
895 intidx = -1;
896 if (intidx < 0)
897 {
898 name = get_user_func_name(xp, idx);
899 if (name != NULL)
900 return name;
901 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200902 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200903 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200904 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200905 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200906 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200907 STRCAT(IObuff, ")");
908 return IObuff;
909 }
910
911 return NULL;
912}
913
914/*
915 * Function given to ExpandGeneric() to obtain the list of internal or
916 * user defined variable or function names.
917 */
918 char_u *
919get_expr_name(expand_T *xp, int idx)
920{
921 static int intidx = -1;
922 char_u *name;
923
924 if (idx == 0)
925 intidx = -1;
926 if (intidx < 0)
927 {
928 name = get_function_name(xp, idx);
929 if (name != NULL)
930 return name;
931 }
932 return get_user_var_name(xp, ++intidx);
933}
934
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200936 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200937 * Return index, or -1 if not found
938 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100939 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200940find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200941{
942 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200943 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200944 int cmp;
945 int x;
946
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200947 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200948
949 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200950 while (first <= last)
951 {
952 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200953 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200954 if (cmp < 0)
955 last = x - 1;
956 else if (cmp > 0)
957 first = x + 1;
958 else
959 return x;
960 }
961 return -1;
962}
963
964 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200965has_internal_func(char_u *name)
966{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200967 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200968}
969
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100970 char *
971internal_func_name(int idx)
972{
973 return global_functions[idx].f_name;
974}
975
976 type_T *
977internal_func_ret_type(int idx, int argcount)
978{
979 funcentry_T *fe = &global_functions[idx];
980
981 if (fe->f_func == f_getline)
982 return argcount == 1 ? &t_string : &t_list_string;
983 return fe->f_rettype;
984}
985
986/*
987 * Check the argument count to use for internal function "idx".
988 * Returns OK or FAIL;
989 */
990 int
991check_internal_func(int idx, int argcount)
992{
993 int res;
994 char *name;
995
996 if (argcount < global_functions[idx].f_min_argc)
997 res = FCERR_TOOFEW;
998 else if (argcount > global_functions[idx].f_max_argc)
999 res = FCERR_TOOMANY;
1000 else
1001 return OK;
1002
1003 name = internal_func_name(idx);
1004 if (res == FCERR_TOOMANY)
1005 semsg(_(e_toomanyarg), name);
1006 else
1007 semsg(_(e_toofewarg), name);
1008 return FAIL;
1009}
1010
Bram Moolenaarac92e252019-08-03 21:58:38 +02001011 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012call_internal_func(
1013 char_u *name,
1014 int argcount,
1015 typval_T *argvars,
1016 typval_T *rettv)
1017{
1018 int i;
1019
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001020 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001021 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001022 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001023 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001024 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001025 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001026 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001027 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001028 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001029 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001030}
1031
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001032 void
1033call_internal_func_by_idx(
1034 int idx,
1035 typval_T *argvars,
1036 typval_T *rettv)
1037{
1038 global_functions[idx].f_func(argvars, rettv);
1039}
1040
Bram Moolenaarac92e252019-08-03 21:58:38 +02001041/*
1042 * Invoke a method for base->method().
1043 */
1044 int
1045call_internal_method(
1046 char_u *name,
1047 int argcount,
1048 typval_T *argvars,
1049 typval_T *rettv,
1050 typval_T *basetv)
1051{
1052 int i;
1053 int fi;
1054 typval_T argv[MAX_FUNC_ARGS + 1];
1055
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001056 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001057 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001058 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001059 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001060 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001061 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001062 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001063 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001064 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001065
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001066 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001067 {
1068 // base value goes last
1069 for (i = 0; i < argcount; ++i)
1070 argv[i] = argvars[i];
1071 argv[argcount] = *basetv;
1072 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001073 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001074 {
1075 // base value goes second
1076 argv[0] = argvars[0];
1077 argv[1] = *basetv;
1078 for (i = 1; i < argcount; ++i)
1079 argv[i + 1] = argvars[i];
1080 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001081 else if (global_functions[fi].f_argtype == FEARG_3)
1082 {
1083 // base value goes third
1084 argv[0] = argvars[0];
1085 argv[1] = argvars[1];
1086 argv[2] = *basetv;
1087 for (i = 2; i < argcount; ++i)
1088 argv[i + 1] = argvars[i];
1089 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001090 else if (global_functions[fi].f_argtype == FEARG_4)
1091 {
1092 // base value goes fourth
1093 argv[0] = argvars[0];
1094 argv[1] = argvars[1];
1095 argv[2] = argvars[2];
1096 argv[3] = *basetv;
1097 for (i = 3; i < argcount; ++i)
1098 argv[i + 1] = argvars[i];
1099 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001100 else
1101 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001102 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001103 argv[0] = *basetv;
1104 for (i = 0; i < argcount; ++i)
1105 argv[i + 1] = argvars[i];
1106 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001107 argv[argcount + 1].v_type = VAR_UNKNOWN;
1108
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001109 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001110 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001111}
1112
1113/*
1114 * Return TRUE for a non-zero Number and a non-empty String.
1115 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001116 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001117non_zero_arg(typval_T *argvars)
1118{
1119 return ((argvars[0].v_type == VAR_NUMBER
1120 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001121 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001122 && argvars[0].vval.v_number == VVAL_TRUE)
1123 || (argvars[0].v_type == VAR_STRING
1124 && argvars[0].vval.v_string != NULL
1125 && *argvars[0].vval.v_string != NUL));
1126}
1127
1128/*
1129 * Get the lnum from the first argument.
1130 * Also accepts ".", "$", etc., but that only works for the current buffer.
1131 * Returns -1 on error.
1132 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001133 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001134tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001135{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001136 linenr_T lnum;
1137
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001138 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001139 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001140 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001141 int fnum;
1142 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1143
1144 if (fp != NULL)
1145 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001146 }
1147 return lnum;
1148}
1149
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001150/*
1151 * Get the lnum from the first argument.
1152 * Also accepts "$", then "buf" is used.
1153 * Returns 0 on error.
1154 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001155 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001156tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1157{
1158 if (argvars[0].v_type == VAR_STRING
1159 && argvars[0].vval.v_string != NULL
1160 && argvars[0].vval.v_string[0] == '$'
1161 && buf != NULL)
1162 return buf->b_ml.ml_line_count;
1163 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1164}
1165
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001166#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001167/*
1168 * Get the float value of "argvars[0]" into "f".
1169 * Returns FAIL when the argument is not a Number or Float.
1170 */
1171 static int
1172get_float_arg(typval_T *argvars, float_T *f)
1173{
1174 if (argvars[0].v_type == VAR_FLOAT)
1175 {
1176 *f = argvars[0].vval.v_float;
1177 return OK;
1178 }
1179 if (argvars[0].v_type == VAR_NUMBER)
1180 {
1181 *f = (float_T)argvars[0].vval.v_number;
1182 return OK;
1183 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001184 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001185 return FAIL;
1186}
1187
1188/*
1189 * "abs(expr)" function
1190 */
1191 static void
1192f_abs(typval_T *argvars, typval_T *rettv)
1193{
1194 if (argvars[0].v_type == VAR_FLOAT)
1195 {
1196 rettv->v_type = VAR_FLOAT;
1197 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1198 }
1199 else
1200 {
1201 varnumber_T n;
1202 int error = FALSE;
1203
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001204 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001205 if (error)
1206 rettv->vval.v_number = -1;
1207 else if (n > 0)
1208 rettv->vval.v_number = n;
1209 else
1210 rettv->vval.v_number = -n;
1211 }
1212}
1213
1214/*
1215 * "acos()" function
1216 */
1217 static void
1218f_acos(typval_T *argvars, typval_T *rettv)
1219{
1220 float_T f = 0.0;
1221
1222 rettv->v_type = VAR_FLOAT;
1223 if (get_float_arg(argvars, &f) == OK)
1224 rettv->vval.v_float = acos(f);
1225 else
1226 rettv->vval.v_float = 0.0;
1227}
1228#endif
1229
1230/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001231 * "and(expr, expr)" function
1232 */
1233 static void
1234f_and(typval_T *argvars, typval_T *rettv)
1235{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001236 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1237 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001238}
1239
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001240#ifdef FEAT_FLOAT
1241/*
1242 * "asin()" function
1243 */
1244 static void
1245f_asin(typval_T *argvars, typval_T *rettv)
1246{
1247 float_T f = 0.0;
1248
1249 rettv->v_type = VAR_FLOAT;
1250 if (get_float_arg(argvars, &f) == OK)
1251 rettv->vval.v_float = asin(f);
1252 else
1253 rettv->vval.v_float = 0.0;
1254}
1255
1256/*
1257 * "atan()" function
1258 */
1259 static void
1260f_atan(typval_T *argvars, typval_T *rettv)
1261{
1262 float_T f = 0.0;
1263
1264 rettv->v_type = VAR_FLOAT;
1265 if (get_float_arg(argvars, &f) == OK)
1266 rettv->vval.v_float = atan(f);
1267 else
1268 rettv->vval.v_float = 0.0;
1269}
1270
1271/*
1272 * "atan2()" function
1273 */
1274 static void
1275f_atan2(typval_T *argvars, typval_T *rettv)
1276{
1277 float_T fx = 0.0, fy = 0.0;
1278
1279 rettv->v_type = VAR_FLOAT;
1280 if (get_float_arg(argvars, &fx) == OK
1281 && get_float_arg(&argvars[1], &fy) == OK)
1282 rettv->vval.v_float = atan2(fx, fy);
1283 else
1284 rettv->vval.v_float = 0.0;
1285}
1286#endif
1287
1288/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001289 * "balloon_show()" function
1290 */
1291#ifdef FEAT_BEVAL
1292 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001293f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1294{
1295 rettv->v_type = VAR_STRING;
1296 if (balloonEval != NULL)
1297 {
1298 if (balloonEval->msg == NULL)
1299 rettv->vval.v_string = NULL;
1300 else
1301 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1302 }
1303}
1304
1305 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001306f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1307{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001308 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001309 {
1310 if (argvars[0].v_type == VAR_LIST
1311# ifdef FEAT_GUI
1312 && !gui.in_use
1313# endif
1314 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001315 {
1316 list_T *l = argvars[0].vval.v_list;
1317
1318 // empty list removes the balloon
1319 post_balloon(balloonEval, NULL,
1320 l == NULL || l->lv_len == 0 ? NULL : l);
1321 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001322 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001323 {
1324 char_u *mesg = tv_get_string_chk(&argvars[0]);
1325
1326 if (mesg != NULL)
1327 // empty string removes the balloon
1328 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1329 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001330 }
1331}
1332
Bram Moolenaar669a8282017-11-19 20:13:05 +01001333# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001334 static void
1335f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1336{
1337 if (rettv_list_alloc(rettv) == OK)
1338 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001339 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001340
1341 if (msg != NULL)
1342 {
1343 pumitem_T *array;
1344 int size = split_message(msg, &array);
1345 int i;
1346
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001347 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001348 for (i = 1; i < size - 1; ++i)
1349 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001350 while (size > 0)
1351 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001352 vim_free(array);
1353 }
1354 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001355}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001356# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001357#endif
1358
1359/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360 * Get buffer by number or pattern.
1361 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001362 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001363tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364{
1365 char_u *name = tv->vval.v_string;
1366 buf_T *buf;
1367
1368 if (tv->v_type == VAR_NUMBER)
1369 return buflist_findnr((int)tv->vval.v_number);
1370 if (tv->v_type != VAR_STRING)
1371 return NULL;
1372 if (name == NULL || *name == NUL)
1373 return curbuf;
1374 if (name[0] == '$' && name[1] == NUL)
1375 return lastbuf;
1376
1377 buf = buflist_find_by_name(name, curtab_only);
1378
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001379 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001380 if (buf == NULL)
1381 buf = find_buffer(tv);
1382
1383 return buf;
1384}
1385
1386/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001387 * Get the buffer from "arg" and give an error and return NULL if it is not
1388 * valid.
1389 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001390 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001391get_buf_arg(typval_T *arg)
1392{
1393 buf_T *buf;
1394
1395 ++emsg_off;
1396 buf = tv_get_buf(arg, FALSE);
1397 --emsg_off;
1398 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001399 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001400 return buf;
1401}
1402
1403/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001404 * "byte2line(byte)" function
1405 */
1406 static void
1407f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1408{
1409#ifndef FEAT_BYTEOFF
1410 rettv->vval.v_number = -1;
1411#else
1412 long boff = 0;
1413
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001414 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001415 if (boff < 0)
1416 rettv->vval.v_number = -1;
1417 else
1418 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1419 (linenr_T)0, &boff);
1420#endif
1421}
1422
1423 static void
1424byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1425{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001426 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001427 char_u *str;
1428 varnumber_T idx;
1429
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001430 str = tv_get_string_chk(&argvars[0]);
1431 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001432 rettv->vval.v_number = -1;
1433 if (str == NULL || idx < 0)
1434 return;
1435
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001436 t = str;
1437 for ( ; idx > 0; idx--)
1438 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001439 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001440 return;
1441 if (enc_utf8 && comp)
1442 t += utf_ptr2len(t);
1443 else
1444 t += (*mb_ptr2len)(t);
1445 }
1446 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001447}
1448
1449/*
1450 * "byteidx()" function
1451 */
1452 static void
1453f_byteidx(typval_T *argvars, typval_T *rettv)
1454{
1455 byteidx(argvars, rettv, FALSE);
1456}
1457
1458/*
1459 * "byteidxcomp()" function
1460 */
1461 static void
1462f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1463{
1464 byteidx(argvars, rettv, TRUE);
1465}
1466
1467/*
1468 * "call(func, arglist [, dict])" function
1469 */
1470 static void
1471f_call(typval_T *argvars, typval_T *rettv)
1472{
1473 char_u *func;
1474 partial_T *partial = NULL;
1475 dict_T *selfdict = NULL;
1476
1477 if (argvars[1].v_type != VAR_LIST)
1478 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001479 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480 return;
1481 }
1482 if (argvars[1].vval.v_list == NULL)
1483 return;
1484
1485 if (argvars[0].v_type == VAR_FUNC)
1486 func = argvars[0].vval.v_string;
1487 else if (argvars[0].v_type == VAR_PARTIAL)
1488 {
1489 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001490 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001491 }
1492 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001493 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001494 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001495 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001496
1497 if (argvars[2].v_type != VAR_UNKNOWN)
1498 {
1499 if (argvars[2].v_type != VAR_DICT)
1500 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001501 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502 return;
1503 }
1504 selfdict = argvars[2].vval.v_dict;
1505 }
1506
1507 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1508}
1509
1510#ifdef FEAT_FLOAT
1511/*
1512 * "ceil({float})" function
1513 */
1514 static void
1515f_ceil(typval_T *argvars, typval_T *rettv)
1516{
1517 float_T f = 0.0;
1518
1519 rettv->v_type = VAR_FLOAT;
1520 if (get_float_arg(argvars, &f) == OK)
1521 rettv->vval.v_float = ceil(f);
1522 else
1523 rettv->vval.v_float = 0.0;
1524}
1525#endif
1526
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001527/*
1528 * "changenr()" function
1529 */
1530 static void
1531f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1532{
1533 rettv->vval.v_number = curbuf->b_u_seq_cur;
1534}
1535
1536/*
1537 * "char2nr(string)" function
1538 */
1539 static void
1540f_char2nr(typval_T *argvars, typval_T *rettv)
1541{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542 if (has_mbyte)
1543 {
1544 int utf8 = 0;
1545
1546 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001547 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001548
1549 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001550 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001551 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001552 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001553 }
1554 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001555 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556}
1557
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001558 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001559get_optional_window(typval_T *argvars, int idx)
1560{
1561 win_T *win = curwin;
1562
1563 if (argvars[idx].v_type != VAR_UNKNOWN)
1564 {
1565 win = find_win_by_nr_or_id(&argvars[idx]);
1566 if (win == NULL)
1567 {
1568 emsg(_(e_invalwindow));
1569 return NULL;
1570 }
1571 }
1572 return win;
1573}
1574
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 * "col(string)" function
1577 */
1578 static void
1579f_col(typval_T *argvars, typval_T *rettv)
1580{
1581 colnr_T col = 0;
1582 pos_T *fp;
1583 int fnum = curbuf->b_fnum;
1584
1585 fp = var2fpos(&argvars[0], FALSE, &fnum);
1586 if (fp != NULL && fnum == curbuf->b_fnum)
1587 {
1588 if (fp->col == MAXCOL)
1589 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001590 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001591 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1592 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1593 else
1594 col = MAXCOL;
1595 }
1596 else
1597 {
1598 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001599 // col(".") when the cursor is on the NUL at the end of the line
1600 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001601 if (virtual_active() && fp == &curwin->w_cursor)
1602 {
1603 char_u *p = ml_get_cursor();
1604
1605 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1606 curwin->w_virtcol - curwin->w_cursor.coladd))
1607 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001608 int l;
1609
1610 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1611 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001612 }
1613 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001614 }
1615 }
1616 rettv->vval.v_number = col;
1617}
1618
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001619/*
1620 * "confirm(message, buttons[, default [, type]])" function
1621 */
1622 static void
1623f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1624{
1625#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1626 char_u *message;
1627 char_u *buttons = NULL;
1628 char_u buf[NUMBUFLEN];
1629 char_u buf2[NUMBUFLEN];
1630 int def = 1;
1631 int type = VIM_GENERIC;
1632 char_u *typestr;
1633 int error = FALSE;
1634
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001635 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001636 if (message == NULL)
1637 error = TRUE;
1638 if (argvars[1].v_type != VAR_UNKNOWN)
1639 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001640 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001641 if (buttons == NULL)
1642 error = TRUE;
1643 if (argvars[2].v_type != VAR_UNKNOWN)
1644 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001645 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001646 if (argvars[3].v_type != VAR_UNKNOWN)
1647 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001648 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649 if (typestr == NULL)
1650 error = TRUE;
1651 else
1652 {
1653 switch (TOUPPER_ASC(*typestr))
1654 {
1655 case 'E': type = VIM_ERROR; break;
1656 case 'Q': type = VIM_QUESTION; break;
1657 case 'I': type = VIM_INFO; break;
1658 case 'W': type = VIM_WARNING; break;
1659 case 'G': type = VIM_GENERIC; break;
1660 }
1661 }
1662 }
1663 }
1664 }
1665
1666 if (buttons == NULL || *buttons == NUL)
1667 buttons = (char_u *)_("&Ok");
1668
1669 if (!error)
1670 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1671 def, NULL, FALSE);
1672#endif
1673}
1674
1675/*
1676 * "copy()" function
1677 */
1678 static void
1679f_copy(typval_T *argvars, typval_T *rettv)
1680{
1681 item_copy(&argvars[0], rettv, FALSE, 0);
1682}
1683
1684#ifdef FEAT_FLOAT
1685/*
1686 * "cos()" function
1687 */
1688 static void
1689f_cos(typval_T *argvars, typval_T *rettv)
1690{
1691 float_T f = 0.0;
1692
1693 rettv->v_type = VAR_FLOAT;
1694 if (get_float_arg(argvars, &f) == OK)
1695 rettv->vval.v_float = cos(f);
1696 else
1697 rettv->vval.v_float = 0.0;
1698}
1699
1700/*
1701 * "cosh()" function
1702 */
1703 static void
1704f_cosh(typval_T *argvars, typval_T *rettv)
1705{
1706 float_T f = 0.0;
1707
1708 rettv->v_type = VAR_FLOAT;
1709 if (get_float_arg(argvars, &f) == OK)
1710 rettv->vval.v_float = cosh(f);
1711 else
1712 rettv->vval.v_float = 0.0;
1713}
1714#endif
1715
1716/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001717 * "cursor(lnum, col)" function, or
1718 * "cursor(list)"
1719 *
1720 * Moves the cursor to the specified line and column.
1721 * Returns 0 when the position could be set, -1 otherwise.
1722 */
1723 static void
1724f_cursor(typval_T *argvars, typval_T *rettv)
1725{
1726 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728 int set_curswant = TRUE;
1729
1730 rettv->vval.v_number = -1;
1731 if (argvars[1].v_type == VAR_UNKNOWN)
1732 {
1733 pos_T pos;
1734 colnr_T curswant = -1;
1735
1736 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1737 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001738 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001739 return;
1740 }
1741 line = pos.lnum;
1742 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001743 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001744 if (curswant >= 0)
1745 {
1746 curwin->w_curswant = curswant - 1;
1747 set_curswant = FALSE;
1748 }
1749 }
1750 else
1751 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001752 line = tv_get_lnum(argvars);
1753 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001754 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001755 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001756 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001757 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001758 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001759 if (line > 0)
1760 curwin->w_cursor.lnum = line;
1761 if (col > 0)
1762 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001763 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001764
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001765 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001766 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001767 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001768 if (has_mbyte)
1769 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001770
1771 curwin->w_set_curswant = set_curswant;
1772 rettv->vval.v_number = 0;
1773}
1774
Bram Moolenaar4f974752019-02-17 17:44:42 +01001775#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001776/*
1777 * "debugbreak()" function
1778 */
1779 static void
1780f_debugbreak(typval_T *argvars, typval_T *rettv)
1781{
1782 int pid;
1783
1784 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001785 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001786 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001787 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001788 else
1789 {
1790 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1791
1792 if (hProcess != NULL)
1793 {
1794 DebugBreakProcess(hProcess);
1795 CloseHandle(hProcess);
1796 rettv->vval.v_number = OK;
1797 }
1798 }
1799}
1800#endif
1801
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001802/*
1803 * "deepcopy()" function
1804 */
1805 static void
1806f_deepcopy(typval_T *argvars, typval_T *rettv)
1807{
1808 int noref = 0;
1809 int copyID;
1810
1811 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001812 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001814 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001815 else
1816 {
1817 copyID = get_copyID();
1818 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1819 }
1820}
1821
1822/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001823 * "did_filetype()" function
1824 */
1825 static void
1826f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1827{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001828 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001829}
1830
1831/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 * "empty({expr})" function
1833 */
1834 static void
1835f_empty(typval_T *argvars, typval_T *rettv)
1836{
1837 int n = FALSE;
1838
1839 switch (argvars[0].v_type)
1840 {
1841 case VAR_STRING:
1842 case VAR_FUNC:
1843 n = argvars[0].vval.v_string == NULL
1844 || *argvars[0].vval.v_string == NUL;
1845 break;
1846 case VAR_PARTIAL:
1847 n = FALSE;
1848 break;
1849 case VAR_NUMBER:
1850 n = argvars[0].vval.v_number == 0;
1851 break;
1852 case VAR_FLOAT:
1853#ifdef FEAT_FLOAT
1854 n = argvars[0].vval.v_float == 0.0;
1855 break;
1856#endif
1857 case VAR_LIST:
1858 n = argvars[0].vval.v_list == NULL
1859 || argvars[0].vval.v_list->lv_first == NULL;
1860 break;
1861 case VAR_DICT:
1862 n = argvars[0].vval.v_dict == NULL
1863 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1864 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001865 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001866 case VAR_SPECIAL:
1867 n = argvars[0].vval.v_number != VVAL_TRUE;
1868 break;
1869
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001870 case VAR_BLOB:
1871 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001872 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1873 break;
1874
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001875 case VAR_JOB:
1876#ifdef FEAT_JOB_CHANNEL
1877 n = argvars[0].vval.v_job == NULL
1878 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1879 break;
1880#endif
1881 case VAR_CHANNEL:
1882#ifdef FEAT_JOB_CHANNEL
1883 n = argvars[0].vval.v_channel == NULL
1884 || !channel_is_open(argvars[0].vval.v_channel);
1885 break;
1886#endif
1887 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001888 case VAR_VOID:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001889 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001890 n = TRUE;
1891 break;
1892 }
1893
1894 rettv->vval.v_number = n;
1895}
1896
1897/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001898 * "environ()" function
1899 */
1900 static void
1901f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1902{
1903#if !defined(AMIGA)
1904 int i = 0;
1905 char_u *entry, *value;
1906# ifdef MSWIN
1907 extern wchar_t **_wenviron;
1908# else
1909 extern char **environ;
1910# endif
1911
1912 if (rettv_dict_alloc(rettv) != OK)
1913 return;
1914
1915# ifdef MSWIN
1916 if (*_wenviron == NULL)
1917 return;
1918# else
1919 if (*environ == NULL)
1920 return;
1921# endif
1922
1923 for (i = 0; ; ++i)
1924 {
1925# ifdef MSWIN
1926 short_u *p;
1927
1928 if ((p = (short_u *)_wenviron[i]) == NULL)
1929 return;
1930 entry = utf16_to_enc(p, NULL);
1931# else
1932 if ((entry = (char_u *)environ[i]) == NULL)
1933 return;
1934 entry = vim_strsave(entry);
1935# endif
1936 if (entry == NULL) // out of memory
1937 return;
1938 if ((value = vim_strchr(entry, '=')) == NULL)
1939 {
1940 vim_free(entry);
1941 continue;
1942 }
1943 *value++ = NUL;
1944 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1945 vim_free(entry);
1946 }
1947#endif
1948}
1949
1950/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001951 * "escape({string}, {chars})" function
1952 */
1953 static void
1954f_escape(typval_T *argvars, typval_T *rettv)
1955{
1956 char_u buf[NUMBUFLEN];
1957
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001958 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1959 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001960 rettv->v_type = VAR_STRING;
1961}
1962
1963/*
1964 * "eval()" function
1965 */
1966 static void
1967f_eval(typval_T *argvars, typval_T *rettv)
1968{
1969 char_u *s, *p;
1970
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001971 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001972 if (s != NULL)
1973 s = skipwhite(s);
1974
1975 p = s;
1976 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1977 {
1978 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001979 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980 need_clr_eos = FALSE;
1981 rettv->v_type = VAR_NUMBER;
1982 rettv->vval.v_number = 0;
1983 }
1984 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001985 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986}
1987
1988/*
1989 * "eventhandler()" function
1990 */
1991 static void
1992f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1993{
1994 rettv->vval.v_number = vgetc_busy;
1995}
1996
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001997static garray_T redir_execute_ga;
1998
1999/*
2000 * Append "value[value_len]" to the execute() output.
2001 */
2002 void
2003execute_redir_str(char_u *value, int value_len)
2004{
2005 int len;
2006
2007 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002008 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002009 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002010 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002011 if (ga_grow(&redir_execute_ga, len) == OK)
2012 {
2013 mch_memmove((char *)redir_execute_ga.ga_data
2014 + redir_execute_ga.ga_len, value, len);
2015 redir_execute_ga.ga_len += len;
2016 }
2017}
2018
2019/*
2020 * Get next line from a list.
2021 * Called by do_cmdline() to get the next line.
2022 * Returns allocated string, or NULL for end of function.
2023 */
2024
2025 static char_u *
2026get_list_line(
2027 int c UNUSED,
2028 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002029 int indent UNUSED,
2030 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002031{
2032 listitem_T **p = (listitem_T **)cookie;
2033 listitem_T *item = *p;
2034 char_u buf[NUMBUFLEN];
2035 char_u *s;
2036
2037 if (item == NULL)
2038 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002039 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002040 *p = item->li_next;
2041 return s == NULL ? NULL : vim_strsave(s);
2042}
2043
2044/*
2045 * "execute()" function
2046 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002047 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002048execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049{
2050 char_u *cmd = NULL;
2051 list_T *list = NULL;
2052 int save_msg_silent = msg_silent;
2053 int save_emsg_silent = emsg_silent;
2054 int save_emsg_noredir = emsg_noredir;
2055 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002056 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002057 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002058 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002059 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002060
2061 rettv->vval.v_string = NULL;
2062 rettv->v_type = VAR_STRING;
2063
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002064 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002065 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002066 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002067 if (list == NULL || list->lv_first == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002068 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002069 return;
2070 ++list->lv_refcount;
2071 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002072 else if (argvars[arg_off].v_type == VAR_JOB
2073 || argvars[arg_off].v_type == VAR_CHANNEL)
2074 {
2075 emsg(_(e_inval_string));
2076 return;
2077 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002078 else
2079 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002080 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002081 if (cmd == NULL)
2082 return;
2083 }
2084
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002085 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002086 {
2087 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002088 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002089
2090 if (s == NULL)
2091 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002092 if (*s == NUL)
2093 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002094 if (STRNCMP(s, "silent", 6) == 0)
2095 ++msg_silent;
2096 if (STRCMP(s, "silent!") == 0)
2097 {
2098 emsg_silent = TRUE;
2099 emsg_noredir = TRUE;
2100 }
2101 }
2102 else
2103 ++msg_silent;
2104
2105 if (redir_execute)
2106 save_ga = redir_execute_ga;
2107 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2108 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002109 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002110 if (!echo_output)
2111 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002112
2113 if (cmd != NULL)
2114 do_cmdline_cmd(cmd);
2115 else
2116 {
2117 listitem_T *item = list->lv_first;
2118
2119 do_cmdline(NULL, get_list_line, (void *)&item,
2120 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2121 --list->lv_refcount;
2122 }
2123
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002124 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002125 if (ga_grow(&redir_execute_ga, 1) == OK)
2126 {
2127 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2128 rettv->vval.v_string = redir_execute_ga.ga_data;
2129 }
2130 else
2131 {
2132 ga_clear(&redir_execute_ga);
2133 rettv->vval.v_string = NULL;
2134 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002135 msg_silent = save_msg_silent;
2136 emsg_silent = save_emsg_silent;
2137 emsg_noredir = save_emsg_noredir;
2138
2139 redir_execute = save_redir_execute;
2140 if (redir_execute)
2141 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002142 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002143
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002144 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002145 if (echo_output)
2146 // When not working silently: put it in column zero. A following
2147 // "echon" will overwrite the message, unavoidably.
2148 msg_col = 0;
2149 else
2150 // When working silently: Put it back where it was, since nothing
2151 // should have been written.
2152 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153}
2154
2155/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002156 * "execute()" function
2157 */
2158 static void
2159f_execute(typval_T *argvars, typval_T *rettv)
2160{
2161 execute_common(argvars, rettv, 0);
2162}
2163
2164/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002165 * "exists()" function
2166 */
2167 static void
2168f_exists(typval_T *argvars, typval_T *rettv)
2169{
2170 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002173 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002174 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002176 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177 if (mch_getenv(p + 1) != NULL)
2178 n = TRUE;
2179 else
2180 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002181 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002182 p = expand_env_save(p);
2183 if (p != NULL && *p != '$')
2184 n = TRUE;
2185 vim_free(p);
2186 }
2187 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002188 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002189 {
2190 n = (get_option_tv(&p, NULL, TRUE) == OK);
2191 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002192 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002193 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002194 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002195 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002196 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002197 }
2198 else if (*p == ':')
2199 {
2200 n = cmd_exists(p + 1);
2201 }
2202 else if (*p == '#')
2203 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204 if (p[1] == '#')
2205 n = autocmd_supported(p + 2);
2206 else
2207 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002208 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002209 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002210 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002211 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002212 }
2213
2214 rettv->vval.v_number = n;
2215}
2216
2217#ifdef FEAT_FLOAT
2218/*
2219 * "exp()" function
2220 */
2221 static void
2222f_exp(typval_T *argvars, typval_T *rettv)
2223{
2224 float_T f = 0.0;
2225
2226 rettv->v_type = VAR_FLOAT;
2227 if (get_float_arg(argvars, &f) == OK)
2228 rettv->vval.v_float = exp(f);
2229 else
2230 rettv->vval.v_float = 0.0;
2231}
2232#endif
2233
2234/*
2235 * "expand()" function
2236 */
2237 static void
2238f_expand(typval_T *argvars, typval_T *rettv)
2239{
2240 char_u *s;
2241 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002242 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002243 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2244 expand_T xpc;
2245 int error = FALSE;
2246 char_u *result;
2247
2248 rettv->v_type = VAR_STRING;
2249 if (argvars[1].v_type != VAR_UNKNOWN
2250 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002251 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002252 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002253 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002254
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002255 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256 if (*s == '%' || *s == '#' || *s == '<')
2257 {
2258 ++emsg_off;
2259 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2260 --emsg_off;
2261 if (rettv->v_type == VAR_LIST)
2262 {
2263 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2264 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002265 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002266 }
2267 else
2268 rettv->vval.v_string = result;
2269 }
2270 else
2271 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002272 // When the optional second argument is non-zero, don't remove matches
2273 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002274 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002275 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002276 options |= WILD_KEEP_ALL;
2277 if (!error)
2278 {
2279 ExpandInit(&xpc);
2280 xpc.xp_context = EXPAND_FILES;
2281 if (p_wic)
2282 options += WILD_ICASE;
2283 if (rettv->v_type == VAR_STRING)
2284 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2285 options, WILD_ALL);
2286 else if (rettv_list_alloc(rettv) != FAIL)
2287 {
2288 int i;
2289
2290 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2291 for (i = 0; i < xpc.xp_numfiles; i++)
2292 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2293 ExpandCleanup(&xpc);
2294 }
2295 }
2296 else
2297 rettv->vval.v_string = NULL;
2298 }
2299}
2300
2301/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002302 * "expandcmd()" function
2303 * Expand all the special characters in a command string.
2304 */
2305 static void
2306f_expandcmd(typval_T *argvars, typval_T *rettv)
2307{
2308 exarg_T eap;
2309 char_u *cmdstr;
2310 char *errormsg = NULL;
2311
2312 rettv->v_type = VAR_STRING;
2313 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2314
2315 memset(&eap, 0, sizeof(eap));
2316 eap.cmd = cmdstr;
2317 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002318 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002319 eap.usefilter = FALSE;
2320 eap.nextcmd = NULL;
2321 eap.cmdidx = CMD_USER;
2322
2323 expand_filename(&eap, &cmdstr, &errormsg);
2324 if (errormsg != NULL && *errormsg != NUL)
2325 emsg(errormsg);
2326
2327 rettv->vval.v_string = cmdstr;
2328}
2329
2330/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002331 * "feedkeys()" function
2332 */
2333 static void
2334f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2335{
2336 int remap = TRUE;
2337 int insert = FALSE;
2338 char_u *keys, *flags;
2339 char_u nbuf[NUMBUFLEN];
2340 int typed = FALSE;
2341 int execute = FALSE;
2342 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002343 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002344 char_u *keys_esc;
2345
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002346 // This is not allowed in the sandbox. If the commands would still be
2347 // executed in the sandbox it would be OK, but it probably happens later,
2348 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002349 if (check_secure())
2350 return;
2351
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002352 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002353
2354 if (argvars[1].v_type != VAR_UNKNOWN)
2355 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002356 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002357 for ( ; *flags != NUL; ++flags)
2358 {
2359 switch (*flags)
2360 {
2361 case 'n': remap = FALSE; break;
2362 case 'm': remap = TRUE; break;
2363 case 't': typed = TRUE; break;
2364 case 'i': insert = TRUE; break;
2365 case 'x': execute = TRUE; break;
2366 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002367 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002368 }
2369 }
2370 }
2371
2372 if (*keys != NUL || execute)
2373 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002374 // Need to escape K_SPECIAL and CSI before putting the string in the
2375 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002376 keys_esc = vim_strsave_escape_csi(keys);
2377 if (keys_esc != NULL)
2378 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002379 if (lowlevel)
2380 {
2381#ifdef USE_INPUT_BUF
2382 add_to_input_buf(keys, (int)STRLEN(keys));
2383#else
2384 emsg(_("E980: lowlevel input not supported"));
2385#endif
2386 }
2387 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002388 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002389 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002390 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002391 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002392#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002393 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002394#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002395 )
2396 typebuf_was_filled = TRUE;
2397 }
2398 vim_free(keys_esc);
2399
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002400 if (execute)
2401 {
2402 int save_msg_scroll = msg_scroll;
2403
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002404 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002405 msg_scroll = FALSE;
2406
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002407 if (!dangerous)
2408 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002409 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002410 if (!dangerous)
2411 --ex_normal_busy;
2412
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002413 msg_scroll |= save_msg_scroll;
2414 }
2415 }
2416 }
2417}
2418
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419#ifdef FEAT_FLOAT
2420/*
2421 * "float2nr({float})" function
2422 */
2423 static void
2424f_float2nr(typval_T *argvars, typval_T *rettv)
2425{
2426 float_T f = 0.0;
2427
2428 if (get_float_arg(argvars, &f) == OK)
2429 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002430 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002431 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002432 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002433 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002434 else
2435 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002436 }
2437}
2438
2439/*
2440 * "floor({float})" function
2441 */
2442 static void
2443f_floor(typval_T *argvars, typval_T *rettv)
2444{
2445 float_T f = 0.0;
2446
2447 rettv->v_type = VAR_FLOAT;
2448 if (get_float_arg(argvars, &f) == OK)
2449 rettv->vval.v_float = floor(f);
2450 else
2451 rettv->vval.v_float = 0.0;
2452}
2453
2454/*
2455 * "fmod()" function
2456 */
2457 static void
2458f_fmod(typval_T *argvars, typval_T *rettv)
2459{
2460 float_T fx = 0.0, fy = 0.0;
2461
2462 rettv->v_type = VAR_FLOAT;
2463 if (get_float_arg(argvars, &fx) == OK
2464 && get_float_arg(&argvars[1], &fy) == OK)
2465 rettv->vval.v_float = fmod(fx, fy);
2466 else
2467 rettv->vval.v_float = 0.0;
2468}
2469#endif
2470
2471/*
2472 * "fnameescape({string})" function
2473 */
2474 static void
2475f_fnameescape(typval_T *argvars, typval_T *rettv)
2476{
2477 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002478 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002479 rettv->v_type = VAR_STRING;
2480}
2481
2482/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002483 * "foreground()" function
2484 */
2485 static void
2486f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2487{
2488#ifdef FEAT_GUI
2489 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002490 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002491 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002492 return;
2493 }
2494#endif
2495#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002496 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002497#endif
2498}
2499
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002500 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002501common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002502{
2503 char_u *s;
2504 char_u *name;
2505 int use_string = FALSE;
2506 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002507 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002508
2509 if (argvars[0].v_type == VAR_FUNC)
2510 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002511 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002512 s = argvars[0].vval.v_string;
2513 }
2514 else if (argvars[0].v_type == VAR_PARTIAL
2515 && argvars[0].vval.v_partial != NULL)
2516 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002517 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002518 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002519 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002520 }
2521 else
2522 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002523 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002524 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002525 use_string = TRUE;
2526 }
2527
Bram Moolenaar843b8842016-08-21 14:36:15 +02002528 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002529 {
2530 name = s;
2531 trans_name = trans_function_name(&name, FALSE,
2532 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2533 if (*name != NUL)
2534 s = NULL;
2535 }
2536
Bram Moolenaar843b8842016-08-21 14:36:15 +02002537 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2538 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002539 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002540 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002541 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002542 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002543 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002544 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002545 else
2546 {
2547 int dict_idx = 0;
2548 int arg_idx = 0;
2549 list_T *list = NULL;
2550
2551 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2552 {
2553 char sid_buf[25];
2554 int off = *s == 's' ? 2 : 5;
2555
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002556 // Expand s: and <SID> into <SNR>nr_, so that the function can
2557 // also be called from another script. Using trans_function_name()
2558 // would also work, but some plugins depend on the name being
2559 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002560 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002561 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002562 if (name != NULL)
2563 {
2564 STRCPY(name, sid_buf);
2565 STRCAT(name, s + off);
2566 }
2567 }
2568 else
2569 name = vim_strsave(s);
2570
2571 if (argvars[1].v_type != VAR_UNKNOWN)
2572 {
2573 if (argvars[2].v_type != VAR_UNKNOWN)
2574 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002575 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002576 arg_idx = 1;
2577 dict_idx = 2;
2578 }
2579 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002580 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002581 dict_idx = 1;
2582 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002583 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002584 arg_idx = 1;
2585 if (dict_idx > 0)
2586 {
2587 if (argvars[dict_idx].v_type != VAR_DICT)
2588 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002589 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002590 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002591 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002592 }
2593 if (argvars[dict_idx].vval.v_dict == NULL)
2594 dict_idx = 0;
2595 }
2596 if (arg_idx > 0)
2597 {
2598 if (argvars[arg_idx].v_type != VAR_LIST)
2599 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002600 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002601 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002602 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002603 }
2604 list = argvars[arg_idx].vval.v_list;
2605 if (list == NULL || list->lv_len == 0)
2606 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002607 else if (list->lv_len > MAX_FUNC_ARGS)
2608 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002609 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002610 vim_free(name);
2611 goto theend;
2612 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002613 }
2614 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002615 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002616 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002617 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002618
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002619 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620 if (pt == NULL)
2621 vim_free(name);
2622 else
2623 {
2624 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2625 {
2626 listitem_T *li;
2627 int i = 0;
2628 int arg_len = 0;
2629 int lv_len = 0;
2630
2631 if (arg_pt != NULL)
2632 arg_len = arg_pt->pt_argc;
2633 if (list != NULL)
2634 lv_len = list->lv_len;
2635 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002636 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002637 if (pt->pt_argv == NULL)
2638 {
2639 vim_free(pt);
2640 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002641 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002642 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002643 for (i = 0; i < arg_len; i++)
2644 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2645 if (lv_len > 0)
2646 for (li = list->lv_first; li != NULL;
2647 li = li->li_next)
2648 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002649 }
2650
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002651 // For "function(dict.func, [], dict)" and "func" is a partial
2652 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653 if (dict_idx > 0)
2654 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002655 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2657 ++pt->pt_dict->dv_refcount;
2658 }
2659 else if (arg_pt != NULL)
2660 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002661 // If the dict was bound automatically the result is also
2662 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002663 pt->pt_dict = arg_pt->pt_dict;
2664 pt->pt_auto = arg_pt->pt_auto;
2665 if (pt->pt_dict != NULL)
2666 ++pt->pt_dict->dv_refcount;
2667 }
2668
2669 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002670 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2671 {
2672 pt->pt_func = arg_pt->pt_func;
2673 func_ptr_ref(pt->pt_func);
2674 vim_free(name);
2675 }
2676 else if (is_funcref)
2677 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002678 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002679 func_ptr_ref(pt->pt_func);
2680 vim_free(name);
2681 }
2682 else
2683 {
2684 pt->pt_name = name;
2685 func_ref(name);
2686 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002687 }
2688 rettv->v_type = VAR_PARTIAL;
2689 rettv->vval.v_partial = pt;
2690 }
2691 else
2692 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002693 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002694 rettv->v_type = VAR_FUNC;
2695 rettv->vval.v_string = name;
2696 func_ref(name);
2697 }
2698 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002699theend:
2700 vim_free(trans_name);
2701}
2702
2703/*
2704 * "funcref()" function
2705 */
2706 static void
2707f_funcref(typval_T *argvars, typval_T *rettv)
2708{
2709 common_function(argvars, rettv, TRUE);
2710}
2711
2712/*
2713 * "function()" function
2714 */
2715 static void
2716f_function(typval_T *argvars, typval_T *rettv)
2717{
2718 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719}
2720
2721/*
2722 * "garbagecollect()" function
2723 */
2724 static void
2725f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2726{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002727 // This is postponed until we are back at the toplevel, because we may be
2728 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002729 want_garbage_collect = TRUE;
2730
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002731 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002732 garbage_collect_at_exit = TRUE;
2733}
2734
2735/*
2736 * "get()" function
2737 */
2738 static void
2739f_get(typval_T *argvars, typval_T *rettv)
2740{
2741 listitem_T *li;
2742 list_T *l;
2743 dictitem_T *di;
2744 dict_T *d;
2745 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002746 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002747
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002748 if (argvars[0].v_type == VAR_BLOB)
2749 {
2750 int error = FALSE;
2751 int idx = tv_get_number_chk(&argvars[1], &error);
2752
2753 if (!error)
2754 {
2755 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002756 if (idx < 0)
2757 idx = blob_len(argvars[0].vval.v_blob) + idx;
2758 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2759 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002760 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002761 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002762 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002763 tv = rettv;
2764 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002765 }
2766 }
2767 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002768 {
2769 if ((l = argvars[0].vval.v_list) != NULL)
2770 {
2771 int error = FALSE;
2772
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002773 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002774 if (!error && li != NULL)
2775 tv = &li->li_tv;
2776 }
2777 }
2778 else if (argvars[0].v_type == VAR_DICT)
2779 {
2780 if ((d = argvars[0].vval.v_dict) != NULL)
2781 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002782 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002783 if (di != NULL)
2784 tv = &di->di_tv;
2785 }
2786 }
2787 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2788 {
2789 partial_T *pt;
2790 partial_T fref_pt;
2791
2792 if (argvars[0].v_type == VAR_PARTIAL)
2793 pt = argvars[0].vval.v_partial;
2794 else
2795 {
2796 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2797 fref_pt.pt_name = argvars[0].vval.v_string;
2798 pt = &fref_pt;
2799 }
2800
2801 if (pt != NULL)
2802 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002803 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002804 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002805
2806 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2807 {
2808 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002809 n = partial_name(pt);
2810 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002811 rettv->vval.v_string = NULL;
2812 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002813 {
2814 rettv->vval.v_string = vim_strsave(n);
2815 if (rettv->v_type == VAR_FUNC)
2816 func_ref(rettv->vval.v_string);
2817 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002818 }
2819 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002820 {
2821 what_is_dict = TRUE;
2822 if (pt->pt_dict != NULL)
2823 rettv_dict_set(rettv, pt->pt_dict);
2824 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002825 else if (STRCMP(what, "args") == 0)
2826 {
2827 rettv->v_type = VAR_LIST;
2828 if (rettv_list_alloc(rettv) == OK)
2829 {
2830 int i;
2831
2832 for (i = 0; i < pt->pt_argc; ++i)
2833 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2834 }
2835 }
2836 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002837 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002838
2839 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2840 // third argument
2841 if (!what_is_dict)
2842 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002843 }
2844 }
2845 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002846 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002847
2848 if (tv == NULL)
2849 {
2850 if (argvars[2].v_type != VAR_UNKNOWN)
2851 copy_tv(&argvars[2], rettv);
2852 }
2853 else
2854 copy_tv(tv, rettv);
2855}
2856
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002857/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002858 * "getchangelist()" function
2859 */
2860 static void
2861f_getchangelist(typval_T *argvars, typval_T *rettv)
2862{
2863#ifdef FEAT_JUMPLIST
2864 buf_T *buf;
2865 int i;
2866 list_T *l;
2867 dict_T *d;
2868#endif
2869
2870 if (rettv_list_alloc(rettv) != OK)
2871 return;
2872
2873#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002874 if (argvars[0].v_type == VAR_UNKNOWN)
2875 buf = curbuf;
2876 else
2877 {
2878 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2879 ++emsg_off;
2880 buf = tv_get_buf(&argvars[0], FALSE);
2881 --emsg_off;
2882 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002883 if (buf == NULL)
2884 return;
2885
2886 l = list_alloc();
2887 if (l == NULL)
2888 return;
2889
2890 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2891 return;
2892 /*
2893 * The current window change list index tracks only the position in the
2894 * current buffer change list. For other buffers, use the change list
2895 * length as the current index.
2896 */
2897 list_append_number(rettv->vval.v_list,
2898 (varnumber_T)((buf == curwin->w_buffer)
2899 ? curwin->w_changelistidx : buf->b_changelistlen));
2900
2901 for (i = 0; i < buf->b_changelistlen; ++i)
2902 {
2903 if (buf->b_changelist[i].lnum == 0)
2904 continue;
2905 if ((d = dict_alloc()) == NULL)
2906 return;
2907 if (list_append_dict(l, d) == FAIL)
2908 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002909 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2910 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002911 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002912 }
2913#endif
2914}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002915
2916/*
2917 * "getcharsearch()" function
2918 */
2919 static void
2920f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2921{
2922 if (rettv_dict_alloc(rettv) != FAIL)
2923 {
2924 dict_T *dict = rettv->vval.v_dict;
2925
Bram Moolenaare0be1672018-07-08 16:50:37 +02002926 dict_add_string(dict, "char", last_csearch());
2927 dict_add_number(dict, "forward", last_csearch_forward());
2928 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002929 }
2930}
2931
2932/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002933 * "getcmdwintype()" function
2934 */
2935 static void
2936f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2937{
2938 rettv->v_type = VAR_STRING;
2939 rettv->vval.v_string = NULL;
2940#ifdef FEAT_CMDWIN
2941 rettv->vval.v_string = alloc(2);
2942 if (rettv->vval.v_string != NULL)
2943 {
2944 rettv->vval.v_string[0] = cmdwin_type;
2945 rettv->vval.v_string[1] = NUL;
2946 }
2947#endif
2948}
2949
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002950/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002951 * "getenv()" function
2952 */
2953 static void
2954f_getenv(typval_T *argvars, typval_T *rettv)
2955{
2956 int mustfree = FALSE;
2957 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2958
2959 if (p == NULL)
2960 {
2961 rettv->v_type = VAR_SPECIAL;
2962 rettv->vval.v_number = VVAL_NULL;
2963 return;
2964 }
2965 if (!mustfree)
2966 p = vim_strsave(p);
2967 rettv->vval.v_string = p;
2968 rettv->v_type = VAR_STRING;
2969}
2970
2971/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002972 * "getfontname()" function
2973 */
2974 static void
2975f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2976{
2977 rettv->v_type = VAR_STRING;
2978 rettv->vval.v_string = NULL;
2979#ifdef FEAT_GUI
2980 if (gui.in_use)
2981 {
2982 GuiFont font;
2983 char_u *name = NULL;
2984
2985 if (argvars[0].v_type == VAR_UNKNOWN)
2986 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002987 // Get the "Normal" font. Either the name saved by
2988 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002989 font = gui.norm_font;
2990 name = hl_get_font_name();
2991 }
2992 else
2993 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002994 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002995 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002996 return;
2997 font = gui_mch_get_font(name, FALSE);
2998 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002999 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003000 }
3001 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3002 if (argvars[0].v_type != VAR_UNKNOWN)
3003 gui_mch_free_font(font);
3004 }
3005#endif
3006}
3007
3008/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003009 * "getjumplist()" function
3010 */
3011 static void
3012f_getjumplist(typval_T *argvars, typval_T *rettv)
3013{
3014#ifdef FEAT_JUMPLIST
3015 win_T *wp;
3016 int i;
3017 list_T *l;
3018 dict_T *d;
3019#endif
3020
3021 if (rettv_list_alloc(rettv) != OK)
3022 return;
3023
3024#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003025 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003026 if (wp == NULL)
3027 return;
3028
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003029 cleanup_jumplist(wp, TRUE);
3030
Bram Moolenaar4f505882018-02-10 21:06:32 +01003031 l = list_alloc();
3032 if (l == NULL)
3033 return;
3034
3035 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3036 return;
3037 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3038
3039 for (i = 0; i < wp->w_jumplistlen; ++i)
3040 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003041 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3042 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003043 if ((d = dict_alloc()) == NULL)
3044 return;
3045 if (list_append_dict(l, d) == FAIL)
3046 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003047 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3048 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003049 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003050 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003051 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003052 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003053 }
3054#endif
3055}
3056
3057/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 * "getpid()" function
3059 */
3060 static void
3061f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3062{
3063 rettv->vval.v_number = mch_get_pid();
3064}
3065
3066 static void
3067getpos_both(
3068 typval_T *argvars,
3069 typval_T *rettv,
3070 int getcurpos)
3071{
3072 pos_T *fp;
3073 list_T *l;
3074 int fnum = -1;
3075
3076 if (rettv_list_alloc(rettv) == OK)
3077 {
3078 l = rettv->vval.v_list;
3079 if (getcurpos)
3080 fp = &curwin->w_cursor;
3081 else
3082 fp = var2fpos(&argvars[0], TRUE, &fnum);
3083 if (fnum != -1)
3084 list_append_number(l, (varnumber_T)fnum);
3085 else
3086 list_append_number(l, (varnumber_T)0);
3087 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3088 : (varnumber_T)0);
3089 list_append_number(l, (fp != NULL)
3090 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3091 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003092 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003093 (varnumber_T)0);
3094 if (getcurpos)
3095 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003096 int save_set_curswant = curwin->w_set_curswant;
3097 colnr_T save_curswant = curwin->w_curswant;
3098 colnr_T save_virtcol = curwin->w_virtcol;
3099
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003100 update_curswant();
3101 list_append_number(l, curwin->w_curswant == MAXCOL ?
3102 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003103
3104 // Do not change "curswant", as it is unexpected that a get
3105 // function has a side effect.
3106 if (save_set_curswant)
3107 {
3108 curwin->w_set_curswant = save_set_curswant;
3109 curwin->w_curswant = save_curswant;
3110 curwin->w_virtcol = save_virtcol;
3111 curwin->w_valid &= ~VALID_VIRTCOL;
3112 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003113 }
3114 }
3115 else
3116 rettv->vval.v_number = FALSE;
3117}
3118
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003119/*
3120 * "getcurpos()" function
3121 */
3122 static void
3123f_getcurpos(typval_T *argvars, typval_T *rettv)
3124{
3125 getpos_both(argvars, rettv, TRUE);
3126}
3127
3128/*
3129 * "getpos(string)" function
3130 */
3131 static void
3132f_getpos(typval_T *argvars, typval_T *rettv)
3133{
3134 getpos_both(argvars, rettv, FALSE);
3135}
3136
3137/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003138 * "getreg()" function
3139 */
3140 static void
3141f_getreg(typval_T *argvars, typval_T *rettv)
3142{
3143 char_u *strregname;
3144 int regname;
3145 int arg2 = FALSE;
3146 int return_list = FALSE;
3147 int error = FALSE;
3148
3149 if (argvars[0].v_type != VAR_UNKNOWN)
3150 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003151 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003152 error = strregname == NULL;
3153 if (argvars[1].v_type != VAR_UNKNOWN)
3154 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003155 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003156 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003157 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003158 }
3159 }
3160 else
3161 strregname = get_vim_var_str(VV_REG);
3162
3163 if (error)
3164 return;
3165
3166 regname = (strregname == NULL ? '"' : *strregname);
3167 if (regname == 0)
3168 regname = '"';
3169
3170 if (return_list)
3171 {
3172 rettv->v_type = VAR_LIST;
3173 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3174 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3175 if (rettv->vval.v_list == NULL)
3176 (void)rettv_list_alloc(rettv);
3177 else
3178 ++rettv->vval.v_list->lv_refcount;
3179 }
3180 else
3181 {
3182 rettv->v_type = VAR_STRING;
3183 rettv->vval.v_string = get_reg_contents(regname,
3184 arg2 ? GREG_EXPR_SRC : 0);
3185 }
3186}
3187
3188/*
3189 * "getregtype()" function
3190 */
3191 static void
3192f_getregtype(typval_T *argvars, typval_T *rettv)
3193{
3194 char_u *strregname;
3195 int regname;
3196 char_u buf[NUMBUFLEN + 2];
3197 long reglen = 0;
3198
3199 if (argvars[0].v_type != VAR_UNKNOWN)
3200 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003201 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003202 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003203 {
3204 rettv->v_type = VAR_STRING;
3205 rettv->vval.v_string = NULL;
3206 return;
3207 }
3208 }
3209 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003210 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003211 strregname = get_vim_var_str(VV_REG);
3212
3213 regname = (strregname == NULL ? '"' : *strregname);
3214 if (regname == 0)
3215 regname = '"';
3216
3217 buf[0] = NUL;
3218 buf[1] = NUL;
3219 switch (get_reg_type(regname, &reglen))
3220 {
3221 case MLINE: buf[0] = 'V'; break;
3222 case MCHAR: buf[0] = 'v'; break;
3223 case MBLOCK:
3224 buf[0] = Ctrl_V;
3225 sprintf((char *)buf + 1, "%ld", reglen + 1);
3226 break;
3227 }
3228 rettv->v_type = VAR_STRING;
3229 rettv->vval.v_string = vim_strsave(buf);
3230}
3231
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003232/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003233 * "gettagstack()" function
3234 */
3235 static void
3236f_gettagstack(typval_T *argvars, typval_T *rettv)
3237{
3238 win_T *wp = curwin; // default is current window
3239
3240 if (rettv_dict_alloc(rettv) != OK)
3241 return;
3242
3243 if (argvars[0].v_type != VAR_UNKNOWN)
3244 {
3245 wp = find_win_by_nr_or_id(&argvars[0]);
3246 if (wp == NULL)
3247 return;
3248 }
3249
3250 get_tagstack(wp, rettv->vval.v_dict);
3251}
3252
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003253// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003254#include "version.h"
3255
3256/*
3257 * "has()" function
3258 */
3259 static void
3260f_has(typval_T *argvars, typval_T *rettv)
3261{
3262 int i;
3263 char_u *name;
3264 int n = FALSE;
3265 static char *(has_list[]) =
3266 {
3267#ifdef AMIGA
3268 "amiga",
3269# ifdef FEAT_ARP
3270 "arp",
3271# endif
3272#endif
3273#ifdef __BEOS__
3274 "beos",
3275#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003276#if defined(BSD) && !defined(MACOS_X)
3277 "bsd",
3278#endif
3279#ifdef hpux
3280 "hpux",
3281#endif
3282#ifdef __linux__
3283 "linux",
3284#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003285#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003286 "mac", // Mac OS X (and, once, Mac OS Classic)
3287 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003288# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003289 "macunix", // Mac OS X, with the darwin feature
3290 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003291# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003292#endif
3293#ifdef __QNX__
3294 "qnx",
3295#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003296#ifdef SUN_SYSTEM
3297 "sun",
3298#else
3299 "moon",
3300#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003301#ifdef UNIX
3302 "unix",
3303#endif
3304#ifdef VMS
3305 "vms",
3306#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003307#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308 "win32",
3309#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003310#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003311 "win32unix",
3312#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003313#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003314 "win64",
3315#endif
3316#ifdef EBCDIC
3317 "ebcdic",
3318#endif
3319#ifndef CASE_INSENSITIVE_FILENAME
3320 "fname_case",
3321#endif
3322#ifdef HAVE_ACL
3323 "acl",
3324#endif
3325#ifdef FEAT_ARABIC
3326 "arabic",
3327#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003328 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003329#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003330 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003331#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003332#ifdef FEAT_AUTOSERVERNAME
3333 "autoservername",
3334#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003335#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003336 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003337# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003338 "balloon_multiline",
3339# endif
3340#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003341#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003342 "balloon_eval_term",
3343#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003344#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3345 "builtin_terms",
3346# ifdef ALL_BUILTIN_TCAPS
3347 "all_builtin_terms",
3348# endif
3349#endif
3350#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003351 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003352 || defined(FEAT_GUI_MOTIF))
3353 "browsefilter",
3354#endif
3355#ifdef FEAT_BYTEOFF
3356 "byte_offset",
3357#endif
3358#ifdef FEAT_JOB_CHANNEL
3359 "channel",
3360#endif
3361#ifdef FEAT_CINDENT
3362 "cindent",
3363#endif
3364#ifdef FEAT_CLIENTSERVER
3365 "clientserver",
3366#endif
3367#ifdef FEAT_CLIPBOARD
3368 "clipboard",
3369#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003370 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003371 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003372 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003373#ifdef FEAT_CONCEAL
3374 "conceal",
3375#endif
3376#ifdef FEAT_CRYPT
3377 "cryptv",
3378 "crypt-blowfish",
3379 "crypt-blowfish2",
3380#endif
3381#ifdef FEAT_CSCOPE
3382 "cscope",
3383#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003384 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003385#ifdef CURSOR_SHAPE
3386 "cursorshape",
3387#endif
3388#ifdef DEBUG
3389 "debug",
3390#endif
3391#ifdef FEAT_CON_DIALOG
3392 "dialog_con",
3393#endif
3394#ifdef FEAT_GUI_DIALOG
3395 "dialog_gui",
3396#endif
3397#ifdef FEAT_DIFF
3398 "diff",
3399#endif
3400#ifdef FEAT_DIGRAPHS
3401 "digraphs",
3402#endif
3403#ifdef FEAT_DIRECTX
3404 "directx",
3405#endif
3406#ifdef FEAT_DND
3407 "dnd",
3408#endif
3409#ifdef FEAT_EMACS_TAGS
3410 "emacs_tags",
3411#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003412 "eval", // always present, of course!
3413 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414#ifdef FEAT_SEARCH_EXTRA
3415 "extra_search",
3416#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003417#ifdef FEAT_SEARCHPATH
3418 "file_in_path",
3419#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003420#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003421 "filterpipe",
3422#endif
3423#ifdef FEAT_FIND_ID
3424 "find_in_path",
3425#endif
3426#ifdef FEAT_FLOAT
3427 "float",
3428#endif
3429#ifdef FEAT_FOLDING
3430 "folding",
3431#endif
3432#ifdef FEAT_FOOTER
3433 "footer",
3434#endif
3435#if !defined(USE_SYSTEM) && defined(UNIX)
3436 "fork",
3437#endif
3438#ifdef FEAT_GETTEXT
3439 "gettext",
3440#endif
3441#ifdef FEAT_GUI
3442 "gui",
3443#endif
3444#ifdef FEAT_GUI_ATHENA
3445# ifdef FEAT_GUI_NEXTAW
3446 "gui_neXtaw",
3447# else
3448 "gui_athena",
3449# endif
3450#endif
3451#ifdef FEAT_GUI_GTK
3452 "gui_gtk",
3453# ifdef USE_GTK3
3454 "gui_gtk3",
3455# else
3456 "gui_gtk2",
3457# endif
3458#endif
3459#ifdef FEAT_GUI_GNOME
3460 "gui_gnome",
3461#endif
3462#ifdef FEAT_GUI_MAC
3463 "gui_mac",
3464#endif
3465#ifdef FEAT_GUI_MOTIF
3466 "gui_motif",
3467#endif
3468#ifdef FEAT_GUI_PHOTON
3469 "gui_photon",
3470#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003471#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472 "gui_win32",
3473#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003474#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3475 "iconv",
3476#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003477 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003478#ifdef FEAT_JOB_CHANNEL
3479 "job",
3480#endif
3481#ifdef FEAT_JUMPLIST
3482 "jumplist",
3483#endif
3484#ifdef FEAT_KEYMAP
3485 "keymap",
3486#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003487 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003488#ifdef FEAT_LANGMAP
3489 "langmap",
3490#endif
3491#ifdef FEAT_LIBCALL
3492 "libcall",
3493#endif
3494#ifdef FEAT_LINEBREAK
3495 "linebreak",
3496#endif
3497#ifdef FEAT_LISP
3498 "lispindent",
3499#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003500 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003501 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003502#ifdef FEAT_LUA
3503# ifndef DYNAMIC_LUA
3504 "lua",
3505# endif
3506#endif
3507#ifdef FEAT_MENU
3508 "menu",
3509#endif
3510#ifdef FEAT_SESSION
3511 "mksession",
3512#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003513 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003514 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003515#ifdef FEAT_MOUSESHAPE
3516 "mouseshape",
3517#endif
3518#if defined(UNIX) || defined(VMS)
3519# ifdef FEAT_MOUSE_DEC
3520 "mouse_dec",
3521# endif
3522# ifdef FEAT_MOUSE_GPM
3523 "mouse_gpm",
3524# endif
3525# ifdef FEAT_MOUSE_JSB
3526 "mouse_jsbterm",
3527# endif
3528# ifdef FEAT_MOUSE_NET
3529 "mouse_netterm",
3530# endif
3531# ifdef FEAT_MOUSE_PTERM
3532 "mouse_pterm",
3533# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003534# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003535 "mouse_sgr",
3536# endif
3537# ifdef FEAT_SYSMOUSE
3538 "mouse_sysmouse",
3539# endif
3540# ifdef FEAT_MOUSE_URXVT
3541 "mouse_urxvt",
3542# endif
3543# ifdef FEAT_MOUSE_XTERM
3544 "mouse_xterm",
3545# endif
3546#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003547 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003548#ifdef FEAT_MBYTE_IME
3549 "multi_byte_ime",
3550#endif
3551#ifdef FEAT_MULTI_LANG
3552 "multi_lang",
3553#endif
3554#ifdef FEAT_MZSCHEME
3555#ifndef DYNAMIC_MZSCHEME
3556 "mzscheme",
3557#endif
3558#endif
3559#ifdef FEAT_NUM64
3560 "num64",
3561#endif
3562#ifdef FEAT_OLE
3563 "ole",
3564#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003565#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003566 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003567#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568#ifdef FEAT_PATH_EXTRA
3569 "path_extra",
3570#endif
3571#ifdef FEAT_PERL
3572#ifndef DYNAMIC_PERL
3573 "perl",
3574#endif
3575#endif
3576#ifdef FEAT_PERSISTENT_UNDO
3577 "persistent_undo",
3578#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003579#if defined(FEAT_PYTHON)
3580 "python_compiled",
3581# if defined(DYNAMIC_PYTHON)
3582 "python_dynamic",
3583# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003584 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003585 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003586# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003587#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003588#if defined(FEAT_PYTHON3)
3589 "python3_compiled",
3590# if defined(DYNAMIC_PYTHON3)
3591 "python3_dynamic",
3592# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003593 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003594 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003595# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003596#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003597#ifdef FEAT_PROP_POPUP
3598 "popupwin",
3599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600#ifdef FEAT_POSTSCRIPT
3601 "postscript",
3602#endif
3603#ifdef FEAT_PRINTER
3604 "printer",
3605#endif
3606#ifdef FEAT_PROFILE
3607 "profile",
3608#endif
3609#ifdef FEAT_RELTIME
3610 "reltime",
3611#endif
3612#ifdef FEAT_QUICKFIX
3613 "quickfix",
3614#endif
3615#ifdef FEAT_RIGHTLEFT
3616 "rightleft",
3617#endif
3618#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3619 "ruby",
3620#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003621 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003622#ifdef FEAT_CMDL_INFO
3623 "showcmd",
3624 "cmdline_info",
3625#endif
3626#ifdef FEAT_SIGNS
3627 "signs",
3628#endif
3629#ifdef FEAT_SMARTINDENT
3630 "smartindent",
3631#endif
3632#ifdef STARTUPTIME
3633 "startuptime",
3634#endif
3635#ifdef FEAT_STL_OPT
3636 "statusline",
3637#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003638#ifdef FEAT_NETBEANS_INTG
3639 "netbeans_intg",
3640#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003641#ifdef FEAT_SOUND
3642 "sound",
3643#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644#ifdef FEAT_SPELL
3645 "spell",
3646#endif
3647#ifdef FEAT_SYN_HL
3648 "syntax",
3649#endif
3650#if defined(USE_SYSTEM) || !defined(UNIX)
3651 "system",
3652#endif
3653#ifdef FEAT_TAG_BINS
3654 "tag_binary",
3655#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003656#ifdef FEAT_TCL
3657# ifndef DYNAMIC_TCL
3658 "tcl",
3659# endif
3660#endif
3661#ifdef FEAT_TERMGUICOLORS
3662 "termguicolors",
3663#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003664#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003665 "terminal",
3666#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003667#ifdef TERMINFO
3668 "terminfo",
3669#endif
3670#ifdef FEAT_TERMRESPONSE
3671 "termresponse",
3672#endif
3673#ifdef FEAT_TEXTOBJ
3674 "textobjects",
3675#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003676#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003677 "textprop",
3678#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003679#ifdef HAVE_TGETENT
3680 "tgetent",
3681#endif
3682#ifdef FEAT_TIMERS
3683 "timers",
3684#endif
3685#ifdef FEAT_TITLE
3686 "title",
3687#endif
3688#ifdef FEAT_TOOLBAR
3689 "toolbar",
3690#endif
3691#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3692 "unnamedplus",
3693#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003694 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003695 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003696#ifdef FEAT_VARTABS
3697 "vartabs",
3698#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003699 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003700#ifdef FEAT_VIMINFO
3701 "viminfo",
3702#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003703 "vimscript-1",
3704 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003705 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003706 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003707 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003708 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003709 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003710 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003711#ifdef FEAT_VTP
3712 "vtp",
3713#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714#ifdef FEAT_WILDIGN
3715 "wildignore",
3716#endif
3717#ifdef FEAT_WILDMENU
3718 "wildmenu",
3719#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003721#ifdef FEAT_WAK
3722 "winaltkeys",
3723#endif
3724#ifdef FEAT_WRITEBACKUP
3725 "writebackup",
3726#endif
3727#ifdef FEAT_XIM
3728 "xim",
3729#endif
3730#ifdef FEAT_XFONTSET
3731 "xfontset",
3732#endif
3733#ifdef FEAT_XPM_W32
3734 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003735 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003736#else
3737# if defined(HAVE_XPM)
3738 "xpm",
3739# endif
3740#endif
3741#ifdef USE_XSMP
3742 "xsmp",
3743#endif
3744#ifdef USE_XSMP_INTERACT
3745 "xsmp_interact",
3746#endif
3747#ifdef FEAT_XCLIPBOARD
3748 "xterm_clipboard",
3749#endif
3750#ifdef FEAT_XTERM_SAVE
3751 "xterm_save",
3752#endif
3753#if defined(UNIX) && defined(FEAT_X11)
3754 "X11",
3755#endif
3756 NULL
3757 };
3758
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003759 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003760 for (i = 0; has_list[i] != NULL; ++i)
3761 if (STRICMP(name, has_list[i]) == 0)
3762 {
3763 n = TRUE;
3764 break;
3765 }
3766
3767 if (n == FALSE)
3768 {
3769 if (STRNICMP(name, "patch", 5) == 0)
3770 {
3771 if (name[5] == '-'
3772 && STRLEN(name) >= 11
3773 && vim_isdigit(name[6])
3774 && vim_isdigit(name[8])
3775 && vim_isdigit(name[10]))
3776 {
3777 int major = atoi((char *)name + 6);
3778 int minor = atoi((char *)name + 8);
3779
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003780 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003781 n = (major < VIM_VERSION_MAJOR
3782 || (major == VIM_VERSION_MAJOR
3783 && (minor < VIM_VERSION_MINOR
3784 || (minor == VIM_VERSION_MINOR
3785 && has_patch(atoi((char *)name + 10))))));
3786 }
3787 else
3788 n = has_patch(atoi((char *)name + 5));
3789 }
3790 else if (STRICMP(name, "vim_starting") == 0)
3791 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003792 else if (STRICMP(name, "ttyin") == 0)
3793 n = mch_input_isatty();
3794 else if (STRICMP(name, "ttyout") == 0)
3795 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003796 else if (STRICMP(name, "multi_byte_encoding") == 0)
3797 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003798#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003799 else if (STRICMP(name, "balloon_multiline") == 0)
3800 n = multiline_balloon_available();
3801#endif
3802#ifdef DYNAMIC_TCL
3803 else if (STRICMP(name, "tcl") == 0)
3804 n = tcl_enabled(FALSE);
3805#endif
3806#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3807 else if (STRICMP(name, "iconv") == 0)
3808 n = iconv_enabled(FALSE);
3809#endif
3810#ifdef DYNAMIC_LUA
3811 else if (STRICMP(name, "lua") == 0)
3812 n = lua_enabled(FALSE);
3813#endif
3814#ifdef DYNAMIC_MZSCHEME
3815 else if (STRICMP(name, "mzscheme") == 0)
3816 n = mzscheme_enabled(FALSE);
3817#endif
3818#ifdef DYNAMIC_RUBY
3819 else if (STRICMP(name, "ruby") == 0)
3820 n = ruby_enabled(FALSE);
3821#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003822#ifdef DYNAMIC_PYTHON
3823 else if (STRICMP(name, "python") == 0)
3824 n = python_enabled(FALSE);
3825#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826#ifdef DYNAMIC_PYTHON3
3827 else if (STRICMP(name, "python3") == 0)
3828 n = python3_enabled(FALSE);
3829#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003830#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3831 else if (STRICMP(name, "pythonx") == 0)
3832 {
3833# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3834 if (p_pyx == 0)
3835 n = python3_enabled(FALSE) || python_enabled(FALSE);
3836 else if (p_pyx == 3)
3837 n = python3_enabled(FALSE);
3838 else if (p_pyx == 2)
3839 n = python_enabled(FALSE);
3840# elif defined(DYNAMIC_PYTHON)
3841 n = python_enabled(FALSE);
3842# elif defined(DYNAMIC_PYTHON3)
3843 n = python3_enabled(FALSE);
3844# endif
3845 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003846#endif
3847#ifdef DYNAMIC_PERL
3848 else if (STRICMP(name, "perl") == 0)
3849 n = perl_enabled(FALSE);
3850#endif
3851#ifdef FEAT_GUI
3852 else if (STRICMP(name, "gui_running") == 0)
3853 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003854# ifdef FEAT_BROWSE
3855 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003856 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003857# endif
3858#endif
3859#ifdef FEAT_SYN_HL
3860 else if (STRICMP(name, "syntax_items") == 0)
3861 n = syntax_present(curwin);
3862#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003863#ifdef FEAT_VTP
3864 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003865 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003866#endif
3867#ifdef FEAT_NETBEANS_INTG
3868 else if (STRICMP(name, "netbeans_enabled") == 0)
3869 n = netbeans_active();
3870#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003871#ifdef FEAT_MOUSE_GPM
3872 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3873 n = gpm_enabled();
3874#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003875#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003876 else if (STRICMP(name, "terminal") == 0)
3877 n = terminal_enabled();
3878#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003879#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003880 else if (STRICMP(name, "conpty") == 0)
3881 n = use_conpty();
3882#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003883#ifdef FEAT_CLIPBOARD
3884 else if (STRICMP(name, "clipboard_working") == 0)
3885 n = clip_star.available;
3886#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003887#ifdef VIMDLL
3888 else if (STRICMP(name, "filterpipe") == 0)
3889 n = gui.in_use || gui.starting;
3890#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003891 }
3892
3893 rettv->vval.v_number = n;
3894}
3895
3896/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003897 * "haslocaldir()" function
3898 */
3899 static void
3900f_haslocaldir(typval_T *argvars, typval_T *rettv)
3901{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003902 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003903 win_T *wp = NULL;
3904
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003905 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3906
3907 // Check for window-local and tab-local directories
3908 if (wp != NULL && wp->w_localdir != NULL)
3909 rettv->vval.v_number = 1;
3910 else if (tp != NULL && tp->tp_localdir != NULL)
3911 rettv->vval.v_number = 2;
3912 else
3913 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003914}
3915
3916/*
3917 * "hasmapto()" function
3918 */
3919 static void
3920f_hasmapto(typval_T *argvars, typval_T *rettv)
3921{
3922 char_u *name;
3923 char_u *mode;
3924 char_u buf[NUMBUFLEN];
3925 int abbr = FALSE;
3926
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003927 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003928 if (argvars[1].v_type == VAR_UNKNOWN)
3929 mode = (char_u *)"nvo";
3930 else
3931 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003932 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003933 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003934 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003935 }
3936
3937 if (map_to_exists(name, mode, abbr))
3938 rettv->vval.v_number = TRUE;
3939 else
3940 rettv->vval.v_number = FALSE;
3941}
3942
3943/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003944 * "highlightID(name)" function
3945 */
3946 static void
3947f_hlID(typval_T *argvars, typval_T *rettv)
3948{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003949 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003950}
3951
3952/*
3953 * "highlight_exists()" function
3954 */
3955 static void
3956f_hlexists(typval_T *argvars, typval_T *rettv)
3957{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003958 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003959}
3960
3961/*
3962 * "hostname()" function
3963 */
3964 static void
3965f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3966{
3967 char_u hostname[256];
3968
3969 mch_get_host_name(hostname, 256);
3970 rettv->v_type = VAR_STRING;
3971 rettv->vval.v_string = vim_strsave(hostname);
3972}
3973
3974/*
3975 * iconv() function
3976 */
3977 static void
3978f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3979{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003980 char_u buf1[NUMBUFLEN];
3981 char_u buf2[NUMBUFLEN];
3982 char_u *from, *to, *str;
3983 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984
3985 rettv->v_type = VAR_STRING;
3986 rettv->vval.v_string = NULL;
3987
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003988 str = tv_get_string(&argvars[0]);
3989 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3990 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003991 vimconv.vc_type = CONV_NONE;
3992 convert_setup(&vimconv, from, to);
3993
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003994 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003995 if (vimconv.vc_type == CONV_NONE)
3996 rettv->vval.v_string = vim_strsave(str);
3997 else
3998 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
3999
4000 convert_setup(&vimconv, NULL, NULL);
4001 vim_free(from);
4002 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004003}
4004
4005/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004006 * "index()" function
4007 */
4008 static void
4009f_index(typval_T *argvars, typval_T *rettv)
4010{
4011 list_T *l;
4012 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004013 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004014 long idx = 0;
4015 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004016 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004017
4018 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004019 if (argvars[0].v_type == VAR_BLOB)
4020 {
4021 typval_T tv;
4022 int start = 0;
4023
4024 if (argvars[2].v_type != VAR_UNKNOWN)
4025 {
4026 start = tv_get_number_chk(&argvars[2], &error);
4027 if (error)
4028 return;
4029 }
4030 b = argvars[0].vval.v_blob;
4031 if (b == NULL)
4032 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004033 if (start < 0)
4034 {
4035 start = blob_len(b) + start;
4036 if (start < 0)
4037 start = 0;
4038 }
4039
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004040 for (idx = start; idx < blob_len(b); ++idx)
4041 {
4042 tv.v_type = VAR_NUMBER;
4043 tv.vval.v_number = blob_get(b, idx);
4044 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4045 {
4046 rettv->vval.v_number = idx;
4047 return;
4048 }
4049 }
4050 return;
4051 }
4052 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004053 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004054 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004055 return;
4056 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004057
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004058 l = argvars[0].vval.v_list;
4059 if (l != NULL)
4060 {
4061 item = l->lv_first;
4062 if (argvars[2].v_type != VAR_UNKNOWN)
4063 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004064 // Start at specified item. Use the cached index that list_find()
4065 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004066 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004067 idx = l->lv_idx;
4068 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004069 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 if (error)
4071 item = NULL;
4072 }
4073
4074 for ( ; item != NULL; item = item->li_next, ++idx)
4075 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4076 {
4077 rettv->vval.v_number = idx;
4078 break;
4079 }
4080 }
4081}
4082
4083static int inputsecret_flag = 0;
4084
4085/*
4086 * "input()" function
4087 * Also handles inputsecret() when inputsecret is set.
4088 */
4089 static void
4090f_input(typval_T *argvars, typval_T *rettv)
4091{
4092 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4093}
4094
4095/*
4096 * "inputdialog()" function
4097 */
4098 static void
4099f_inputdialog(typval_T *argvars, typval_T *rettv)
4100{
4101#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004102 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004103 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4104 {
4105 char_u *message;
4106 char_u buf[NUMBUFLEN];
4107 char_u *defstr = (char_u *)"";
4108
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004109 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004110 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004111 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004112 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4113 else
4114 IObuff[0] = NUL;
4115 if (message != NULL && defstr != NULL
4116 && do_dialog(VIM_QUESTION, NULL, message,
4117 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4118 rettv->vval.v_string = vim_strsave(IObuff);
4119 else
4120 {
4121 if (message != NULL && defstr != NULL
4122 && argvars[1].v_type != VAR_UNKNOWN
4123 && argvars[2].v_type != VAR_UNKNOWN)
4124 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004125 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004126 else
4127 rettv->vval.v_string = NULL;
4128 }
4129 rettv->v_type = VAR_STRING;
4130 }
4131 else
4132#endif
4133 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4134}
4135
4136/*
4137 * "inputlist()" function
4138 */
4139 static void
4140f_inputlist(typval_T *argvars, typval_T *rettv)
4141{
4142 listitem_T *li;
4143 int selected;
4144 int mouse_used;
4145
4146#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004147 // While starting up, there is no place to enter text. When running tests
4148 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004149 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004150 return;
4151#endif
4152 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4153 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004154 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004155 return;
4156 }
4157
4158 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004159 msg_row = Rows - 1; // for when 'cmdheight' > 1
4160 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004161 msg_scroll = TRUE;
4162 msg_clr_eos();
4163
4164 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4165 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004166 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004167 msg_putchar('\n');
4168 }
4169
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004170 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004171 selected = prompt_for_number(&mouse_used);
4172 if (mouse_used)
4173 selected -= lines_left;
4174
4175 rettv->vval.v_number = selected;
4176}
4177
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004178static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4179
4180/*
4181 * "inputrestore()" function
4182 */
4183 static void
4184f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4185{
4186 if (ga_userinput.ga_len > 0)
4187 {
4188 --ga_userinput.ga_len;
4189 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4190 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004191 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004192 }
4193 else if (p_verbose > 1)
4194 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004195 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004196 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004197 }
4198}
4199
4200/*
4201 * "inputsave()" function
4202 */
4203 static void
4204f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4205{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004206 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004207 if (ga_grow(&ga_userinput, 1) == OK)
4208 {
4209 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4210 + ga_userinput.ga_len);
4211 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004212 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004213 }
4214 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004215 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004216}
4217
4218/*
4219 * "inputsecret()" function
4220 */
4221 static void
4222f_inputsecret(typval_T *argvars, typval_T *rettv)
4223{
4224 ++cmdline_star;
4225 ++inputsecret_flag;
4226 f_input(argvars, rettv);
4227 --cmdline_star;
4228 --inputsecret_flag;
4229}
4230
4231/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004232 * "interrupt()" function
4233 */
4234 static void
4235f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4236{
4237 got_int = TRUE;
4238}
4239
4240/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004241 * "invert(expr)" function
4242 */
4243 static void
4244f_invert(typval_T *argvars, typval_T *rettv)
4245{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004246 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247}
4248
4249/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004250 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4251 * or it refers to a List or Dictionary that is locked.
4252 */
4253 static int
4254tv_islocked(typval_T *tv)
4255{
4256 return (tv->v_lock & VAR_LOCKED)
4257 || (tv->v_type == VAR_LIST
4258 && tv->vval.v_list != NULL
4259 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4260 || (tv->v_type == VAR_DICT
4261 && tv->vval.v_dict != NULL
4262 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4263}
4264
4265/*
4266 * "islocked()" function
4267 */
4268 static void
4269f_islocked(typval_T *argvars, typval_T *rettv)
4270{
4271 lval_T lv;
4272 char_u *end;
4273 dictitem_T *di;
4274
4275 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004276 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004277 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004278 if (end != NULL && lv.ll_name != NULL)
4279 {
4280 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004281 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004282 else
4283 {
4284 if (lv.ll_tv == NULL)
4285 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004286 di = find_var(lv.ll_name, NULL, TRUE);
4287 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004288 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004289 // Consider a variable locked when:
4290 // 1. the variable itself is locked
4291 // 2. the value of the variable is locked.
4292 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004293 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4294 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004295 }
4296 }
4297 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004298 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004299 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004300 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004301 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004302 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004303 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4304 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004305 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004306 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4307 }
4308 }
4309
4310 clear_lval(&lv);
4311}
4312
4313#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4314/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004315 * "isinf()" function
4316 */
4317 static void
4318f_isinf(typval_T *argvars, typval_T *rettv)
4319{
4320 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4321 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4322}
4323
4324/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004325 * "isnan()" function
4326 */
4327 static void
4328f_isnan(typval_T *argvars, typval_T *rettv)
4329{
4330 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4331 && isnan(argvars[0].vval.v_float);
4332}
4333#endif
4334
4335/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004336 * "last_buffer_nr()" function.
4337 */
4338 static void
4339f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4340{
4341 int n = 0;
4342 buf_T *buf;
4343
Bram Moolenaar29323592016-07-24 22:04:11 +02004344 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004345 if (n < buf->b_fnum)
4346 n = buf->b_fnum;
4347
4348 rettv->vval.v_number = n;
4349}
4350
4351/*
4352 * "len()" function
4353 */
4354 static void
4355f_len(typval_T *argvars, typval_T *rettv)
4356{
4357 switch (argvars[0].v_type)
4358 {
4359 case VAR_STRING:
4360 case VAR_NUMBER:
4361 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004362 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004363 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004364 case VAR_BLOB:
4365 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4366 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004367 case VAR_LIST:
4368 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4369 break;
4370 case VAR_DICT:
4371 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4372 break;
4373 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004374 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004375 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004376 case VAR_SPECIAL:
4377 case VAR_FLOAT:
4378 case VAR_FUNC:
4379 case VAR_PARTIAL:
4380 case VAR_JOB:
4381 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004382 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004383 break;
4384 }
4385}
4386
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004387 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004388libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004389{
4390#ifdef FEAT_LIBCALL
4391 char_u *string_in;
4392 char_u **string_result;
4393 int nr_result;
4394#endif
4395
4396 rettv->v_type = type;
4397 if (type != VAR_NUMBER)
4398 rettv->vval.v_string = NULL;
4399
4400 if (check_restricted() || check_secure())
4401 return;
4402
4403#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004404 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004405 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4406 {
4407 string_in = NULL;
4408 if (argvars[2].v_type == VAR_STRING)
4409 string_in = argvars[2].vval.v_string;
4410 if (type == VAR_NUMBER)
4411 string_result = NULL;
4412 else
4413 string_result = &rettv->vval.v_string;
4414 if (mch_libcall(argvars[0].vval.v_string,
4415 argvars[1].vval.v_string,
4416 string_in,
4417 argvars[2].vval.v_number,
4418 string_result,
4419 &nr_result) == OK
4420 && type == VAR_NUMBER)
4421 rettv->vval.v_number = nr_result;
4422 }
4423#endif
4424}
4425
4426/*
4427 * "libcall()" function
4428 */
4429 static void
4430f_libcall(typval_T *argvars, typval_T *rettv)
4431{
4432 libcall_common(argvars, rettv, VAR_STRING);
4433}
4434
4435/*
4436 * "libcallnr()" function
4437 */
4438 static void
4439f_libcallnr(typval_T *argvars, typval_T *rettv)
4440{
4441 libcall_common(argvars, rettv, VAR_NUMBER);
4442}
4443
4444/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004445 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004446 */
4447 static void
4448f_line(typval_T *argvars, typval_T *rettv)
4449{
4450 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004451 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004452 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004453 int id;
4454 tabpage_T *tp;
4455 win_T *wp;
4456 win_T *save_curwin;
4457 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004458
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004459 if (argvars[1].v_type != VAR_UNKNOWN)
4460 {
4461 // use window specified in the second argument
4462 id = (int)tv_get_number(&argvars[1]);
4463 wp = win_id2wp_tp(id, &tp);
4464 if (wp != NULL && tp != NULL)
4465 {
4466 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4467 == OK)
4468 {
4469 check_cursor();
4470 fp = var2fpos(&argvars[0], TRUE, &fnum);
4471 }
4472 restore_win_noblock(save_curwin, save_curtab, TRUE);
4473 }
4474 }
4475 else
4476 // use current window
4477 fp = var2fpos(&argvars[0], TRUE, &fnum);
4478
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004479 if (fp != NULL)
4480 lnum = fp->lnum;
4481 rettv->vval.v_number = lnum;
4482}
4483
4484/*
4485 * "line2byte(lnum)" function
4486 */
4487 static void
4488f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4489{
4490#ifndef FEAT_BYTEOFF
4491 rettv->vval.v_number = -1;
4492#else
4493 linenr_T lnum;
4494
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004495 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004496 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4497 rettv->vval.v_number = -1;
4498 else
4499 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4500 if (rettv->vval.v_number >= 0)
4501 ++rettv->vval.v_number;
4502#endif
4503}
4504
4505/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004506 * "localtime()" function
4507 */
4508 static void
4509f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4510{
4511 rettv->vval.v_number = (varnumber_T)time(NULL);
4512}
4513
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004514#ifdef FEAT_FLOAT
4515/*
4516 * "log()" function
4517 */
4518 static void
4519f_log(typval_T *argvars, typval_T *rettv)
4520{
4521 float_T f = 0.0;
4522
4523 rettv->v_type = VAR_FLOAT;
4524 if (get_float_arg(argvars, &f) == OK)
4525 rettv->vval.v_float = log(f);
4526 else
4527 rettv->vval.v_float = 0.0;
4528}
4529
4530/*
4531 * "log10()" function
4532 */
4533 static void
4534f_log10(typval_T *argvars, typval_T *rettv)
4535{
4536 float_T f = 0.0;
4537
4538 rettv->v_type = VAR_FLOAT;
4539 if (get_float_arg(argvars, &f) == OK)
4540 rettv->vval.v_float = log10(f);
4541 else
4542 rettv->vval.v_float = 0.0;
4543}
4544#endif
4545
4546#ifdef FEAT_LUA
4547/*
4548 * "luaeval()" function
4549 */
4550 static void
4551f_luaeval(typval_T *argvars, typval_T *rettv)
4552{
4553 char_u *str;
4554 char_u buf[NUMBUFLEN];
4555
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004556 if (check_restricted() || check_secure())
4557 return;
4558
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004559 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004560 do_luaeval(str, argvars + 1, rettv);
4561}
4562#endif
4563
4564/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004565 * "maparg()" function
4566 */
4567 static void
4568f_maparg(typval_T *argvars, typval_T *rettv)
4569{
4570 get_maparg(argvars, rettv, TRUE);
4571}
4572
4573/*
4574 * "mapcheck()" function
4575 */
4576 static void
4577f_mapcheck(typval_T *argvars, typval_T *rettv)
4578{
4579 get_maparg(argvars, rettv, FALSE);
4580}
4581
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004582typedef enum
4583{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004584 MATCH_END, // matchend()
4585 MATCH_MATCH, // match()
4586 MATCH_STR, // matchstr()
4587 MATCH_LIST, // matchlist()
4588 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004589} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004590
4591 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004592find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004593{
4594 char_u *str = NULL;
4595 long len = 0;
4596 char_u *expr = NULL;
4597 char_u *pat;
4598 regmatch_T regmatch;
4599 char_u patbuf[NUMBUFLEN];
4600 char_u strbuf[NUMBUFLEN];
4601 char_u *save_cpo;
4602 long start = 0;
4603 long nth = 1;
4604 colnr_T startcol = 0;
4605 int match = 0;
4606 list_T *l = NULL;
4607 listitem_T *li = NULL;
4608 long idx = 0;
4609 char_u *tofree = NULL;
4610
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004611 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004612 save_cpo = p_cpo;
4613 p_cpo = (char_u *)"";
4614
4615 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004616 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004617 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004618 // type MATCH_LIST: return empty list when there are no matches.
4619 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004620 if (rettv_list_alloc(rettv) == FAIL)
4621 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004622 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004623 && (list_append_string(rettv->vval.v_list,
4624 (char_u *)"", 0) == FAIL
4625 || list_append_number(rettv->vval.v_list,
4626 (varnumber_T)-1) == FAIL
4627 || list_append_number(rettv->vval.v_list,
4628 (varnumber_T)-1) == FAIL
4629 || list_append_number(rettv->vval.v_list,
4630 (varnumber_T)-1) == FAIL))
4631 {
4632 list_free(rettv->vval.v_list);
4633 rettv->vval.v_list = NULL;
4634 goto theend;
4635 }
4636 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004637 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004638 {
4639 rettv->v_type = VAR_STRING;
4640 rettv->vval.v_string = NULL;
4641 }
4642
4643 if (argvars[0].v_type == VAR_LIST)
4644 {
4645 if ((l = argvars[0].vval.v_list) == NULL)
4646 goto theend;
4647 li = l->lv_first;
4648 }
4649 else
4650 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004651 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004652 len = (long)STRLEN(str);
4653 }
4654
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004655 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004656 if (pat == NULL)
4657 goto theend;
4658
4659 if (argvars[2].v_type != VAR_UNKNOWN)
4660 {
4661 int error = FALSE;
4662
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004663 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004664 if (error)
4665 goto theend;
4666 if (l != NULL)
4667 {
4668 li = list_find(l, start);
4669 if (li == NULL)
4670 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004671 idx = l->lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004672 }
4673 else
4674 {
4675 if (start < 0)
4676 start = 0;
4677 if (start > len)
4678 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004679 // When "count" argument is there ignore matches before "start",
4680 // otherwise skip part of the string. Differs when pattern is "^"
4681 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004682 if (argvars[3].v_type != VAR_UNKNOWN)
4683 startcol = start;
4684 else
4685 {
4686 str += start;
4687 len -= start;
4688 }
4689 }
4690
4691 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004692 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 if (error)
4694 goto theend;
4695 }
4696
4697 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4698 if (regmatch.regprog != NULL)
4699 {
4700 regmatch.rm_ic = p_ic;
4701
4702 for (;;)
4703 {
4704 if (l != NULL)
4705 {
4706 if (li == NULL)
4707 {
4708 match = FALSE;
4709 break;
4710 }
4711 vim_free(tofree);
4712 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4713 if (str == NULL)
4714 break;
4715 }
4716
4717 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4718
4719 if (match && --nth <= 0)
4720 break;
4721 if (l == NULL && !match)
4722 break;
4723
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004724 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004725 if (l != NULL)
4726 {
4727 li = li->li_next;
4728 ++idx;
4729 }
4730 else
4731 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004732 startcol = (colnr_T)(regmatch.startp[0]
4733 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 if (startcol > (colnr_T)len
4735 || str + startcol <= regmatch.startp[0])
4736 {
4737 match = FALSE;
4738 break;
4739 }
4740 }
4741 }
4742
4743 if (match)
4744 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004745 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004746 {
4747 listitem_T *li1 = rettv->vval.v_list->lv_first;
4748 listitem_T *li2 = li1->li_next;
4749 listitem_T *li3 = li2->li_next;
4750 listitem_T *li4 = li3->li_next;
4751
4752 vim_free(li1->li_tv.vval.v_string);
4753 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4754 (int)(regmatch.endp[0] - regmatch.startp[0]));
4755 li3->li_tv.vval.v_number =
4756 (varnumber_T)(regmatch.startp[0] - expr);
4757 li4->li_tv.vval.v_number =
4758 (varnumber_T)(regmatch.endp[0] - expr);
4759 if (l != NULL)
4760 li2->li_tv.vval.v_number = (varnumber_T)idx;
4761 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004762 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004763 {
4764 int i;
4765
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004766 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004767 for (i = 0; i < NSUBEXP; ++i)
4768 {
4769 if (regmatch.endp[i] == NULL)
4770 {
4771 if (list_append_string(rettv->vval.v_list,
4772 (char_u *)"", 0) == FAIL)
4773 break;
4774 }
4775 else if (list_append_string(rettv->vval.v_list,
4776 regmatch.startp[i],
4777 (int)(regmatch.endp[i] - regmatch.startp[i]))
4778 == FAIL)
4779 break;
4780 }
4781 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004782 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004783 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004784 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004785 if (l != NULL)
4786 copy_tv(&li->li_tv, rettv);
4787 else
4788 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4789 (int)(regmatch.endp[0] - regmatch.startp[0]));
4790 }
4791 else if (l != NULL)
4792 rettv->vval.v_number = idx;
4793 else
4794 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004795 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796 rettv->vval.v_number =
4797 (varnumber_T)(regmatch.startp[0] - str);
4798 else
4799 rettv->vval.v_number =
4800 (varnumber_T)(regmatch.endp[0] - str);
4801 rettv->vval.v_number += (varnumber_T)(str - expr);
4802 }
4803 }
4804 vim_regfree(regmatch.regprog);
4805 }
4806
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004807theend:
4808 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004809 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004810 listitem_remove(rettv->vval.v_list,
4811 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004812 vim_free(tofree);
4813 p_cpo = save_cpo;
4814}
4815
4816/*
4817 * "match()" function
4818 */
4819 static void
4820f_match(typval_T *argvars, typval_T *rettv)
4821{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004822 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004823}
4824
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004825/*
4826 * "matchend()" function
4827 */
4828 static void
4829f_matchend(typval_T *argvars, typval_T *rettv)
4830{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004831 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004832}
4833
4834/*
4835 * "matchlist()" function
4836 */
4837 static void
4838f_matchlist(typval_T *argvars, typval_T *rettv)
4839{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004840 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841}
4842
4843/*
4844 * "matchstr()" function
4845 */
4846 static void
4847f_matchstr(typval_T *argvars, typval_T *rettv)
4848{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004849 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850}
4851
4852/*
4853 * "matchstrpos()" function
4854 */
4855 static void
4856f_matchstrpos(typval_T *argvars, typval_T *rettv)
4857{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004858 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859}
4860
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861 static void
4862max_min(typval_T *argvars, typval_T *rettv, int domax)
4863{
4864 varnumber_T n = 0;
4865 varnumber_T i;
4866 int error = FALSE;
4867
4868 if (argvars[0].v_type == VAR_LIST)
4869 {
4870 list_T *l;
4871 listitem_T *li;
4872
4873 l = argvars[0].vval.v_list;
4874 if (l != NULL)
4875 {
4876 li = l->lv_first;
4877 if (li != NULL)
4878 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004879 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004880 for (;;)
4881 {
4882 li = li->li_next;
4883 if (li == NULL)
4884 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004885 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004886 if (domax ? i > n : i < n)
4887 n = i;
4888 }
4889 }
4890 }
4891 }
4892 else if (argvars[0].v_type == VAR_DICT)
4893 {
4894 dict_T *d;
4895 int first = TRUE;
4896 hashitem_T *hi;
4897 int todo;
4898
4899 d = argvars[0].vval.v_dict;
4900 if (d != NULL)
4901 {
4902 todo = (int)d->dv_hashtab.ht_used;
4903 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4904 {
4905 if (!HASHITEM_EMPTY(hi))
4906 {
4907 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004908 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909 if (first)
4910 {
4911 n = i;
4912 first = FALSE;
4913 }
4914 else if (domax ? i > n : i < n)
4915 n = i;
4916 }
4917 }
4918 }
4919 }
4920 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004921 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004922 rettv->vval.v_number = error ? 0 : n;
4923}
4924
4925/*
4926 * "max()" function
4927 */
4928 static void
4929f_max(typval_T *argvars, typval_T *rettv)
4930{
4931 max_min(argvars, rettv, TRUE);
4932}
4933
4934/*
4935 * "min()" function
4936 */
4937 static void
4938f_min(typval_T *argvars, typval_T *rettv)
4939{
4940 max_min(argvars, rettv, FALSE);
4941}
4942
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004943#if defined(FEAT_MZSCHEME) || defined(PROTO)
4944/*
4945 * "mzeval()" function
4946 */
4947 static void
4948f_mzeval(typval_T *argvars, typval_T *rettv)
4949{
4950 char_u *str;
4951 char_u buf[NUMBUFLEN];
4952
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004953 if (check_restricted() || check_secure())
4954 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004955 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004956 do_mzeval(str, rettv);
4957}
4958
4959 void
4960mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4961{
4962 typval_T argvars[3];
4963
4964 argvars[0].v_type = VAR_STRING;
4965 argvars[0].vval.v_string = name;
4966 copy_tv(args, &argvars[1]);
4967 argvars[2].v_type = VAR_UNKNOWN;
4968 f_call(argvars, rettv);
4969 clear_tv(&argvars[1]);
4970}
4971#endif
4972
4973/*
4974 * "nextnonblank()" function
4975 */
4976 static void
4977f_nextnonblank(typval_T *argvars, typval_T *rettv)
4978{
4979 linenr_T lnum;
4980
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004981 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004982 {
4983 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
4984 {
4985 lnum = 0;
4986 break;
4987 }
4988 if (*skipwhite(ml_get(lnum)) != NUL)
4989 break;
4990 }
4991 rettv->vval.v_number = lnum;
4992}
4993
4994/*
4995 * "nr2char()" function
4996 */
4997 static void
4998f_nr2char(typval_T *argvars, typval_T *rettv)
4999{
5000 char_u buf[NUMBUFLEN];
5001
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005002 if (has_mbyte)
5003 {
5004 int utf8 = 0;
5005
5006 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005007 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005008 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005009 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005010 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005011 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005012 }
5013 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005014 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005015 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005016 buf[1] = NUL;
5017 }
5018 rettv->v_type = VAR_STRING;
5019 rettv->vval.v_string = vim_strsave(buf);
5020}
5021
5022/*
5023 * "or(expr, expr)" function
5024 */
5025 static void
5026f_or(typval_T *argvars, typval_T *rettv)
5027{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005028 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5029 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005030}
5031
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005032#ifdef FEAT_PERL
5033/*
5034 * "perleval()" function
5035 */
5036 static void
5037f_perleval(typval_T *argvars, typval_T *rettv)
5038{
5039 char_u *str;
5040 char_u buf[NUMBUFLEN];
5041
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005042 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005043 do_perleval(str, rettv);
5044}
5045#endif
5046
5047#ifdef FEAT_FLOAT
5048/*
5049 * "pow()" function
5050 */
5051 static void
5052f_pow(typval_T *argvars, typval_T *rettv)
5053{
5054 float_T fx = 0.0, fy = 0.0;
5055
5056 rettv->v_type = VAR_FLOAT;
5057 if (get_float_arg(argvars, &fx) == OK
5058 && get_float_arg(&argvars[1], &fy) == OK)
5059 rettv->vval.v_float = pow(fx, fy);
5060 else
5061 rettv->vval.v_float = 0.0;
5062}
5063#endif
5064
5065/*
5066 * "prevnonblank()" function
5067 */
5068 static void
5069f_prevnonblank(typval_T *argvars, typval_T *rettv)
5070{
5071 linenr_T lnum;
5072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005073 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005074 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5075 lnum = 0;
5076 else
5077 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5078 --lnum;
5079 rettv->vval.v_number = lnum;
5080}
5081
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005082// This dummy va_list is here because:
5083// - passing a NULL pointer doesn't work when va_list isn't a pointer
5084// - locally in the function results in a "used before set" warning
5085// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005086static va_list ap;
5087
5088/*
5089 * "printf()" function
5090 */
5091 static void
5092f_printf(typval_T *argvars, typval_T *rettv)
5093{
5094 char_u buf[NUMBUFLEN];
5095 int len;
5096 char_u *s;
5097 int saved_did_emsg = did_emsg;
5098 char *fmt;
5099
5100 rettv->v_type = VAR_STRING;
5101 rettv->vval.v_string = NULL;
5102
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005103 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005104 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005105 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005106 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 if (!did_emsg)
5108 {
5109 s = alloc(len + 1);
5110 if (s != NULL)
5111 {
5112 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005113 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5114 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115 }
5116 }
5117 did_emsg |= saved_did_emsg;
5118}
5119
5120/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005121 * "pum_getpos()" function
5122 */
5123 static void
5124f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5125{
5126 if (rettv_dict_alloc(rettv) != OK)
5127 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005128 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005129}
5130
5131/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005132 * "pumvisible()" function
5133 */
5134 static void
5135f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5136{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137 if (pum_visible())
5138 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005139}
5140
5141#ifdef FEAT_PYTHON3
5142/*
5143 * "py3eval()" function
5144 */
5145 static void
5146f_py3eval(typval_T *argvars, typval_T *rettv)
5147{
5148 char_u *str;
5149 char_u buf[NUMBUFLEN];
5150
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005151 if (check_restricted() || check_secure())
5152 return;
5153
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005154 if (p_pyx == 0)
5155 p_pyx = 3;
5156
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005157 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005158 do_py3eval(str, rettv);
5159}
5160#endif
5161
5162#ifdef FEAT_PYTHON
5163/*
5164 * "pyeval()" function
5165 */
5166 static void
5167f_pyeval(typval_T *argvars, typval_T *rettv)
5168{
5169 char_u *str;
5170 char_u buf[NUMBUFLEN];
5171
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005172 if (check_restricted() || check_secure())
5173 return;
5174
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005175 if (p_pyx == 0)
5176 p_pyx = 2;
5177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005178 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005179 do_pyeval(str, rettv);
5180}
5181#endif
5182
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005183#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5184/*
5185 * "pyxeval()" function
5186 */
5187 static void
5188f_pyxeval(typval_T *argvars, typval_T *rettv)
5189{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005190 if (check_restricted() || check_secure())
5191 return;
5192
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005193# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5194 init_pyxversion();
5195 if (p_pyx == 2)
5196 f_pyeval(argvars, rettv);
5197 else
5198 f_py3eval(argvars, rettv);
5199# elif defined(FEAT_PYTHON)
5200 f_pyeval(argvars, rettv);
5201# elif defined(FEAT_PYTHON3)
5202 f_py3eval(argvars, rettv);
5203# endif
5204}
5205#endif
5206
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005207/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005208 * "rand()" function
5209 */
5210 static void
5211f_rand(typval_T *argvars, typval_T *rettv)
5212{
5213 list_T *l = NULL;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005214 static list_T *globl = NULL;
5215 UINT32_T x, y, z, w, t, result;
5216 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005217
5218 if (argvars[0].v_type == VAR_UNKNOWN)
5219 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005220 // When no argument is given use the global seed list.
5221 if (globl == NULL)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005222 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005223 // Initialize the global seed list.
5224 f_srand(argvars, rettv);
5225 l = rettv->vval.v_list;
5226 if (l == NULL || list_len(l) != 4)
5227 {
5228 clear_tv(rettv);
5229 goto theend;
5230 }
5231 globl = l;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005232 }
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005233 else
5234 l = globl;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005235 }
5236 else if (argvars[0].v_type == VAR_LIST)
5237 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005238 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005239 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005240 goto theend;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005241 }
5242 else
5243 goto theend;
5244
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005245 lx = list_find(l, 0L);
5246 ly = list_find(l, 1L);
5247 lz = list_find(l, 2L);
5248 lw = list_find(l, 3L);
5249 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5250 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5251 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5252 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5253 x = (UINT32_T)lx->li_tv.vval.v_number;
5254 y = (UINT32_T)ly->li_tv.vval.v_number;
5255 z = (UINT32_T)lz->li_tv.vval.v_number;
5256 w = (UINT32_T)lw->li_tv.vval.v_number;
5257
5258 // SHUFFLE_XOSHIRO128STARSTAR
5259#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5260 result = ROTL(y * 5, 7) * 9;
5261 t = y << 9;
5262 z ^= x;
5263 w ^= y;
5264 y ^= z, x ^= w;
5265 z ^= t;
5266 w = ROTL(w, 11);
5267#undef ROTL
5268
5269 lx->li_tv.vval.v_number = (varnumber_T)x;
5270 ly->li_tv.vval.v_number = (varnumber_T)y;
5271 lz->li_tv.vval.v_number = (varnumber_T)z;
5272 lw->li_tv.vval.v_number = (varnumber_T)w;
5273
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005274 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005275 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005276 return;
5277
5278theend:
5279 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005280 rettv->v_type = VAR_NUMBER;
5281 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005282}
5283
5284/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005285 * "range()" function
5286 */
5287 static void
5288f_range(typval_T *argvars, typval_T *rettv)
5289{
5290 varnumber_T start;
5291 varnumber_T end;
5292 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005293 int error = FALSE;
5294
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005295 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296 if (argvars[1].v_type == VAR_UNKNOWN)
5297 {
5298 end = start - 1;
5299 start = 0;
5300 }
5301 else
5302 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005303 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005304 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005305 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005306 }
5307
5308 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005309 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005310 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005311 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005312 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005313 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005314 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005315 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005316 list_T *list = rettv->vval.v_list;
5317
5318 // Create a non-materialized list. This is much more efficient and
5319 // works with ":for". If used otherwise range_list_materialize() must
5320 // be called.
5321 list->lv_first = &range_list_item;
5322 list->lv_start = start;
5323 list->lv_end = end;
5324 list->lv_stride = stride;
5325 list->lv_len = (end - start + 1) / stride;
5326 }
5327}
5328
5329/*
5330 * If "list" is a non-materialized list then materialize it now.
5331 */
5332 void
5333range_list_materialize(list_T *list)
5334{
5335 if (list->lv_first == &range_list_item)
5336 {
5337 varnumber_T start = list->lv_start;
5338 varnumber_T end = list->lv_end;
5339 int stride = list->lv_stride;
5340 varnumber_T i;
5341
5342 list->lv_first = NULL;
5343 list->lv_last = NULL;
5344 list->lv_len = 0;
5345 list->lv_idx_item = NULL;
5346 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5347 if (list_append_number(list, (varnumber_T)i) == FAIL)
5348 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005349 }
5350}
5351
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005352 static void
5353return_register(int regname, typval_T *rettv)
5354{
5355 char_u buf[2] = {0, 0};
5356
5357 buf[0] = (char_u)regname;
5358 rettv->v_type = VAR_STRING;
5359 rettv->vval.v_string = vim_strsave(buf);
5360}
5361
5362/*
5363 * "reg_executing()" function
5364 */
5365 static void
5366f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5367{
5368 return_register(reg_executing, rettv);
5369}
5370
5371/*
5372 * "reg_recording()" function
5373 */
5374 static void
5375f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5376{
5377 return_register(reg_recording, rettv);
5378}
5379
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005380#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005381/*
5382 * Convert a List to proftime_T.
5383 * Return FAIL when there is something wrong.
5384 */
5385 static int
5386list2proftime(typval_T *arg, proftime_T *tm)
5387{
5388 long n1, n2;
5389 int error = FALSE;
5390
5391 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5392 || arg->vval.v_list->lv_len != 2)
5393 return FAIL;
5394 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5395 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005396# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005397 tm->HighPart = n1;
5398 tm->LowPart = n2;
5399# else
5400 tm->tv_sec = n1;
5401 tm->tv_usec = n2;
5402# endif
5403 return error ? FAIL : OK;
5404}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005405#endif // FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005406
5407/*
5408 * "reltime()" function
5409 */
5410 static void
5411f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5412{
5413#ifdef FEAT_RELTIME
5414 proftime_T res;
5415 proftime_T start;
5416
5417 if (argvars[0].v_type == VAR_UNKNOWN)
5418 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005419 // No arguments: get current time.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005420 profile_start(&res);
5421 }
5422 else if (argvars[1].v_type == VAR_UNKNOWN)
5423 {
5424 if (list2proftime(&argvars[0], &res) == FAIL)
5425 return;
5426 profile_end(&res);
5427 }
5428 else
5429 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005430 // Two arguments: compute the difference.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005431 if (list2proftime(&argvars[0], &start) == FAIL
5432 || list2proftime(&argvars[1], &res) == FAIL)
5433 return;
5434 profile_sub(&res, &start);
5435 }
5436
5437 if (rettv_list_alloc(rettv) == OK)
5438 {
5439 long n1, n2;
5440
Bram Moolenaar4f974752019-02-17 17:44:42 +01005441# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005442 n1 = res.HighPart;
5443 n2 = res.LowPart;
5444# else
5445 n1 = res.tv_sec;
5446 n2 = res.tv_usec;
5447# endif
5448 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5449 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5450 }
5451#endif
5452}
5453
5454#ifdef FEAT_FLOAT
5455/*
5456 * "reltimefloat()" function
5457 */
5458 static void
5459f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5460{
5461# ifdef FEAT_RELTIME
5462 proftime_T tm;
5463# endif
5464
5465 rettv->v_type = VAR_FLOAT;
5466 rettv->vval.v_float = 0;
5467# ifdef FEAT_RELTIME
5468 if (list2proftime(&argvars[0], &tm) == OK)
5469 rettv->vval.v_float = profile_float(&tm);
5470# endif
5471}
5472#endif
5473
5474/*
5475 * "reltimestr()" function
5476 */
5477 static void
5478f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5479{
5480#ifdef FEAT_RELTIME
5481 proftime_T tm;
5482#endif
5483
5484 rettv->v_type = VAR_STRING;
5485 rettv->vval.v_string = NULL;
5486#ifdef FEAT_RELTIME
5487 if (list2proftime(&argvars[0], &tm) == OK)
5488 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5489#endif
5490}
5491
5492#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005493 static void
5494make_connection(void)
5495{
5496 if (X_DISPLAY == NULL
5497# ifdef FEAT_GUI
5498 && !gui.in_use
5499# endif
5500 )
5501 {
5502 x_force_connect = TRUE;
5503 setup_term_clip();
5504 x_force_connect = FALSE;
5505 }
5506}
5507
5508 static int
5509check_connection(void)
5510{
5511 make_connection();
5512 if (X_DISPLAY == NULL)
5513 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005514 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005515 return FAIL;
5516 }
5517 return OK;
5518}
5519#endif
5520
5521#ifdef FEAT_CLIENTSERVER
5522 static void
5523remote_common(typval_T *argvars, typval_T *rettv, int expr)
5524{
5525 char_u *server_name;
5526 char_u *keys;
5527 char_u *r = NULL;
5528 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005529 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005530# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005531 HWND w;
5532# else
5533 Window w;
5534# endif
5535
5536 if (check_restricted() || check_secure())
5537 return;
5538
5539# ifdef FEAT_X11
5540 if (check_connection() == FAIL)
5541 return;
5542# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005543 if (argvars[2].v_type != VAR_UNKNOWN
5544 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005545 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005546
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005547 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005548 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005549 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005550 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005551# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005552 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005553# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005554 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5555 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005556# endif
5557 {
5558 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005559 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005560 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005561 vim_free(r);
5562 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005563 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005564 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005565 return;
5566 }
5567
5568 rettv->vval.v_string = r;
5569
5570 if (argvars[2].v_type != VAR_UNKNOWN)
5571 {
5572 dictitem_T v;
5573 char_u str[30];
5574 char_u *idvar;
5575
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005576 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005577 if (idvar != NULL && *idvar != NUL)
5578 {
5579 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5580 v.di_tv.v_type = VAR_STRING;
5581 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005582 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005583 vim_free(v.di_tv.vval.v_string);
5584 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005585 }
5586}
5587#endif
5588
5589/*
5590 * "remote_expr()" function
5591 */
5592 static void
5593f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5594{
5595 rettv->v_type = VAR_STRING;
5596 rettv->vval.v_string = NULL;
5597#ifdef FEAT_CLIENTSERVER
5598 remote_common(argvars, rettv, TRUE);
5599#endif
5600}
5601
5602/*
5603 * "remote_foreground()" function
5604 */
5605 static void
5606f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5607{
5608#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005609# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005610 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005611 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005612 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005613
5614 if (server_name != NULL)
5615 serverForeground(server_name);
5616 }
5617# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005618 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005619 argvars[1].v_type = VAR_STRING;
5620 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5621 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005622 rettv->v_type = VAR_STRING;
5623 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005624 remote_common(argvars, rettv, TRUE);
5625 vim_free(argvars[1].vval.v_string);
5626# endif
5627#endif
5628}
5629
5630 static void
5631f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5632{
5633#ifdef FEAT_CLIENTSERVER
5634 dictitem_T v;
5635 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005636# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005637 long_u n = 0;
5638# endif
5639 char_u *serverid;
5640
5641 if (check_restricted() || check_secure())
5642 {
5643 rettv->vval.v_number = -1;
5644 return;
5645 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005646 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005647 if (serverid == NULL)
5648 {
5649 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005650 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005651 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005652# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005653 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5654 if (n == 0)
5655 rettv->vval.v_number = -1;
5656 else
5657 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005658 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 rettv->vval.v_number = (s != NULL);
5660 }
5661# else
5662 if (check_connection() == FAIL)
5663 return;
5664
5665 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5666 serverStrToWin(serverid), &s);
5667# endif
5668
5669 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5670 {
5671 char_u *retvar;
5672
5673 v.di_tv.v_type = VAR_STRING;
5674 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005675 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005676 if (retvar != NULL)
5677 set_var(retvar, &v.di_tv, FALSE);
5678 vim_free(v.di_tv.vval.v_string);
5679 }
5680#else
5681 rettv->vval.v_number = -1;
5682#endif
5683}
5684
5685 static void
5686f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5687{
5688 char_u *r = NULL;
5689
5690#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005691 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005692
5693 if (serverid != NULL && !check_restricted() && !check_secure())
5694 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005695 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005696# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005697 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005698 long_u n = 0;
5699# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005700
5701 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005702 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005703
Bram Moolenaar4f974752019-02-17 17:44:42 +01005704# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005705 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5706 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005707 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005708 if (r == NULL)
5709# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005710 if (check_connection() == FAIL
5711 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5712 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005713# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005714 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005715 }
5716#endif
5717 rettv->v_type = VAR_STRING;
5718 rettv->vval.v_string = r;
5719}
5720
5721/*
5722 * "remote_send()" function
5723 */
5724 static void
5725f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5726{
5727 rettv->v_type = VAR_STRING;
5728 rettv->vval.v_string = NULL;
5729#ifdef FEAT_CLIENTSERVER
5730 remote_common(argvars, rettv, FALSE);
5731#endif
5732}
5733
5734/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005735 * "remote_startserver()" function
5736 */
5737 static void
5738f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5739{
5740#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005741 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005742
5743 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005744 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005745 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005746 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005747 else
5748 {
5749# ifdef FEAT_X11
5750 if (check_connection() == OK)
5751 serverRegisterName(X_DISPLAY, server);
5752# else
5753 serverSetName(server);
5754# endif
5755 }
5756#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005757 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005758#endif
5759}
5760
5761/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005762 * "rename({from}, {to})" function
5763 */
5764 static void
5765f_rename(typval_T *argvars, typval_T *rettv)
5766{
5767 char_u buf[NUMBUFLEN];
5768
5769 if (check_restricted() || check_secure())
5770 rettv->vval.v_number = -1;
5771 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005772 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5773 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005774}
5775
5776/*
5777 * "repeat()" function
5778 */
5779 static void
5780f_repeat(typval_T *argvars, typval_T *rettv)
5781{
5782 char_u *p;
5783 int n;
5784 int slen;
5785 int len;
5786 char_u *r;
5787 int i;
5788
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005789 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005790 if (argvars[0].v_type == VAR_LIST)
5791 {
5792 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5793 while (n-- > 0)
5794 if (list_extend(rettv->vval.v_list,
5795 argvars[0].vval.v_list, NULL) == FAIL)
5796 break;
5797 }
5798 else
5799 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005800 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005801 rettv->v_type = VAR_STRING;
5802 rettv->vval.v_string = NULL;
5803
5804 slen = (int)STRLEN(p);
5805 len = slen * n;
5806 if (len <= 0)
5807 return;
5808
5809 r = alloc(len + 1);
5810 if (r != NULL)
5811 {
5812 for (i = 0; i < n; i++)
5813 mch_memmove(r + i * slen, p, (size_t)slen);
5814 r[len] = NUL;
5815 }
5816
5817 rettv->vval.v_string = r;
5818 }
5819}
5820
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005821#define SP_NOMOVE 0x01 // don't move cursor
5822#define SP_REPEAT 0x02 // repeat to find outer pair
5823#define SP_RETCOUNT 0x04 // return matchcount
5824#define SP_SETPCMARK 0x08 // set previous context mark
5825#define SP_START 0x10 // accept match at start position
5826#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5827#define SP_END 0x40 // leave cursor at end of match
5828#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005830/*
5831 * Get flags for a search function.
5832 * Possibly sets "p_ws".
5833 * Returns BACKWARD, FORWARD or zero (for an error).
5834 */
5835 static int
5836get_search_arg(typval_T *varp, int *flagsp)
5837{
5838 int dir = FORWARD;
5839 char_u *flags;
5840 char_u nbuf[NUMBUFLEN];
5841 int mask;
5842
5843 if (varp->v_type != VAR_UNKNOWN)
5844 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005845 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005846 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005847 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005848 while (*flags != NUL)
5849 {
5850 switch (*flags)
5851 {
5852 case 'b': dir = BACKWARD; break;
5853 case 'w': p_ws = TRUE; break;
5854 case 'W': p_ws = FALSE; break;
5855 default: mask = 0;
5856 if (flagsp != NULL)
5857 switch (*flags)
5858 {
5859 case 'c': mask = SP_START; break;
5860 case 'e': mask = SP_END; break;
5861 case 'm': mask = SP_RETCOUNT; break;
5862 case 'n': mask = SP_NOMOVE; break;
5863 case 'p': mask = SP_SUBPAT; break;
5864 case 'r': mask = SP_REPEAT; break;
5865 case 's': mask = SP_SETPCMARK; break;
5866 case 'z': mask = SP_COLUMN; break;
5867 }
5868 if (mask == 0)
5869 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005870 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005871 dir = 0;
5872 }
5873 else
5874 *flagsp |= mask;
5875 }
5876 if (dir == 0)
5877 break;
5878 ++flags;
5879 }
5880 }
5881 return dir;
5882}
5883
5884/*
5885 * Shared by search() and searchpos() functions.
5886 */
5887 static int
5888search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5889{
5890 int flags;
5891 char_u *pat;
5892 pos_T pos;
5893 pos_T save_cursor;
5894 int save_p_ws = p_ws;
5895 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005896 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005897 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005898#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005899 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005900 long time_limit = 0;
5901#endif
5902 int options = SEARCH_KEEP;
5903 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005904 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005905
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005906 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005907 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005908 if (dir == 0)
5909 goto theend;
5910 flags = *flagsp;
5911 if (flags & SP_START)
5912 options |= SEARCH_START;
5913 if (flags & SP_END)
5914 options |= SEARCH_END;
5915 if (flags & SP_COLUMN)
5916 options |= SEARCH_COL;
5917
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005918 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005919 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5920 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005921 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005922 if (lnum_stop < 0)
5923 goto theend;
5924#ifdef FEAT_RELTIME
5925 if (argvars[3].v_type != VAR_UNKNOWN)
5926 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005927 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005928 if (time_limit < 0)
5929 goto theend;
5930 }
5931#endif
5932 }
5933
5934#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005935 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005936 profile_setlimit(time_limit, &tm);
5937#endif
5938
5939 /*
5940 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5941 * Check to make sure only those flags are set.
5942 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5943 * flags cannot be set. Check for that condition also.
5944 */
5945 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5946 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5947 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005948 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005949 goto theend;
5950 }
5951
5952 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005953 vim_memset(&sia, 0, sizeof(sia));
5954 sia.sa_stop_lnum = (linenr_T)lnum_stop;
5955#ifdef FEAT_RELTIME
5956 sia.sa_tm = &tm;
5957#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005958 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005959 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005960 if (subpatnum != FAIL)
5961 {
5962 if (flags & SP_SUBPAT)
5963 retval = subpatnum;
5964 else
5965 retval = pos.lnum;
5966 if (flags & SP_SETPCMARK)
5967 setpcmark();
5968 curwin->w_cursor = pos;
5969 if (match_pos != NULL)
5970 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005971 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972 match_pos->lnum = pos.lnum;
5973 match_pos->col = pos.col + 1;
5974 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005975 // "/$" will put the cursor after the end of the line, may need to
5976 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005977 check_cursor();
5978 }
5979
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005980 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005981 if (flags & SP_NOMOVE)
5982 curwin->w_cursor = save_cursor;
5983 else
5984 curwin->w_set_curswant = TRUE;
5985theend:
5986 p_ws = save_p_ws;
5987
5988 return retval;
5989}
5990
5991#ifdef FEAT_FLOAT
5992
5993/*
5994 * round() is not in C90, use ceil() or floor() instead.
5995 */
5996 float_T
5997vim_round(float_T f)
5998{
5999 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6000}
6001
6002/*
6003 * "round({float})" function
6004 */
6005 static void
6006f_round(typval_T *argvars, typval_T *rettv)
6007{
6008 float_T f = 0.0;
6009
6010 rettv->v_type = VAR_FLOAT;
6011 if (get_float_arg(argvars, &f) == OK)
6012 rettv->vval.v_float = vim_round(f);
6013 else
6014 rettv->vval.v_float = 0.0;
6015}
6016#endif
6017
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006018#ifdef FEAT_RUBY
6019/*
6020 * "rubyeval()" function
6021 */
6022 static void
6023f_rubyeval(typval_T *argvars, typval_T *rettv)
6024{
6025 char_u *str;
6026 char_u buf[NUMBUFLEN];
6027
6028 str = tv_get_string_buf(&argvars[0], buf);
6029 do_rubyeval(str, rettv);
6030}
6031#endif
6032
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006033/*
6034 * "screenattr()" function
6035 */
6036 static void
6037f_screenattr(typval_T *argvars, typval_T *rettv)
6038{
6039 int row;
6040 int col;
6041 int c;
6042
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006043 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6044 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006045 if (row < 0 || row >= screen_Rows
6046 || col < 0 || col >= screen_Columns)
6047 c = -1;
6048 else
6049 c = ScreenAttrs[LineOffset[row] + col];
6050 rettv->vval.v_number = c;
6051}
6052
6053/*
6054 * "screenchar()" function
6055 */
6056 static void
6057f_screenchar(typval_T *argvars, typval_T *rettv)
6058{
6059 int row;
6060 int col;
6061 int off;
6062 int c;
6063
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006064 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6065 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006066 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006067 c = -1;
6068 else
6069 {
6070 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006071 if (enc_utf8 && ScreenLinesUC[off] != 0)
6072 c = ScreenLinesUC[off];
6073 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006074 c = ScreenLines[off];
6075 }
6076 rettv->vval.v_number = c;
6077}
6078
6079/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006080 * "screenchars()" function
6081 */
6082 static void
6083f_screenchars(typval_T *argvars, typval_T *rettv)
6084{
6085 int row;
6086 int col;
6087 int off;
6088 int c;
6089 int i;
6090
6091 if (rettv_list_alloc(rettv) == FAIL)
6092 return;
6093 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6094 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6095 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6096 return;
6097
6098 off = LineOffset[row] + col;
6099 if (enc_utf8 && ScreenLinesUC[off] != 0)
6100 c = ScreenLinesUC[off];
6101 else
6102 c = ScreenLines[off];
6103 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6104
6105 if (enc_utf8)
6106
6107 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6108 list_append_number(rettv->vval.v_list,
6109 (varnumber_T)ScreenLinesC[i][off]);
6110}
6111
6112/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006113 * "screencol()" function
6114 *
6115 * First column is 1 to be consistent with virtcol().
6116 */
6117 static void
6118f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6119{
6120 rettv->vval.v_number = screen_screencol() + 1;
6121}
6122
6123/*
6124 * "screenrow()" function
6125 */
6126 static void
6127f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6128{
6129 rettv->vval.v_number = screen_screenrow() + 1;
6130}
6131
6132/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006133 * "screenstring()" function
6134 */
6135 static void
6136f_screenstring(typval_T *argvars, typval_T *rettv)
6137{
6138 int row;
6139 int col;
6140 int off;
6141 int c;
6142 int i;
6143 char_u buf[MB_MAXBYTES + 1];
6144 int buflen = 0;
6145
6146 rettv->vval.v_string = NULL;
6147 rettv->v_type = VAR_STRING;
6148
6149 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6150 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6151 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6152 return;
6153
6154 off = LineOffset[row] + col;
6155 if (enc_utf8 && ScreenLinesUC[off] != 0)
6156 c = ScreenLinesUC[off];
6157 else
6158 c = ScreenLines[off];
6159 buflen += mb_char2bytes(c, buf);
6160
6161 if (enc_utf8)
6162 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6163 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6164
6165 buf[buflen] = NUL;
6166 rettv->vval.v_string = vim_strsave(buf);
6167}
6168
6169/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006170 * "search()" function
6171 */
6172 static void
6173f_search(typval_T *argvars, typval_T *rettv)
6174{
6175 int flags = 0;
6176
6177 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6178}
6179
6180/*
6181 * "searchdecl()" function
6182 */
6183 static void
6184f_searchdecl(typval_T *argvars, typval_T *rettv)
6185{
6186 int locally = 1;
6187 int thisblock = 0;
6188 int error = FALSE;
6189 char_u *name;
6190
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006191 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006192
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006193 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 if (argvars[1].v_type != VAR_UNKNOWN)
6195 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006196 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006198 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006199 }
6200 if (!error && name != NULL)
6201 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6202 locally, thisblock, SEARCH_KEEP) == FAIL;
6203}
6204
6205/*
6206 * Used by searchpair() and searchpairpos()
6207 */
6208 static int
6209searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6210{
6211 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006212 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006213 int save_p_ws = p_ws;
6214 int dir;
6215 int flags = 0;
6216 char_u nbuf1[NUMBUFLEN];
6217 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006218 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006219 long lnum_stop = 0;
6220 long time_limit = 0;
6221
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006222 // Get the three pattern arguments: start, middle, end. Will result in an
6223 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006224 spat = tv_get_string_chk(&argvars[0]);
6225 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6226 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006227 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006228 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006229
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006230 // Handle the optional fourth argument: flags
6231 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006232 if (dir == 0)
6233 goto theend;
6234
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006235 // Don't accept SP_END or SP_SUBPAT.
6236 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006237 if ((flags & (SP_END | SP_SUBPAT)) != 0
6238 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6239 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006240 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006241 goto theend;
6242 }
6243
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006244 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006245 if (flags & SP_REPEAT)
6246 p_ws = FALSE;
6247
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006248 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006249 if (argvars[3].v_type == VAR_UNKNOWN
6250 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006251 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006252 else
6253 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006254 skip = &argvars[4];
6255 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6256 && skip->v_type != VAR_STRING)
6257 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006258 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006259 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006260 goto theend;
6261 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006262 if (argvars[5].v_type != VAR_UNKNOWN)
6263 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006264 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006265 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006266 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006267 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006269 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270#ifdef FEAT_RELTIME
6271 if (argvars[6].v_type != VAR_UNKNOWN)
6272 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006273 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006274 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006275 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006276 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006277 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006278 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006279 }
6280#endif
6281 }
6282 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006283
6284 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6285 match_pos, lnum_stop, time_limit);
6286
6287theend:
6288 p_ws = save_p_ws;
6289
6290 return retval;
6291}
6292
6293/*
6294 * "searchpair()" function
6295 */
6296 static void
6297f_searchpair(typval_T *argvars, typval_T *rettv)
6298{
6299 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6300}
6301
6302/*
6303 * "searchpairpos()" function
6304 */
6305 static void
6306f_searchpairpos(typval_T *argvars, typval_T *rettv)
6307{
6308 pos_T match_pos;
6309 int lnum = 0;
6310 int col = 0;
6311
6312 if (rettv_list_alloc(rettv) == FAIL)
6313 return;
6314
6315 if (searchpair_cmn(argvars, &match_pos) > 0)
6316 {
6317 lnum = match_pos.lnum;
6318 col = match_pos.col;
6319 }
6320
6321 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6322 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6323}
6324
6325/*
6326 * Search for a start/middle/end thing.
6327 * Used by searchpair(), see its documentation for the details.
6328 * Returns 0 or -1 for no match,
6329 */
6330 long
6331do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006332 char_u *spat, // start pattern
6333 char_u *mpat, // middle pattern
6334 char_u *epat, // end pattern
6335 int dir, // BACKWARD or FORWARD
6336 typval_T *skip, // skip expression
6337 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006338 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006339 linenr_T lnum_stop, // stop at this line if not zero
6340 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341{
6342 char_u *save_cpo;
6343 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6344 long retval = 0;
6345 pos_T pos;
6346 pos_T firstpos;
6347 pos_T foundpos;
6348 pos_T save_cursor;
6349 pos_T save_pos;
6350 int n;
6351 int r;
6352 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006353 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006354 int err;
6355 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006356#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006357 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006358#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006359
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006360 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006361 save_cpo = p_cpo;
6362 p_cpo = empty_option;
6363
6364#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006365 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006366 profile_setlimit(time_limit, &tm);
6367#endif
6368
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006369 // Make two search patterns: start/end (pat2, for in nested pairs) and
6370 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006371 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6372 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373 if (pat2 == NULL || pat3 == NULL)
6374 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006375 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376 if (*mpat == NUL)
6377 STRCPY(pat3, pat2);
6378 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006379 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006380 spat, epat, mpat);
6381 if (flags & SP_START)
6382 options |= SEARCH_START;
6383
Bram Moolenaar48570482017-10-30 21:48:41 +01006384 if (skip != NULL)
6385 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006386 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006387 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6388 use_skip = skip->vval.v_string != NULL
6389 && *skip->vval.v_string != NUL;
6390 }
6391
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006392 save_cursor = curwin->w_cursor;
6393 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006394 CLEAR_POS(&firstpos);
6395 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396 pat = pat3;
6397 for (;;)
6398 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006399 searchit_arg_T sia;
6400
6401 vim_memset(&sia, 0, sizeof(sia));
6402 sia.sa_stop_lnum = lnum_stop;
6403#ifdef FEAT_RELTIME
6404 sia.sa_tm = &tm;
6405#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006406 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006407 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006408 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006409 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006410 break;
6411
6412 if (firstpos.lnum == 0)
6413 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006414 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006416 // Found the same position again. Can happen with a pattern that
6417 // has "\zs" at the end and searching backwards. Advance one
6418 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006419 if (dir == BACKWARD)
6420 decl(&pos);
6421 else
6422 incl(&pos);
6423 }
6424 foundpos = pos;
6425
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006426 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006427 options &= ~SEARCH_START;
6428
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006429 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006430 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006431 {
6432 save_pos = curwin->w_cursor;
6433 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006434 err = FALSE;
6435 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006436 curwin->w_cursor = save_pos;
6437 if (err)
6438 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006439 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006440 curwin->w_cursor = save_cursor;
6441 retval = -1;
6442 break;
6443 }
6444 if (r)
6445 continue;
6446 }
6447
6448 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6449 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006450 // Found end when searching backwards or start when searching
6451 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006452 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006453 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006454 }
6455 else
6456 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006457 // Found end when searching forward or start when searching
6458 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006459 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006460 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006461 }
6462
6463 if (nest == 0)
6464 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006465 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006466 if (flags & SP_RETCOUNT)
6467 ++retval;
6468 else
6469 retval = pos.lnum;
6470 if (flags & SP_SETPCMARK)
6471 setpcmark();
6472 curwin->w_cursor = pos;
6473 if (!(flags & SP_REPEAT))
6474 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006475 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 }
6477 }
6478
6479 if (match_pos != NULL)
6480 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006481 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006482 match_pos->lnum = curwin->w_cursor.lnum;
6483 match_pos->col = curwin->w_cursor.col + 1;
6484 }
6485
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006486 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006487 if ((flags & SP_NOMOVE) || retval == 0)
6488 curwin->w_cursor = save_cursor;
6489
6490theend:
6491 vim_free(pat2);
6492 vim_free(pat3);
6493 if (p_cpo == empty_option)
6494 p_cpo = save_cpo;
6495 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006496 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006497 free_string_option(save_cpo);
6498
6499 return retval;
6500}
6501
6502/*
6503 * "searchpos()" function
6504 */
6505 static void
6506f_searchpos(typval_T *argvars, typval_T *rettv)
6507{
6508 pos_T match_pos;
6509 int lnum = 0;
6510 int col = 0;
6511 int n;
6512 int flags = 0;
6513
6514 if (rettv_list_alloc(rettv) == FAIL)
6515 return;
6516
6517 n = search_cmn(argvars, &match_pos, &flags);
6518 if (n > 0)
6519 {
6520 lnum = match_pos.lnum;
6521 col = match_pos.col;
6522 }
6523
6524 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6525 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6526 if (flags & SP_SUBPAT)
6527 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6528}
6529
6530 static void
6531f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6532{
6533#ifdef FEAT_CLIENTSERVER
6534 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006535 char_u *server = tv_get_string_chk(&argvars[0]);
6536 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006537
6538 rettv->vval.v_number = -1;
6539 if (server == NULL || reply == NULL)
6540 return;
6541 if (check_restricted() || check_secure())
6542 return;
6543# ifdef FEAT_X11
6544 if (check_connection() == FAIL)
6545 return;
6546# endif
6547
6548 if (serverSendReply(server, reply) < 0)
6549 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006550 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006551 return;
6552 }
6553 rettv->vval.v_number = 0;
6554#else
6555 rettv->vval.v_number = -1;
6556#endif
6557}
6558
6559 static void
6560f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6561{
6562 char_u *r = NULL;
6563
6564#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006565# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006566 r = serverGetVimNames();
6567# else
6568 make_connection();
6569 if (X_DISPLAY != NULL)
6570 r = serverGetVimNames(X_DISPLAY);
6571# endif
6572#endif
6573 rettv->v_type = VAR_STRING;
6574 rettv->vval.v_string = r;
6575}
6576
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006577 static void
6578f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6579{
6580 dict_T *d;
6581 dictitem_T *di;
6582 char_u *csearch;
6583
6584 if (argvars[0].v_type != VAR_DICT)
6585 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006586 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006587 return;
6588 }
6589
6590 if ((d = argvars[0].vval.v_dict) != NULL)
6591 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006592 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006593 if (csearch != NULL)
6594 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006595 if (enc_utf8)
6596 {
6597 int pcc[MAX_MCO];
6598 int c = utfc_ptr2char(csearch, pcc);
6599
6600 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6601 }
6602 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006603 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006604 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006605 }
6606
6607 di = dict_find(d, (char_u *)"forward", -1);
6608 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006609 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006610 ? FORWARD : BACKWARD);
6611
6612 di = dict_find(d, (char_u *)"until", -1);
6613 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006614 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006615 }
6616}
6617
6618/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006619 * "setenv()" function
6620 */
6621 static void
6622f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6623{
6624 char_u namebuf[NUMBUFLEN];
6625 char_u valbuf[NUMBUFLEN];
6626 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6627
6628 if (argvars[1].v_type == VAR_SPECIAL
6629 && argvars[1].vval.v_number == VVAL_NULL)
6630 vim_unsetenv(name);
6631 else
6632 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6633}
6634
6635/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006636 * "setfperm({fname}, {mode})" function
6637 */
6638 static void
6639f_setfperm(typval_T *argvars, typval_T *rettv)
6640{
6641 char_u *fname;
6642 char_u modebuf[NUMBUFLEN];
6643 char_u *mode_str;
6644 int i;
6645 int mask;
6646 int mode = 0;
6647
6648 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006649 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006650 if (fname == NULL)
6651 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006652 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006653 if (mode_str == NULL)
6654 return;
6655 if (STRLEN(mode_str) != 9)
6656 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006657 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006658 return;
6659 }
6660
6661 mask = 1;
6662 for (i = 8; i >= 0; --i)
6663 {
6664 if (mode_str[i] != '-')
6665 mode |= mask;
6666 mask = mask << 1;
6667 }
6668 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6669}
6670
6671/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006672 * "setpos()" function
6673 */
6674 static void
6675f_setpos(typval_T *argvars, typval_T *rettv)
6676{
6677 pos_T pos;
6678 int fnum;
6679 char_u *name;
6680 colnr_T curswant = -1;
6681
6682 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006683 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006684 if (name != NULL)
6685 {
6686 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6687 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006688 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006689 pos.col = 0;
6690 if (name[0] == '.' && name[1] == NUL)
6691 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006692 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006693 curwin->w_cursor = pos;
6694 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006695 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006696 curwin->w_curswant = curswant - 1;
6697 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006698 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006699 check_cursor();
6700 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 }
6702 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6703 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006704 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006705 if (setmark_pos(name[1], &pos, fnum) == OK)
6706 rettv->vval.v_number = 0;
6707 }
6708 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006709 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006710 }
6711 }
6712}
6713
6714/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006715 * "setreg()" function
6716 */
6717 static void
6718f_setreg(typval_T *argvars, typval_T *rettv)
6719{
6720 int regname;
6721 char_u *strregname;
6722 char_u *stropt;
6723 char_u *strval;
6724 int append;
6725 char_u yank_type;
6726 long block_len;
6727
6728 block_len = -1;
6729 yank_type = MAUTO;
6730 append = FALSE;
6731
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006732 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006733 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006734
6735 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006736 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006737 regname = *strregname;
6738 if (regname == 0 || regname == '@')
6739 regname = '"';
6740
6741 if (argvars[2].v_type != VAR_UNKNOWN)
6742 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006743 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006744 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006745 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006746 for (; *stropt != NUL; ++stropt)
6747 switch (*stropt)
6748 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006749 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006750 append = TRUE;
6751 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006752 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006753 yank_type = MCHAR;
6754 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006755 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006756 yank_type = MLINE;
6757 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006758 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006759 yank_type = MBLOCK;
6760 if (VIM_ISDIGIT(stropt[1]))
6761 {
6762 ++stropt;
6763 block_len = getdigits(&stropt) - 1;
6764 --stropt;
6765 }
6766 break;
6767 }
6768 }
6769
6770 if (argvars[1].v_type == VAR_LIST)
6771 {
6772 char_u **lstval;
6773 char_u **allocval;
6774 char_u buf[NUMBUFLEN];
6775 char_u **curval;
6776 char_u **curallocval;
6777 list_T *ll = argvars[1].vval.v_list;
6778 listitem_T *li;
6779 int len;
6780
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006781 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006782 len = ll == NULL ? 0 : ll->lv_len;
6783
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006784 // First half: use for pointers to result lines; second half: use for
6785 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006786 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006787 if (lstval == NULL)
6788 return;
6789 curval = lstval;
6790 allocval = lstval + len + 2;
6791 curallocval = allocval;
6792
6793 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6794 li = li->li_next)
6795 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006796 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006797 if (strval == NULL)
6798 goto free_lstval;
6799 if (strval == buf)
6800 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006801 // Need to make a copy, next tv_get_string_buf_chk() will
6802 // overwrite the string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006803 strval = vim_strsave(buf);
6804 if (strval == NULL)
6805 goto free_lstval;
6806 *curallocval++ = strval;
6807 }
6808 *curval++ = strval;
6809 }
6810 *curval++ = NULL;
6811
6812 write_reg_contents_lst(regname, lstval, -1,
6813 append, yank_type, block_len);
6814free_lstval:
6815 while (curallocval > allocval)
6816 vim_free(*--curallocval);
6817 vim_free(lstval);
6818 }
6819 else
6820 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006821 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006822 if (strval == NULL)
6823 return;
6824 write_reg_contents_ex(regname, strval, -1,
6825 append, yank_type, block_len);
6826 }
6827 rettv->vval.v_number = 0;
6828}
6829
6830/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006831 * "settagstack()" function
6832 */
6833 static void
6834f_settagstack(typval_T *argvars, typval_T *rettv)
6835{
6836 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6837 win_T *wp;
6838 dict_T *d;
6839 int action = 'r';
6840
6841 rettv->vval.v_number = -1;
6842
6843 // first argument: window number or id
6844 wp = find_win_by_nr_or_id(&argvars[0]);
6845 if (wp == NULL)
6846 return;
6847
6848 // second argument: dict with items to set in the tag stack
6849 if (argvars[1].v_type != VAR_DICT)
6850 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006851 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006852 return;
6853 }
6854 d = argvars[1].vval.v_dict;
6855 if (d == NULL)
6856 return;
6857
6858 // third argument: action - 'a' for append and 'r' for replace.
6859 // default is to replace the stack.
6860 if (argvars[2].v_type == VAR_UNKNOWN)
6861 action = 'r';
6862 else if (argvars[2].v_type == VAR_STRING)
6863 {
6864 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006865 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006866 if (actstr == NULL)
6867 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006868 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6869 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006870 action = *actstr;
6871 else
6872 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006873 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006874 return;
6875 }
6876 }
6877 else
6878 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006879 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006880 return;
6881 }
6882
6883 if (set_tagstack(wp, d, action) == OK)
6884 rettv->vval.v_number = 0;
6885}
6886
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006887#ifdef FEAT_CRYPT
6888/*
6889 * "sha256({string})" function
6890 */
6891 static void
6892f_sha256(typval_T *argvars, typval_T *rettv)
6893{
6894 char_u *p;
6895
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006896 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006897 rettv->vval.v_string = vim_strsave(
6898 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6899 rettv->v_type = VAR_STRING;
6900}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006901#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006902
6903/*
6904 * "shellescape({string})" function
6905 */
6906 static void
6907f_shellescape(typval_T *argvars, typval_T *rettv)
6908{
Bram Moolenaar20615522017-06-05 18:46:26 +02006909 int do_special = non_zero_arg(&argvars[1]);
6910
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006911 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006912 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006913 rettv->v_type = VAR_STRING;
6914}
6915
6916/*
6917 * shiftwidth() function
6918 */
6919 static void
6920f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6921{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006922 rettv->vval.v_number = 0;
6923
6924 if (argvars[0].v_type != VAR_UNKNOWN)
6925 {
6926 long col;
6927
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006928 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006929 if (col < 0)
6930 return; // type error; errmsg already given
6931#ifdef FEAT_VARTABS
6932 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6933 return;
6934#endif
6935 }
6936
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006937 rettv->vval.v_number = get_sw_value(curbuf);
6938}
6939
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006940#ifdef FEAT_FLOAT
6941/*
6942 * "sin()" function
6943 */
6944 static void
6945f_sin(typval_T *argvars, typval_T *rettv)
6946{
6947 float_T f = 0.0;
6948
6949 rettv->v_type = VAR_FLOAT;
6950 if (get_float_arg(argvars, &f) == OK)
6951 rettv->vval.v_float = sin(f);
6952 else
6953 rettv->vval.v_float = 0.0;
6954}
6955
6956/*
6957 * "sinh()" function
6958 */
6959 static void
6960f_sinh(typval_T *argvars, typval_T *rettv)
6961{
6962 float_T f = 0.0;
6963
6964 rettv->v_type = VAR_FLOAT;
6965 if (get_float_arg(argvars, &f) == OK)
6966 rettv->vval.v_float = sinh(f);
6967 else
6968 rettv->vval.v_float = 0.0;
6969}
6970#endif
6971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006972/*
6973 * "soundfold({word})" function
6974 */
6975 static void
6976f_soundfold(typval_T *argvars, typval_T *rettv)
6977{
6978 char_u *s;
6979
6980 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006981 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006982#ifdef FEAT_SPELL
6983 rettv->vval.v_string = eval_soundfold(s);
6984#else
6985 rettv->vval.v_string = vim_strsave(s);
6986#endif
6987}
6988
6989/*
6990 * "spellbadword()" function
6991 */
6992 static void
6993f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6994{
6995 char_u *word = (char_u *)"";
6996 hlf_T attr = HLF_COUNT;
6997 int len = 0;
6998
6999 if (rettv_list_alloc(rettv) == FAIL)
7000 return;
7001
7002#ifdef FEAT_SPELL
7003 if (argvars[0].v_type == VAR_UNKNOWN)
7004 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007005 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007006 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7007 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007008 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007009 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007010 curwin->w_set_curswant = TRUE;
7011 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007012 }
7013 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7014 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007015 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007016 int capcol = -1;
7017
7018 if (str != NULL)
7019 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007020 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007021 while (*str != NUL)
7022 {
7023 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7024 if (attr != HLF_COUNT)
7025 {
7026 word = str;
7027 break;
7028 }
7029 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007030 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007031 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007032 }
7033 }
7034 }
7035#endif
7036
7037 list_append_string(rettv->vval.v_list, word, len);
7038 list_append_string(rettv->vval.v_list, (char_u *)(
7039 attr == HLF_SPB ? "bad" :
7040 attr == HLF_SPR ? "rare" :
7041 attr == HLF_SPL ? "local" :
7042 attr == HLF_SPC ? "caps" :
7043 ""), -1);
7044}
7045
7046/*
7047 * "spellsuggest()" function
7048 */
7049 static void
7050f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7051{
7052#ifdef FEAT_SPELL
7053 char_u *str;
7054 int typeerr = FALSE;
7055 int maxcount;
7056 garray_T ga;
7057 int i;
7058 listitem_T *li;
7059 int need_capital = FALSE;
7060#endif
7061
7062 if (rettv_list_alloc(rettv) == FAIL)
7063 return;
7064
7065#ifdef FEAT_SPELL
7066 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7067 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007068 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069 if (argvars[1].v_type != VAR_UNKNOWN)
7070 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007071 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007072 if (maxcount <= 0)
7073 return;
7074 if (argvars[2].v_type != VAR_UNKNOWN)
7075 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007076 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007077 if (typeerr)
7078 return;
7079 }
7080 }
7081 else
7082 maxcount = 25;
7083
7084 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7085
7086 for (i = 0; i < ga.ga_len; ++i)
7087 {
7088 str = ((char_u **)ga.ga_data)[i];
7089
7090 li = listitem_alloc();
7091 if (li == NULL)
7092 vim_free(str);
7093 else
7094 {
7095 li->li_tv.v_type = VAR_STRING;
7096 li->li_tv.v_lock = 0;
7097 li->li_tv.vval.v_string = str;
7098 list_append(rettv->vval.v_list, li);
7099 }
7100 }
7101 ga_clear(&ga);
7102 }
7103#endif
7104}
7105
7106 static void
7107f_split(typval_T *argvars, typval_T *rettv)
7108{
7109 char_u *str;
7110 char_u *end;
7111 char_u *pat = NULL;
7112 regmatch_T regmatch;
7113 char_u patbuf[NUMBUFLEN];
7114 char_u *save_cpo;
7115 int match;
7116 colnr_T col = 0;
7117 int keepempty = FALSE;
7118 int typeerr = FALSE;
7119
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007120 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007121 save_cpo = p_cpo;
7122 p_cpo = (char_u *)"";
7123
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007124 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007125 if (argvars[1].v_type != VAR_UNKNOWN)
7126 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007127 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007128 if (pat == NULL)
7129 typeerr = TRUE;
7130 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007131 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007132 }
7133 if (pat == NULL || *pat == NUL)
7134 pat = (char_u *)"[\\x01- ]\\+";
7135
7136 if (rettv_list_alloc(rettv) == FAIL)
7137 return;
7138 if (typeerr)
7139 return;
7140
7141 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7142 if (regmatch.regprog != NULL)
7143 {
7144 regmatch.rm_ic = FALSE;
7145 while (*str != NUL || keepempty)
7146 {
7147 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007148 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007149 else
7150 match = vim_regexec_nl(&regmatch, str, col);
7151 if (match)
7152 end = regmatch.startp[0];
7153 else
7154 end = str + STRLEN(str);
7155 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7156 && *str != NUL && match && end < regmatch.endp[0]))
7157 {
7158 if (list_append_string(rettv->vval.v_list, str,
7159 (int)(end - str)) == FAIL)
7160 break;
7161 }
7162 if (!match)
7163 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007164 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007165 if (regmatch.endp[0] > str)
7166 col = 0;
7167 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007168 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007169 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007170 str = regmatch.endp[0];
7171 }
7172
7173 vim_regfree(regmatch.regprog);
7174 }
7175
7176 p_cpo = save_cpo;
7177}
7178
7179#ifdef FEAT_FLOAT
7180/*
7181 * "sqrt()" function
7182 */
7183 static void
7184f_sqrt(typval_T *argvars, typval_T *rettv)
7185{
7186 float_T f = 0.0;
7187
7188 rettv->v_type = VAR_FLOAT;
7189 if (get_float_arg(argvars, &f) == OK)
7190 rettv->vval.v_float = sqrt(f);
7191 else
7192 rettv->vval.v_float = 0.0;
7193}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007194#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007195
7196/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007197 * "srand()" function
7198 */
7199 static void
7200f_srand(typval_T *argvars, typval_T *rettv)
7201{
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007202 static int dev_urandom_state = -1; // FAIL or OK once tried
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007203 UINT32_T x = 0, z;
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007204
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007205 if (rettv_list_alloc(rettv) == FAIL)
7206 return;
7207 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007208 {
7209 if (dev_urandom_state != FAIL)
7210 {
7211 int fd = open("/dev/urandom", O_RDONLY);
7212 struct {
7213 union {
7214 UINT32_T number;
7215 char bytes[sizeof(UINT32_T)];
7216 } cont;
7217 } buf;
7218
7219 // Attempt reading /dev/urandom.
7220 if (fd == -1)
7221 dev_urandom_state = FAIL;
7222 else
7223 {
7224 buf.cont.number = 0;
7225 if (read(fd, buf.cont.bytes, sizeof(UINT32_T))
7226 != sizeof(UINT32_T))
7227 dev_urandom_state = FAIL;
7228 else
7229 {
7230 dev_urandom_state = OK;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007231 x = buf.cont.number;
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007232 }
7233 close(fd);
7234 }
7235
7236 }
7237 if (dev_urandom_state != OK)
7238 // Reading /dev/urandom doesn't work, fall back to time().
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007239 x = vim_time();
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007240 }
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007241 else
7242 {
7243 int error = FALSE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007244
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007245 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007246 if (error)
7247 return;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007248 }
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007249
7250#define SPLITMIX32 ( \
7251 z = (x += 0x9e3779b9), \
7252 z = (z ^ (z >> 16)) * 0x85ebca6b, \
7253 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
7254 z ^ (z >> 16) \
7255 )
7256
7257 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7258 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7259 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7260 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007261}
7262
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007263#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007264/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007265 * "str2float()" function
7266 */
7267 static void
7268f_str2float(typval_T *argvars, typval_T *rettv)
7269{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007270 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007271 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007272
Bram Moolenaar08243d22017-01-10 16:12:29 +01007273 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007274 p = skipwhite(p + 1);
7275 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007276 if (isneg)
7277 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007278 rettv->v_type = VAR_FLOAT;
7279}
7280#endif
7281
7282/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007283 * "str2list()" function
7284 */
7285 static void
7286f_str2list(typval_T *argvars, typval_T *rettv)
7287{
7288 char_u *p;
7289 int utf8 = FALSE;
7290
7291 if (rettv_list_alloc(rettv) == FAIL)
7292 return;
7293
7294 if (argvars[1].v_type != VAR_UNKNOWN)
7295 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7296
7297 p = tv_get_string(&argvars[0]);
7298
7299 if (has_mbyte || utf8)
7300 {
7301 int (*ptr2len)(char_u *);
7302 int (*ptr2char)(char_u *);
7303
7304 if (utf8 || enc_utf8)
7305 {
7306 ptr2len = utf_ptr2len;
7307 ptr2char = utf_ptr2char;
7308 }
7309 else
7310 {
7311 ptr2len = mb_ptr2len;
7312 ptr2char = mb_ptr2char;
7313 }
7314
7315 for ( ; *p != NUL; p += (*ptr2len)(p))
7316 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7317 }
7318 else
7319 for ( ; *p != NUL; ++p)
7320 list_append_number(rettv->vval.v_list, *p);
7321}
7322
7323/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007324 * "str2nr()" function
7325 */
7326 static void
7327f_str2nr(typval_T *argvars, typval_T *rettv)
7328{
7329 int base = 10;
7330 char_u *p;
7331 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007332 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007333 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007334
7335 if (argvars[1].v_type != VAR_UNKNOWN)
7336 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007337 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007338 if (base != 2 && base != 8 && base != 10 && base != 16)
7339 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007340 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007341 return;
7342 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007343 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7344 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 }
7346
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007347 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007348 isneg = (*p == '-');
7349 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350 p = skipwhite(p + 1);
7351 switch (base)
7352 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007353 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7354 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7355 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007357 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7358 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007359 if (isneg)
7360 rettv->vval.v_number = -n;
7361 else
7362 rettv->vval.v_number = n;
7363
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364}
7365
7366#ifdef HAVE_STRFTIME
7367/*
7368 * "strftime({format}[, {time}])" function
7369 */
7370 static void
7371f_strftime(typval_T *argvars, typval_T *rettv)
7372{
7373 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007374 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007375 struct tm *curtime;
7376 time_t seconds;
7377 char_u *p;
7378
7379 rettv->v_type = VAR_STRING;
7380
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007381 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 if (argvars[1].v_type == VAR_UNKNOWN)
7383 seconds = time(NULL);
7384 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007385 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007386 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007387 // MSVC returns NULL for an invalid value of seconds.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388 if (curtime == NULL)
7389 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7390 else
7391 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 vimconv_T conv;
7393 char_u *enc;
7394
7395 conv.vc_type = CONV_NONE;
7396 enc = enc_locale();
7397 convert_setup(&conv, p_enc, enc);
7398 if (conv.vc_type != CONV_NONE)
7399 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007400 if (p != NULL)
7401 (void)strftime((char *)result_buf, sizeof(result_buf),
7402 (char *)p, curtime);
7403 else
7404 result_buf[0] = NUL;
7405
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007406 if (conv.vc_type != CONV_NONE)
7407 vim_free(p);
7408 convert_setup(&conv, enc, p_enc);
7409 if (conv.vc_type != CONV_NONE)
7410 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7411 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412 rettv->vval.v_string = vim_strsave(result_buf);
7413
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007414 // Release conversion descriptors
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007415 convert_setup(&conv, NULL, NULL);
7416 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007417 }
7418}
7419#endif
7420
7421/*
7422 * "strgetchar()" function
7423 */
7424 static void
7425f_strgetchar(typval_T *argvars, typval_T *rettv)
7426{
7427 char_u *str;
7428 int len;
7429 int error = FALSE;
7430 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007431 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432
7433 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007434 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007435 if (str == NULL)
7436 return;
7437 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007438 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439 if (error)
7440 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441
Bram Moolenaar13505972019-01-24 15:04:48 +01007442 while (charidx >= 0 && byteidx < len)
7443 {
7444 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007445 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007446 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7447 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007448 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007449 --charidx;
7450 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007451 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007452}
7453
7454/*
7455 * "stridx()" function
7456 */
7457 static void
7458f_stridx(typval_T *argvars, typval_T *rettv)
7459{
7460 char_u buf[NUMBUFLEN];
7461 char_u *needle;
7462 char_u *haystack;
7463 char_u *save_haystack;
7464 char_u *pos;
7465 int start_idx;
7466
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007467 needle = tv_get_string_chk(&argvars[1]);
7468 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007469 rettv->vval.v_number = -1;
7470 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007471 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007472
7473 if (argvars[2].v_type != VAR_UNKNOWN)
7474 {
7475 int error = FALSE;
7476
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007477 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478 if (error || start_idx >= (int)STRLEN(haystack))
7479 return;
7480 if (start_idx >= 0)
7481 haystack += start_idx;
7482 }
7483
7484 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7485 if (pos != NULL)
7486 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7487}
7488
7489/*
7490 * "string()" function
7491 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007492 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007493f_string(typval_T *argvars, typval_T *rettv)
7494{
7495 char_u *tofree;
7496 char_u numbuf[NUMBUFLEN];
7497
7498 rettv->v_type = VAR_STRING;
7499 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7500 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007501 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007502 if (rettv->vval.v_string != NULL && tofree == NULL)
7503 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7504}
7505
7506/*
7507 * "strlen()" function
7508 */
7509 static void
7510f_strlen(typval_T *argvars, typval_T *rettv)
7511{
7512 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007513 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007514}
7515
7516/*
7517 * "strchars()" function
7518 */
7519 static void
7520f_strchars(typval_T *argvars, typval_T *rettv)
7521{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007522 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007523 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524 varnumber_T len = 0;
7525 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526
7527 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007528 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007530 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007531 else
7532 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007533 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7534 while (*s != NUL)
7535 {
7536 func_mb_ptr2char_adv(&s);
7537 ++len;
7538 }
7539 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540 }
7541}
7542
7543/*
7544 * "strdisplaywidth()" function
7545 */
7546 static void
7547f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7548{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007549 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007550 int col = 0;
7551
7552 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007553 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554
7555 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7556}
7557
7558/*
7559 * "strwidth()" function
7560 */
7561 static void
7562f_strwidth(typval_T *argvars, typval_T *rettv)
7563{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007564 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007565
Bram Moolenaar13505972019-01-24 15:04:48 +01007566 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567}
7568
7569/*
7570 * "strcharpart()" function
7571 */
7572 static void
7573f_strcharpart(typval_T *argvars, typval_T *rettv)
7574{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575 char_u *p;
7576 int nchar;
7577 int nbyte = 0;
7578 int charlen;
7579 int len = 0;
7580 int slen;
7581 int error = FALSE;
7582
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007583 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007584 slen = (int)STRLEN(p);
7585
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007586 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007587 if (!error)
7588 {
7589 if (nchar > 0)
7590 while (nchar > 0 && nbyte < slen)
7591 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007592 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007593 --nchar;
7594 }
7595 else
7596 nbyte = nchar;
7597 if (argvars[2].v_type != VAR_UNKNOWN)
7598 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007599 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007600 while (charlen > 0 && nbyte + len < slen)
7601 {
7602 int off = nbyte + len;
7603
7604 if (off < 0)
7605 len += 1;
7606 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007607 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007608 --charlen;
7609 }
7610 }
7611 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007612 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007613 }
7614
7615 /*
7616 * Only return the overlap between the specified part and the actual
7617 * string.
7618 */
7619 if (nbyte < 0)
7620 {
7621 len += nbyte;
7622 nbyte = 0;
7623 }
7624 else if (nbyte > slen)
7625 nbyte = slen;
7626 if (len < 0)
7627 len = 0;
7628 else if (nbyte + len > slen)
7629 len = slen - nbyte;
7630
7631 rettv->v_type = VAR_STRING;
7632 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633}
7634
7635/*
7636 * "strpart()" function
7637 */
7638 static void
7639f_strpart(typval_T *argvars, typval_T *rettv)
7640{
7641 char_u *p;
7642 int n;
7643 int len;
7644 int slen;
7645 int error = FALSE;
7646
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007647 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007648 slen = (int)STRLEN(p);
7649
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007650 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007651 if (error)
7652 len = 0;
7653 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007654 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007656 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007657
7658 /*
7659 * Only return the overlap between the specified part and the actual
7660 * string.
7661 */
7662 if (n < 0)
7663 {
7664 len += n;
7665 n = 0;
7666 }
7667 else if (n > slen)
7668 n = slen;
7669 if (len < 0)
7670 len = 0;
7671 else if (n + len > slen)
7672 len = slen - n;
7673
7674 rettv->v_type = VAR_STRING;
7675 rettv->vval.v_string = vim_strnsave(p + n, len);
7676}
7677
Bram Moolenaar10455d42019-11-21 15:36:18 +01007678#ifdef HAVE_STRPTIME
7679/*
7680 * "strptime({format}, {timestring})" function
7681 */
7682 static void
7683f_strptime(typval_T *argvars, typval_T *rettv)
7684{
7685 struct tm tmval;
7686 char_u *fmt;
7687 char_u *str;
7688 vimconv_T conv;
7689 char_u *enc;
7690
7691 vim_memset(&tmval, NUL, sizeof(tmval));
7692 fmt = tv_get_string(&argvars[0]);
7693 str = tv_get_string(&argvars[1]);
7694
7695 conv.vc_type = CONV_NONE;
7696 enc = enc_locale();
7697 convert_setup(&conv, p_enc, enc);
7698 if (conv.vc_type != CONV_NONE)
7699 fmt = string_convert(&conv, fmt, NULL);
7700 if (fmt == NULL
7701 || strptime((char *)str, (char *)fmt, &tmval) == NULL
7702 || (rettv->vval.v_number = mktime(&tmval)) == -1)
7703 rettv->vval.v_number = 0;
7704
7705 if (conv.vc_type != CONV_NONE)
7706 vim_free(fmt);
7707 convert_setup(&conv, NULL, NULL);
7708 vim_free(enc);
7709}
7710#endif
7711
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007712/*
7713 * "strridx()" function
7714 */
7715 static void
7716f_strridx(typval_T *argvars, typval_T *rettv)
7717{
7718 char_u buf[NUMBUFLEN];
7719 char_u *needle;
7720 char_u *haystack;
7721 char_u *rest;
7722 char_u *lastmatch = NULL;
7723 int haystack_len, end_idx;
7724
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007725 needle = tv_get_string_chk(&argvars[1]);
7726 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007727
7728 rettv->vval.v_number = -1;
7729 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007730 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007731
7732 haystack_len = (int)STRLEN(haystack);
7733 if (argvars[2].v_type != VAR_UNKNOWN)
7734 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007735 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007736 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007737 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007738 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007739 }
7740 else
7741 end_idx = haystack_len;
7742
7743 if (*needle == NUL)
7744 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007745 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746 lastmatch = haystack + end_idx;
7747 }
7748 else
7749 {
7750 for (rest = haystack; *rest != '\0'; ++rest)
7751 {
7752 rest = (char_u *)strstr((char *)rest, (char *)needle);
7753 if (rest == NULL || rest > haystack + end_idx)
7754 break;
7755 lastmatch = rest;
7756 }
7757 }
7758
7759 if (lastmatch == NULL)
7760 rettv->vval.v_number = -1;
7761 else
7762 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7763}
7764
7765/*
7766 * "strtrans()" function
7767 */
7768 static void
7769f_strtrans(typval_T *argvars, typval_T *rettv)
7770{
7771 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007772 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007773}
7774
7775/*
7776 * "submatch()" function
7777 */
7778 static void
7779f_submatch(typval_T *argvars, typval_T *rettv)
7780{
7781 int error = FALSE;
7782 int no;
7783 int retList = 0;
7784
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007785 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007786 if (error)
7787 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007788 if (no < 0 || no >= NSUBEXP)
7789 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007790 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007791 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007792 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007793 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007794 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795 if (error)
7796 return;
7797
7798 if (retList == 0)
7799 {
7800 rettv->v_type = VAR_STRING;
7801 rettv->vval.v_string = reg_submatch(no);
7802 }
7803 else
7804 {
7805 rettv->v_type = VAR_LIST;
7806 rettv->vval.v_list = reg_submatch_list(no);
7807 }
7808}
7809
7810/*
7811 * "substitute()" function
7812 */
7813 static void
7814f_substitute(typval_T *argvars, typval_T *rettv)
7815{
7816 char_u patbuf[NUMBUFLEN];
7817 char_u subbuf[NUMBUFLEN];
7818 char_u flagsbuf[NUMBUFLEN];
7819
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007820 char_u *str = tv_get_string_chk(&argvars[0]);
7821 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007822 char_u *sub = NULL;
7823 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007824 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007825
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007826 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7827 expr = &argvars[2];
7828 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007829 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007830
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007831 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007832 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7833 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007834 rettv->vval.v_string = NULL;
7835 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007836 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007837}
7838
7839/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007840 * "swapinfo(swap_filename)" function
7841 */
7842 static void
7843f_swapinfo(typval_T *argvars, typval_T *rettv)
7844{
7845 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007846 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007847}
7848
7849/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007850 * "swapname(expr)" function
7851 */
7852 static void
7853f_swapname(typval_T *argvars, typval_T *rettv)
7854{
7855 buf_T *buf;
7856
7857 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007858 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007859 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7860 || buf->b_ml.ml_mfp->mf_fname == NULL)
7861 rettv->vval.v_string = NULL;
7862 else
7863 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7864}
7865
7866/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007867 * "synID(lnum, col, trans)" function
7868 */
7869 static void
7870f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7871{
7872 int id = 0;
7873#ifdef FEAT_SYN_HL
7874 linenr_T lnum;
7875 colnr_T col;
7876 int trans;
7877 int transerr = FALSE;
7878
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007879 lnum = tv_get_lnum(argvars); // -1 on type error
7880 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007881 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882
7883 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7884 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7885 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7886#endif
7887
7888 rettv->vval.v_number = id;
7889}
7890
7891/*
7892 * "synIDattr(id, what [, mode])" function
7893 */
7894 static void
7895f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7896{
7897 char_u *p = NULL;
7898#ifdef FEAT_SYN_HL
7899 int id;
7900 char_u *what;
7901 char_u *mode;
7902 char_u modebuf[NUMBUFLEN];
7903 int modec;
7904
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007905 id = (int)tv_get_number(&argvars[0]);
7906 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007907 if (argvars[2].v_type != VAR_UNKNOWN)
7908 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007909 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910 modec = TOLOWER_ASC(mode[0]);
7911 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007912 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007913 }
7914 else
7915 {
7916#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7917 if (USE_24BIT)
7918 modec = 'g';
7919 else
7920#endif
7921 if (t_colors > 1)
7922 modec = 'c';
7923 else
7924 modec = 't';
7925 }
7926
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007927 switch (TOLOWER_ASC(what[0]))
7928 {
7929 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007930 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007932 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007933 p = highlight_has_attr(id, HL_BOLD, modec);
7934 break;
7935
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007936 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 p = highlight_color(id, what, modec);
7938 break;
7939
7940 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007941 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007943 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007944 p = highlight_has_attr(id, HL_ITALIC, modec);
7945 break;
7946
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007947 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007948 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007949 break;
7950
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007951 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007952 p = highlight_has_attr(id, HL_INVERSE, modec);
7953 break;
7954
7955 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007956 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007957 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007958 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007959 else if (TOLOWER_ASC(what[1]) == 't' &&
7960 TOLOWER_ASC(what[2]) == 'r')
7961 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007962 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007963 p = highlight_has_attr(id, HL_STANDOUT, modec);
7964 break;
7965
7966 case 'u':
7967 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007968 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007969 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7970 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007971 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007972 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7973 break;
7974 }
7975
7976 if (p != NULL)
7977 p = vim_strsave(p);
7978#endif
7979 rettv->v_type = VAR_STRING;
7980 rettv->vval.v_string = p;
7981}
7982
7983/*
7984 * "synIDtrans(id)" function
7985 */
7986 static void
7987f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7988{
7989 int id;
7990
7991#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007992 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993
7994 if (id > 0)
7995 id = syn_get_final_id(id);
7996 else
7997#endif
7998 id = 0;
7999
8000 rettv->vval.v_number = id;
8001}
8002
8003/*
8004 * "synconcealed(lnum, col)" function
8005 */
8006 static void
8007f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8008{
8009#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8010 linenr_T lnum;
8011 colnr_T col;
8012 int syntax_flags = 0;
8013 int cchar;
8014 int matchid = 0;
8015 char_u str[NUMBUFLEN];
8016#endif
8017
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008018 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008019
8020#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008021 lnum = tv_get_lnum(argvars); // -1 on type error
8022 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023
8024 vim_memset(str, NUL, sizeof(str));
8025
8026 if (rettv_list_alloc(rettv) != FAIL)
8027 {
8028 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8029 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8030 && curwin->w_p_cole > 0)
8031 {
8032 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8033 syntax_flags = get_syntax_info(&matchid);
8034
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008035 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008036 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8037 {
8038 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008039 if (cchar == NUL && curwin->w_p_cole == 1)
8040 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008041 if (cchar != NUL)
8042 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008043 if (has_mbyte)
8044 (*mb_char2bytes)(cchar, str);
8045 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008046 str[0] = cchar;
8047 }
8048 }
8049 }
8050
8051 list_append_number(rettv->vval.v_list,
8052 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008053 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008054 list_append_string(rettv->vval.v_list, str, -1);
8055 list_append_number(rettv->vval.v_list, matchid);
8056 }
8057#endif
8058}
8059
8060/*
8061 * "synstack(lnum, col)" function
8062 */
8063 static void
8064f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8065{
8066#ifdef FEAT_SYN_HL
8067 linenr_T lnum;
8068 colnr_T col;
8069 int i;
8070 int id;
8071#endif
8072
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008073 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008074
8075#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008076 lnum = tv_get_lnum(argvars); // -1 on type error
8077 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008078
8079 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8080 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8081 && rettv_list_alloc(rettv) != FAIL)
8082 {
8083 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8084 for (i = 0; ; ++i)
8085 {
8086 id = syn_get_stack_item(i);
8087 if (id < 0)
8088 break;
8089 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8090 break;
8091 }
8092 }
8093#endif
8094}
8095
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008096/*
8097 * "tabpagebuflist()" function
8098 */
8099 static void
8100f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8101{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008102 tabpage_T *tp;
8103 win_T *wp = NULL;
8104
8105 if (argvars[0].v_type == VAR_UNKNOWN)
8106 wp = firstwin;
8107 else
8108 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008109 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008110 if (tp != NULL)
8111 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8112 }
8113 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8114 {
8115 for (; wp != NULL; wp = wp->w_next)
8116 if (list_append_number(rettv->vval.v_list,
8117 wp->w_buffer->b_fnum) == FAIL)
8118 break;
8119 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008120}
8121
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008123 * "tagfiles()" function
8124 */
8125 static void
8126f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8127{
8128 char_u *fname;
8129 tagname_T tn;
8130 int first;
8131
8132 if (rettv_list_alloc(rettv) == FAIL)
8133 return;
8134 fname = alloc(MAXPATHL);
8135 if (fname == NULL)
8136 return;
8137
8138 for (first = TRUE; ; first = FALSE)
8139 if (get_tagfname(&tn, first, fname) == FAIL
8140 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8141 break;
8142 tagname_free(&tn);
8143 vim_free(fname);
8144}
8145
8146/*
8147 * "taglist()" function
8148 */
8149 static void
8150f_taglist(typval_T *argvars, typval_T *rettv)
8151{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008152 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008153 char_u *tag_pattern;
8154
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008155 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008156
8157 rettv->vval.v_number = FALSE;
8158 if (*tag_pattern == NUL)
8159 return;
8160
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008161 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008162 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008164 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165}
8166
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008167#ifdef FEAT_FLOAT
8168/*
8169 * "tan()" function
8170 */
8171 static void
8172f_tan(typval_T *argvars, typval_T *rettv)
8173{
8174 float_T f = 0.0;
8175
8176 rettv->v_type = VAR_FLOAT;
8177 if (get_float_arg(argvars, &f) == OK)
8178 rettv->vval.v_float = tan(f);
8179 else
8180 rettv->vval.v_float = 0.0;
8181}
8182
8183/*
8184 * "tanh()" function
8185 */
8186 static void
8187f_tanh(typval_T *argvars, typval_T *rettv)
8188{
8189 float_T f = 0.0;
8190
8191 rettv->v_type = VAR_FLOAT;
8192 if (get_float_arg(argvars, &f) == OK)
8193 rettv->vval.v_float = tanh(f);
8194 else
8195 rettv->vval.v_float = 0.0;
8196}
8197#endif
8198
8199/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008200 * "tolower(string)" function
8201 */
8202 static void
8203f_tolower(typval_T *argvars, typval_T *rettv)
8204{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008205 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008206 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008207}
8208
8209/*
8210 * "toupper(string)" function
8211 */
8212 static void
8213f_toupper(typval_T *argvars, typval_T *rettv)
8214{
8215 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008216 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008217}
8218
8219/*
8220 * "tr(string, fromstr, tostr)" function
8221 */
8222 static void
8223f_tr(typval_T *argvars, typval_T *rettv)
8224{
8225 char_u *in_str;
8226 char_u *fromstr;
8227 char_u *tostr;
8228 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008229 int inlen;
8230 int fromlen;
8231 int tolen;
8232 int idx;
8233 char_u *cpstr;
8234 int cplen;
8235 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008236 char_u buf[NUMBUFLEN];
8237 char_u buf2[NUMBUFLEN];
8238 garray_T ga;
8239
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008240 in_str = tv_get_string(&argvars[0]);
8241 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8242 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008243
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008244 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008245 rettv->v_type = VAR_STRING;
8246 rettv->vval.v_string = NULL;
8247 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008248 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008249 ga_init2(&ga, (int)sizeof(char), 80);
8250
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008251 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008252 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008253 if (STRLEN(fromstr) != STRLEN(tostr))
8254 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008255error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008256 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008257 ga_clear(&ga);
8258 return;
8259 }
8260
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008261 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008262 while (*in_str != NUL)
8263 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008264 if (has_mbyte)
8265 {
8266 inlen = (*mb_ptr2len)(in_str);
8267 cpstr = in_str;
8268 cplen = inlen;
8269 idx = 0;
8270 for (p = fromstr; *p != NUL; p += fromlen)
8271 {
8272 fromlen = (*mb_ptr2len)(p);
8273 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8274 {
8275 for (p = tostr; *p != NUL; p += tolen)
8276 {
8277 tolen = (*mb_ptr2len)(p);
8278 if (idx-- == 0)
8279 {
8280 cplen = tolen;
8281 cpstr = p;
8282 break;
8283 }
8284 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008285 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008286 goto error;
8287 break;
8288 }
8289 ++idx;
8290 }
8291
8292 if (first && cpstr == in_str)
8293 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008294 // Check that fromstr and tostr have the same number of
8295 // (multi-byte) characters. Done only once when a character
8296 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008297 first = FALSE;
8298 for (p = tostr; *p != NUL; p += tolen)
8299 {
8300 tolen = (*mb_ptr2len)(p);
8301 --idx;
8302 }
8303 if (idx != 0)
8304 goto error;
8305 }
8306
8307 (void)ga_grow(&ga, cplen);
8308 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8309 ga.ga_len += cplen;
8310
8311 in_str += inlen;
8312 }
8313 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008314 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008315 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316 p = vim_strchr(fromstr, *in_str);
8317 if (p != NULL)
8318 ga_append(&ga, tostr[p - fromstr]);
8319 else
8320 ga_append(&ga, *in_str);
8321 ++in_str;
8322 }
8323 }
8324
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008325 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008326 (void)ga_grow(&ga, 1);
8327 ga_append(&ga, NUL);
8328
8329 rettv->vval.v_string = ga.ga_data;
8330}
8331
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008332/*
8333 * "trim({expr})" function
8334 */
8335 static void
8336f_trim(typval_T *argvars, typval_T *rettv)
8337{
8338 char_u buf1[NUMBUFLEN];
8339 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008340 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008341 char_u *mask = NULL;
8342 char_u *tail;
8343 char_u *prev;
8344 char_u *p;
8345 int c1;
8346
8347 rettv->v_type = VAR_STRING;
8348 if (head == NULL)
8349 {
8350 rettv->vval.v_string = NULL;
8351 return;
8352 }
8353
8354 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008355 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008356
8357 while (*head != NUL)
8358 {
8359 c1 = PTR2CHAR(head);
8360 if (mask == NULL)
8361 {
8362 if (c1 > ' ' && c1 != 0xa0)
8363 break;
8364 }
8365 else
8366 {
8367 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8368 if (c1 == PTR2CHAR(p))
8369 break;
8370 if (*p == NUL)
8371 break;
8372 }
8373 MB_PTR_ADV(head);
8374 }
8375
8376 for (tail = head + STRLEN(head); tail > head; tail = prev)
8377 {
8378 prev = tail;
8379 MB_PTR_BACK(head, prev);
8380 c1 = PTR2CHAR(prev);
8381 if (mask == NULL)
8382 {
8383 if (c1 > ' ' && c1 != 0xa0)
8384 break;
8385 }
8386 else
8387 {
8388 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8389 if (c1 == PTR2CHAR(p))
8390 break;
8391 if (*p == NUL)
8392 break;
8393 }
8394 }
8395 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8396}
8397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008398#ifdef FEAT_FLOAT
8399/*
8400 * "trunc({float})" function
8401 */
8402 static void
8403f_trunc(typval_T *argvars, typval_T *rettv)
8404{
8405 float_T f = 0.0;
8406
8407 rettv->v_type = VAR_FLOAT;
8408 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008409 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008410 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8411 else
8412 rettv->vval.v_float = 0.0;
8413}
8414#endif
8415
8416/*
8417 * "type(expr)" function
8418 */
8419 static void
8420f_type(typval_T *argvars, typval_T *rettv)
8421{
8422 int n = -1;
8423
8424 switch (argvars[0].v_type)
8425 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008426 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8427 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008428 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008429 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8430 case VAR_LIST: n = VAR_TYPE_LIST; break;
8431 case VAR_DICT: n = VAR_TYPE_DICT; break;
8432 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8433 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8434 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008435 case VAR_JOB: n = VAR_TYPE_JOB; break;
8436 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008437 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008438 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008439 case VAR_VOID:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008440 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008441 n = -1;
8442 break;
8443 }
8444 rettv->vval.v_number = n;
8445}
8446
8447/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008448 * "virtcol(string)" function
8449 */
8450 static void
8451f_virtcol(typval_T *argvars, typval_T *rettv)
8452{
8453 colnr_T vcol = 0;
8454 pos_T *fp;
8455 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008456 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008457
8458 fp = var2fpos(&argvars[0], FALSE, &fnum);
8459 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8460 && fnum == curbuf->b_fnum)
8461 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008462 // Limit the column to a valid value, getvvcol() doesn't check.
8463 if (fp->col < 0)
8464 fp->col = 0;
8465 else
8466 {
8467 len = (int)STRLEN(ml_get(fp->lnum));
8468 if (fp->col > len)
8469 fp->col = len;
8470 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008471 getvvcol(curwin, fp, NULL, NULL, &vcol);
8472 ++vcol;
8473 }
8474
8475 rettv->vval.v_number = vcol;
8476}
8477
8478/*
8479 * "visualmode()" function
8480 */
8481 static void
8482f_visualmode(typval_T *argvars, typval_T *rettv)
8483{
8484 char_u str[2];
8485
8486 rettv->v_type = VAR_STRING;
8487 str[0] = curbuf->b_visual_mode_eval;
8488 str[1] = NUL;
8489 rettv->vval.v_string = vim_strsave(str);
8490
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008491 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008492 if (non_zero_arg(&argvars[0]))
8493 curbuf->b_visual_mode_eval = NUL;
8494}
8495
8496/*
8497 * "wildmenumode()" function
8498 */
8499 static void
8500f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8501{
8502#ifdef FEAT_WILDMENU
8503 if (wild_menu_showing)
8504 rettv->vval.v_number = 1;
8505#endif
8506}
8507
8508/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008509 * "windowsversion()" function
8510 */
8511 static void
8512f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8513{
8514 rettv->v_type = VAR_STRING;
8515 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8516}
8517
8518/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008519 * "wordcount()" function
8520 */
8521 static void
8522f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8523{
8524 if (rettv_dict_alloc(rettv) == FAIL)
8525 return;
8526 cursor_pos_info(rettv->vval.v_dict);
8527}
8528
8529/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530 * "xor(expr, expr)" function
8531 */
8532 static void
8533f_xor(typval_T *argvars, typval_T *rettv)
8534{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008535 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8536 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008537}
8538
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008539#endif // FEAT_EVAL