blob: a79cc8932998177502358b9312c10fa94e62b24d [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaar10455d42019-11-21 15:36:18 +010023#if defined(MACOS_X)
Bram Moolenaar8d71b542019-08-30 15:46:30 +020024# include <time.h> // for time_t
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020025#endif
26
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027#ifdef FEAT_FLOAT
28static void f_abs(typval_T *argvars, typval_T *rettv);
29static void f_acos(typval_T *argvars, typval_T *rettv);
30#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020031static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020032#ifdef FEAT_FLOAT
33static void f_asin(typval_T *argvars, typval_T *rettv);
34static void f_atan(typval_T *argvars, typval_T *rettv);
35static void f_atan2(typval_T *argvars, typval_T *rettv);
36#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010037#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020038static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010039static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010040# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010041static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_byte2line(typval_T *argvars, typval_T *rettv);
45static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
46static void f_byteidx(typval_T *argvars, typval_T *rettv);
47static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
48static void f_call(typval_T *argvars, typval_T *rettv);
49#ifdef FEAT_FLOAT
50static void f_ceil(typval_T *argvars, typval_T *rettv);
51#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_changenr(typval_T *argvars, typval_T *rettv);
53static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_confirm(typval_T *argvars, typval_T *rettv);
56static void f_copy(typval_T *argvars, typval_T *rettv);
57#ifdef FEAT_FLOAT
58static void f_cos(typval_T *argvars, typval_T *rettv);
59static void f_cosh(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010062#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020063static void f_debugbreak(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020065static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020068static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_escape(typval_T *argvars, typval_T *rettv);
70static void f_eval(typval_T *argvars, typval_T *rettv);
71static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_exists(typval_T *argvars, typval_T *rettv);
74#ifdef FEAT_FLOAT
75static void f_exp(typval_T *argvars, typval_T *rettv);
76#endif
77static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020078static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020079static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080#ifdef FEAT_FLOAT
81static void f_float2nr(typval_T *argvars, typval_T *rettv);
82static void f_floor(typval_T *argvars, typval_T *rettv);
83static void f_fmod(typval_T *argvars, typval_T *rettv);
84#endif
85static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020086static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020087static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020088static void f_function(typval_T *argvars, typval_T *rettv);
89static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
90static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010091static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020094static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020095static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010096static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020097static void f_getpid(typval_T *argvars, typval_T *rettv);
98static void f_getcurpos(typval_T *argvars, typval_T *rettv);
99static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_getreg(typval_T *argvars, typval_T *rettv);
101static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100102static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
104static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_hlID(typval_T *argvars, typval_T *rettv);
106static void f_hlexists(typval_T *argvars, typval_T *rettv);
107static void f_hostname(typval_T *argvars, typval_T *rettv);
108static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200109static void f_index(typval_T *argvars, typval_T *rettv);
110static void f_input(typval_T *argvars, typval_T *rettv);
111static void f_inputdialog(typval_T *argvars, typval_T *rettv);
112static void f_inputlist(typval_T *argvars, typval_T *rettv);
113static void f_inputrestore(typval_T *argvars, typval_T *rettv);
114static void f_inputsave(typval_T *argvars, typval_T *rettv);
115static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar67a2deb2019-11-25 00:05:32 +0100116static void f_interrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_islocked(typval_T *argvars, typval_T *rettv);
119#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200120static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200121static void f_isnan(typval_T *argvars, typval_T *rettv);
122#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200123static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
124static void f_len(typval_T *argvars, typval_T *rettv);
125static void f_libcall(typval_T *argvars, typval_T *rettv);
126static void f_libcallnr(typval_T *argvars, typval_T *rettv);
127static void f_line(typval_T *argvars, typval_T *rettv);
128static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_localtime(typval_T *argvars, typval_T *rettv);
130#ifdef FEAT_FLOAT
131static void f_log(typval_T *argvars, typval_T *rettv);
132static void f_log10(typval_T *argvars, typval_T *rettv);
133#endif
134#ifdef FEAT_LUA
135static void f_luaeval(typval_T *argvars, typval_T *rettv);
136#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_maparg(typval_T *argvars, typval_T *rettv);
138static void f_mapcheck(typval_T *argvars, typval_T *rettv);
139static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200140static void f_matchend(typval_T *argvars, typval_T *rettv);
141static void f_matchlist(typval_T *argvars, typval_T *rettv);
142static void f_matchstr(typval_T *argvars, typval_T *rettv);
143static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
144static void f_max(typval_T *argvars, typval_T *rettv);
145static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200146#ifdef FEAT_MZSCHEME
147static void f_mzeval(typval_T *argvars, typval_T *rettv);
148#endif
149static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
150static void f_nr2char(typval_T *argvars, typval_T *rettv);
151static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200152#ifdef FEAT_PERL
153static void f_perleval(typval_T *argvars, typval_T *rettv);
154#endif
155#ifdef FEAT_FLOAT
156static void f_pow(typval_T *argvars, typval_T *rettv);
157#endif
158static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
159static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200160static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200161static void f_pumvisible(typval_T *argvars, typval_T *rettv);
162#ifdef FEAT_PYTHON3
163static void f_py3eval(typval_T *argvars, typval_T *rettv);
164#endif
165#ifdef FEAT_PYTHON
166static void f_pyeval(typval_T *argvars, typval_T *rettv);
167#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100168#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
169static void f_pyxeval(typval_T *argvars, typval_T *rettv);
170#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100171static void f_rand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200173static void f_reg_executing(typval_T *argvars, typval_T *rettv);
174static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_reltime(typval_T *argvars, typval_T *rettv);
176#ifdef FEAT_FLOAT
177static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
178#endif
179static void f_reltimestr(typval_T *argvars, typval_T *rettv);
180static void f_remote_expr(typval_T *argvars, typval_T *rettv);
181static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
182static void f_remote_peek(typval_T *argvars, typval_T *rettv);
183static void f_remote_read(typval_T *argvars, typval_T *rettv);
184static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100185static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200186static void f_rename(typval_T *argvars, typval_T *rettv);
187static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188#ifdef FEAT_FLOAT
189static void f_round(typval_T *argvars, typval_T *rettv);
190#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100191#ifdef FEAT_RUBY
192static void f_rubyeval(typval_T *argvars, typval_T *rettv);
193#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_screenattr(typval_T *argvars, typval_T *rettv);
195static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100196static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197static void f_screencol(typval_T *argvars, typval_T *rettv);
198static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100199static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_search(typval_T *argvars, typval_T *rettv);
201static void f_searchdecl(typval_T *argvars, typval_T *rettv);
202static void f_searchpair(typval_T *argvars, typval_T *rettv);
203static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
204static void f_searchpos(typval_T *argvars, typval_T *rettv);
205static void f_server2client(typval_T *argvars, typval_T *rettv);
206static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200207static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200208static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200210static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200211static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100212static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213#ifdef FEAT_CRYPT
214static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200215#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200216static void f_shellescape(typval_T *argvars, typval_T *rettv);
217static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200218#ifdef FEAT_FLOAT
219static void f_sin(typval_T *argvars, typval_T *rettv);
220static void f_sinh(typval_T *argvars, typval_T *rettv);
221#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200222static void f_soundfold(typval_T *argvars, typval_T *rettv);
223static void f_spellbadword(typval_T *argvars, typval_T *rettv);
224static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
225static void f_split(typval_T *argvars, typval_T *rettv);
226#ifdef FEAT_FLOAT
227static void f_sqrt(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100228#endif
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +0100229static void f_srand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0387cae2019-11-29 21:07:58 +0100230#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200231static void f_str2float(typval_T *argvars, typval_T *rettv);
232#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200233static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200234static void f_str2nr(typval_T *argvars, typval_T *rettv);
235static void f_strchars(typval_T *argvars, typval_T *rettv);
236#ifdef HAVE_STRFTIME
237static void f_strftime(typval_T *argvars, typval_T *rettv);
238#endif
239static void f_strgetchar(typval_T *argvars, typval_T *rettv);
240static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200241static void f_strlen(typval_T *argvars, typval_T *rettv);
242static void f_strcharpart(typval_T *argvars, typval_T *rettv);
243static void f_strpart(typval_T *argvars, typval_T *rettv);
Bram Moolenaar10455d42019-11-21 15:36:18 +0100244#ifdef HAVE_STRPTIME
245static void f_strptime(typval_T *argvars, typval_T *rettv);
246#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200247static void f_strridx(typval_T *argvars, typval_T *rettv);
248static void f_strtrans(typval_T *argvars, typval_T *rettv);
249static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
250static void f_strwidth(typval_T *argvars, typval_T *rettv);
251static void f_submatch(typval_T *argvars, typval_T *rettv);
252static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200253static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200254static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200255static void f_synID(typval_T *argvars, typval_T *rettv);
256static void f_synIDattr(typval_T *argvars, typval_T *rettv);
257static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
258static void f_synstack(typval_T *argvars, typval_T *rettv);
259static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_taglist(typval_T *argvars, typval_T *rettv);
262static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200263#ifdef FEAT_FLOAT
264static void f_tan(typval_T *argvars, typval_T *rettv);
265static void f_tanh(typval_T *argvars, typval_T *rettv);
266#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200267static void f_tolower(typval_T *argvars, typval_T *rettv);
268static void f_toupper(typval_T *argvars, typval_T *rettv);
269static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100270static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200271#ifdef FEAT_FLOAT
272static void f_trunc(typval_T *argvars, typval_T *rettv);
273#endif
274static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200275static void f_virtcol(typval_T *argvars, typval_T *rettv);
276static void f_visualmode(typval_T *argvars, typval_T *rettv);
277static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0c1e3742019-12-27 13:49:24 +0100278static void f_windowsversion(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200279static void f_wordcount(typval_T *argvars, typval_T *rettv);
280static void f_xor(typval_T *argvars, typval_T *rettv);
281
282/*
283 * Array with names and number of arguments of all internal functions
284 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
285 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200286typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200287{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200288 char *f_name; // function name
289 char f_min_argc; // minimal number of arguments
290 char f_max_argc; // maximal number of arguments
291 char f_argtype; // for method: FEARG_ values
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100292 type_T *f_rettype; // return type
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200293 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200294 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200295} funcentry_T;
296
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200297// values for f_argtype; zero means it cannot be used as a method
298#define FEARG_1 1 // base is the first argument
299#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200300#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200301#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200302#define FEARG_LAST 9 // base is the last argument
303
Bram Moolenaarac92e252019-08-03 21:58:38 +0200304static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200305{
306#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100307 {"abs", 1, 1, FEARG_1, &t_any, f_abs},
308 {"acos", 1, 1, FEARG_1, &t_float, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200309#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100310 {"add", 2, 2, FEARG_1, &t_any, f_add},
311 {"and", 2, 2, FEARG_1, &t_number, f_and},
312 {"append", 2, 2, FEARG_LAST, &t_number, f_append},
313 {"appendbufline", 3, 3, FEARG_LAST, &t_number, f_appendbufline},
314 {"argc", 0, 1, 0, &t_number, f_argc},
315 {"argidx", 0, 0, 0, &t_number, f_argidx},
316 {"arglistid", 0, 2, 0, &t_number, f_arglistid},
317 {"argv", 0, 2, 0, &t_any, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200318#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100319 {"asin", 1, 1, FEARG_1, &t_float, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200320#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100321 {"assert_beeps", 1, 2, FEARG_1, &t_number, f_assert_beeps},
322 {"assert_equal", 2, 3, FEARG_2, &t_number, f_assert_equal},
323 {"assert_equalfile", 2, 2, FEARG_1, &t_number, f_assert_equalfile},
324 {"assert_exception", 1, 2, 0, &t_number, f_assert_exception},
325 {"assert_fails", 1, 3, FEARG_1, &t_number, f_assert_fails},
326 {"assert_false", 1, 2, FEARG_1, &t_number, f_assert_false},
327 {"assert_inrange", 3, 4, FEARG_3, &t_number, f_assert_inrange},
328 {"assert_match", 2, 3, FEARG_2, &t_number, f_assert_match},
329 {"assert_notequal", 2, 3, FEARG_2, &t_number, f_assert_notequal},
330 {"assert_notmatch", 2, 3, FEARG_2, &t_number, f_assert_notmatch},
331 {"assert_report", 1, 1, FEARG_1, &t_number, f_assert_report},
332 {"assert_true", 1, 2, FEARG_1, &t_number, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200333#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100334 {"atan", 1, 1, FEARG_1, &t_float, f_atan},
335 {"atan2", 2, 2, FEARG_1, &t_float, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200336#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100337#ifdef FEAT_BEVAL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100338 {"balloon_gettext", 0, 0, 0, &t_string, f_balloon_gettext},
339 {"balloon_show", 1, 1, FEARG_1, &t_void, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100340# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100341 {"balloon_split", 1, 1, FEARG_1, &t_list_string, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100342# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100343#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100344 {"browse", 4, 4, 0, &t_string, f_browse},
345 {"browsedir", 2, 2, 0, &t_string, f_browsedir},
346 {"bufadd", 1, 1, FEARG_1, &t_number, f_bufadd},
347 {"bufexists", 1, 1, FEARG_1, &t_number, f_bufexists},
348 {"buffer_exists", 1, 1, FEARG_1, &t_number, f_bufexists}, // obsolete
349 {"buffer_name", 0, 1, FEARG_1, &t_string, f_bufname}, // obsolete
350 {"buffer_number", 0, 1, FEARG_1, &t_number, f_bufnr}, // obsolete
351 {"buflisted", 1, 1, FEARG_1, &t_number, f_buflisted},
352 {"bufload", 1, 1, FEARG_1, &t_void, f_bufload},
353 {"bufloaded", 1, 1, FEARG_1, &t_number, f_bufloaded},
354 {"bufname", 0, 1, FEARG_1, &t_string, f_bufname},
355 {"bufnr", 0, 2, FEARG_1, &t_number, f_bufnr},
356 {"bufwinid", 1, 1, FEARG_1, &t_number, f_bufwinid},
357 {"bufwinnr", 1, 1, FEARG_1, &t_number, f_bufwinnr},
358 {"byte2line", 1, 1, FEARG_1, &t_number, f_byte2line},
359 {"byteidx", 2, 2, FEARG_1, &t_number, f_byteidx},
360 {"byteidxcomp", 2, 2, FEARG_1, &t_number, f_byteidxcomp},
361 {"call", 2, 3, FEARG_1, &t_any, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200362#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100363 {"ceil", 1, 1, FEARG_1, &t_float, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200364#endif
365#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100366 {"ch_canread", 1, 1, FEARG_1, &t_number, f_ch_canread},
367 {"ch_close", 1, 1, FEARG_1, &t_void, f_ch_close},
368 {"ch_close_in", 1, 1, FEARG_1, &t_void, f_ch_close_in},
369 {"ch_evalexpr", 2, 3, FEARG_1, &t_any, f_ch_evalexpr},
370 {"ch_evalraw", 2, 3, FEARG_1, &t_any, f_ch_evalraw},
371 {"ch_getbufnr", 2, 2, FEARG_1, &t_number, f_ch_getbufnr},
372 {"ch_getjob", 1, 1, FEARG_1, &t_job, f_ch_getjob},
373 {"ch_info", 1, 1, FEARG_1, &t_dict_any, f_ch_info},
374 {"ch_log", 1, 2, FEARG_1, &t_void, f_ch_log},
375 {"ch_logfile", 1, 2, FEARG_1, &t_void, f_ch_logfile},
376 {"ch_open", 1, 2, FEARG_1, &t_channel, f_ch_open},
377 {"ch_read", 1, 2, FEARG_1, &t_string, f_ch_read},
378 {"ch_readblob", 1, 2, FEARG_1, &t_blob, f_ch_readblob},
379 {"ch_readraw", 1, 2, FEARG_1, &t_string, f_ch_readraw},
380 {"ch_sendexpr", 2, 3, FEARG_1, &t_void, f_ch_sendexpr},
381 {"ch_sendraw", 2, 3, FEARG_1, &t_void, f_ch_sendraw},
382 {"ch_setoptions", 2, 2, FEARG_1, &t_void, f_ch_setoptions},
383 {"ch_status", 1, 2, FEARG_1, &t_string, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200384#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100385 {"changenr", 0, 0, 0, &t_number, f_changenr},
386 {"char2nr", 1, 2, FEARG_1, &t_number, f_char2nr},
387 {"chdir", 1, 1, FEARG_1, &t_string, f_chdir},
388 {"cindent", 1, 1, FEARG_1, &t_number, f_cindent},
389 {"clearmatches", 0, 1, FEARG_1, &t_void, f_clearmatches},
390 {"col", 1, 1, FEARG_1, &t_number, f_col},
391 {"complete", 2, 2, FEARG_2, &t_void, f_complete},
392 {"complete_add", 1, 1, FEARG_1, &t_number, f_complete_add},
393 {"complete_check", 0, 0, 0, &t_number, f_complete_check},
394 {"complete_info", 0, 1, FEARG_1, &t_dict_any, f_complete_info},
395 {"confirm", 1, 4, FEARG_1, &t_number, f_confirm},
396 {"copy", 1, 1, FEARG_1, &t_any, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200397#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100398 {"cos", 1, 1, FEARG_1, &t_float, f_cos},
399 {"cosh", 1, 1, FEARG_1, &t_float, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200400#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100401 {"count", 2, 4, FEARG_1, &t_number, f_count},
402 {"cscope_connection",0,3, 0, &t_number, f_cscope_connection},
403 {"cursor", 1, 3, FEARG_1, &t_number, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100404#ifdef MSWIN
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100405 {"debugbreak", 1, 1, FEARG_1, &t_number, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200406#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100407 {"deepcopy", 1, 2, FEARG_1, &t_any, f_deepcopy},
408 {"delete", 1, 2, FEARG_1, &t_number, f_delete},
409 {"deletebufline", 2, 3, FEARG_1, &t_number, f_deletebufline},
410 {"did_filetype", 0, 0, 0, &t_number, f_did_filetype},
411 {"diff_filler", 1, 1, FEARG_1, &t_number, f_diff_filler},
412 {"diff_hlID", 2, 2, FEARG_1, &t_number, f_diff_hlID},
413 {"empty", 1, 1, FEARG_1, &t_number, f_empty},
414 {"environ", 0, 0, 0, &t_dict_string, f_environ},
415 {"escape", 2, 2, FEARG_1, &t_string, f_escape},
416 {"eval", 1, 1, FEARG_1, &t_any, f_eval},
417 {"eventhandler", 0, 0, 0, &t_number, f_eventhandler},
418 {"executable", 1, 1, FEARG_1, &t_number, f_executable},
419 {"execute", 1, 2, FEARG_1, &t_string, f_execute},
420 {"exepath", 1, 1, FEARG_1, &t_string, f_exepath},
421 {"exists", 1, 1, FEARG_1, &t_number, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200422#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100423 {"exp", 1, 1, FEARG_1, &t_float, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200424#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100425 {"expand", 1, 3, FEARG_1, &t_any, f_expand},
426 {"expandcmd", 1, 1, FEARG_1, &t_string, f_expandcmd},
427 {"extend", 2, 3, FEARG_1, &t_any, f_extend},
428 {"feedkeys", 1, 2, FEARG_1, &t_void, f_feedkeys},
429 {"file_readable", 1, 1, FEARG_1, &t_number, f_filereadable}, // obsolete
430 {"filereadable", 1, 1, FEARG_1, &t_number, f_filereadable},
431 {"filewritable", 1, 1, FEARG_1, &t_number, f_filewritable},
432 {"filter", 2, 2, FEARG_1, &t_any, f_filter},
433 {"finddir", 1, 3, FEARG_1, &t_string, f_finddir},
434 {"findfile", 1, 3, FEARG_1, &t_string, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200435#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100436 {"float2nr", 1, 1, FEARG_1, &t_number, f_float2nr},
437 {"floor", 1, 1, FEARG_1, &t_float, f_floor},
438 {"fmod", 2, 2, FEARG_1, &t_float, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100440 {"fnameescape", 1, 1, FEARG_1, &t_string, f_fnameescape},
441 {"fnamemodify", 2, 2, FEARG_1, &t_string, f_fnamemodify},
442 {"foldclosed", 1, 1, FEARG_1, &t_number, f_foldclosed},
443 {"foldclosedend", 1, 1, FEARG_1, &t_number, f_foldclosedend},
444 {"foldlevel", 1, 1, FEARG_1, &t_number, f_foldlevel},
445 {"foldtext", 0, 0, 0, &t_string, f_foldtext},
446 {"foldtextresult", 1, 1, FEARG_1, &t_string, f_foldtextresult},
447 {"foreground", 0, 0, 0, &t_void, f_foreground},
448 {"funcref", 1, 3, FEARG_1, &t_any, f_funcref},
449 {"function", 1, 3, FEARG_1, &t_any, f_function},
450 {"garbagecollect", 0, 1, 0, &t_void, f_garbagecollect},
451 {"get", 2, 3, FEARG_1, &t_any, f_get},
452 {"getbufinfo", 0, 1, 0, &t_list_dict_any, f_getbufinfo},
453 {"getbufline", 2, 3, FEARG_1, &t_list_string, f_getbufline},
454 {"getbufvar", 2, 3, FEARG_1, &t_any, f_getbufvar},
455 {"getchangelist", 0, 1, FEARG_1, &t_list_any, f_getchangelist},
456 {"getchar", 0, 1, 0, &t_number, f_getchar},
457 {"getcharmod", 0, 0, 0, &t_number, f_getcharmod},
458 {"getcharsearch", 0, 0, 0, &t_dict_any, f_getcharsearch},
459 {"getcmdline", 0, 0, 0, &t_string, f_getcmdline},
460 {"getcmdpos", 0, 0, 0, &t_number, f_getcmdpos},
461 {"getcmdtype", 0, 0, 0, &t_string, f_getcmdtype},
462 {"getcmdwintype", 0, 0, 0, &t_string, f_getcmdwintype},
463 {"getcompletion", 2, 3, FEARG_1, &t_list_string, f_getcompletion},
464 {"getcurpos", 0, 0, 0, &t_list_number, f_getcurpos},
465 {"getcwd", 0, 2, FEARG_1, &t_string, f_getcwd},
466 {"getenv", 1, 1, FEARG_1, &t_string, f_getenv},
467 {"getfontname", 0, 1, 0, &t_string, f_getfontname},
468 {"getfperm", 1, 1, FEARG_1, &t_string, f_getfperm},
469 {"getfsize", 1, 1, FEARG_1, &t_number, f_getfsize},
470 {"getftime", 1, 1, FEARG_1, &t_number, f_getftime},
471 {"getftype", 1, 1, FEARG_1, &t_string, f_getftype},
472 {"getimstatus", 0, 0, 0, &t_number, f_getimstatus},
473 {"getjumplist", 0, 2, FEARG_1, &t_list_any, f_getjumplist},
474 {"getline", 1, 2, FEARG_1, &t_string, f_getline},
475 {"getloclist", 1, 2, 0, &t_list_dict_any, f_getloclist},
476 {"getmatches", 0, 1, 0, &t_list_dict_any, f_getmatches},
477 {"getmousepos", 0, 0, 0, &t_dict_number, f_getmousepos},
478 {"getpid", 0, 0, 0, &t_number, f_getpid},
479 {"getpos", 1, 1, FEARG_1, &t_list_number, f_getpos},
480 {"getqflist", 0, 1, 0, &t_list_dict_any, f_getqflist},
481 {"getreg", 0, 3, FEARG_1, &t_string, f_getreg},
482 {"getregtype", 0, 1, FEARG_1, &t_string, f_getregtype},
483 {"gettabinfo", 0, 1, FEARG_1, &t_list_dict_any, f_gettabinfo},
484 {"gettabvar", 2, 3, FEARG_1, &t_any, f_gettabvar},
485 {"gettabwinvar", 3, 4, FEARG_1, &t_any, f_gettabwinvar},
486 {"gettagstack", 0, 1, FEARG_1, &t_dict_any, f_gettagstack},
487 {"getwininfo", 0, 1, FEARG_1, &t_list_dict_any, f_getwininfo},
488 {"getwinpos", 0, 1, FEARG_1, &t_list_number, f_getwinpos},
489 {"getwinposx", 0, 0, 0, &t_number, f_getwinposx},
490 {"getwinposy", 0, 0, 0, &t_number, f_getwinposy},
491 {"getwinvar", 2, 3, FEARG_1, &t_any, f_getwinvar},
492 {"glob", 1, 4, FEARG_1, &t_any, f_glob},
493 {"glob2regpat", 1, 1, FEARG_1, &t_string, f_glob2regpat},
494 {"globpath", 2, 5, FEARG_2, &t_any, f_globpath},
495 {"has", 1, 1, 0, &t_number, f_has},
496 {"has_key", 2, 2, FEARG_1, &t_number, f_has_key},
497 {"haslocaldir", 0, 2, FEARG_1, &t_number, f_haslocaldir},
498 {"hasmapto", 1, 3, FEARG_1, &t_number, f_hasmapto},
499 {"highlightID", 1, 1, FEARG_1, &t_number, f_hlID}, // obsolete
500 {"highlight_exists",1, 1, FEARG_1, &t_number, f_hlexists}, // obsolete
501 {"histadd", 2, 2, FEARG_2, &t_number, f_histadd},
502 {"histdel", 1, 2, FEARG_1, &t_number, f_histdel},
503 {"histget", 1, 2, FEARG_1, &t_string, f_histget},
504 {"histnr", 1, 1, FEARG_1, &t_number, f_histnr},
505 {"hlID", 1, 1, FEARG_1, &t_number, f_hlID},
506 {"hlexists", 1, 1, FEARG_1, &t_number, f_hlexists},
507 {"hostname", 0, 0, 0, &t_string, f_hostname},
508 {"iconv", 3, 3, FEARG_1, &t_string, f_iconv},
509 {"indent", 1, 1, FEARG_1, &t_number, f_indent},
510 {"index", 2, 4, FEARG_1, &t_number, f_index},
511 {"input", 1, 3, FEARG_1, &t_string, f_input},
512 {"inputdialog", 1, 3, FEARG_1, &t_string, f_inputdialog},
513 {"inputlist", 1, 1, FEARG_1, &t_number, f_inputlist},
514 {"inputrestore", 0, 0, 0, &t_number, f_inputrestore},
515 {"inputsave", 0, 0, 0, &t_number, f_inputsave},
516 {"inputsecret", 1, 2, FEARG_1, &t_string, f_inputsecret},
517 {"insert", 2, 3, FEARG_1, &t_any, f_insert},
518 {"interrupt", 0, 0, 0, &t_void, f_interrupt},
519 {"invert", 1, 1, FEARG_1, &t_number, f_invert},
520 {"isdirectory", 1, 1, FEARG_1, &t_number, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200521#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100522 {"isinf", 1, 1, FEARG_1, &t_number, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200523#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100524 {"islocked", 1, 1, FEARG_1, &t_number, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100526 {"isnan", 1, 1, FEARG_1, &t_number, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100528 {"items", 1, 1, FEARG_1, &t_list_any, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100530 {"job_getchannel", 1, 1, FEARG_1, &t_channel, f_job_getchannel},
531 {"job_info", 0, 1, FEARG_1, &t_dict_any, f_job_info},
532 {"job_setoptions", 2, 2, FEARG_1, &t_void, f_job_setoptions},
533 {"job_start", 1, 2, FEARG_1, &t_job, f_job_start},
534 {"job_status", 1, 1, FEARG_1, &t_string, f_job_status},
535 {"job_stop", 1, 2, FEARG_1, &t_number, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200536#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100537 {"join", 1, 2, FEARG_1, &t_string, f_join},
538 {"js_decode", 1, 1, FEARG_1, &t_any, f_js_decode},
539 {"js_encode", 1, 1, FEARG_1, &t_string, f_js_encode},
540 {"json_decode", 1, 1, FEARG_1, &t_any, f_json_decode},
541 {"json_encode", 1, 1, FEARG_1, &t_string, f_json_encode},
542 {"keys", 1, 1, FEARG_1, &t_list_any, f_keys},
543 {"last_buffer_nr", 0, 0, 0, &t_number, f_last_buffer_nr}, // obsolete
544 {"len", 1, 1, FEARG_1, &t_number, f_len},
545 {"libcall", 3, 3, FEARG_3, &t_string, f_libcall},
546 {"libcallnr", 3, 3, FEARG_3, &t_number, f_libcallnr},
547 {"line", 1, 2, FEARG_1, &t_number, f_line},
548 {"line2byte", 1, 1, FEARG_1, &t_number, f_line2byte},
549 {"lispindent", 1, 1, FEARG_1, &t_number, f_lispindent},
550 {"list2str", 1, 2, FEARG_1, &t_string, f_list2str},
551 {"listener_add", 1, 2, FEARG_2, &t_number, f_listener_add},
552 {"listener_flush", 0, 1, FEARG_1, &t_void, f_listener_flush},
553 {"listener_remove", 1, 1, FEARG_1, &t_number, f_listener_remove},
554 {"localtime", 0, 0, 0, &t_number, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200555#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100556 {"log", 1, 1, FEARG_1, &t_float, f_log},
557 {"log10", 1, 1, FEARG_1, &t_float, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200558#endif
559#ifdef FEAT_LUA
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100560 {"luaeval", 1, 2, FEARG_1, &t_any, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200561#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100562 {"map", 2, 2, FEARG_1, &t_any, f_map},
563 {"maparg", 1, 4, FEARG_1, &t_string, f_maparg},
564 {"mapcheck", 1, 3, FEARG_1, &t_string, f_mapcheck},
565 {"match", 2, 4, FEARG_1, &t_any, f_match},
566 {"matchadd", 2, 5, FEARG_1, &t_number, f_matchadd},
567 {"matchaddpos", 2, 5, FEARG_1, &t_number, f_matchaddpos},
568 {"matcharg", 1, 1, FEARG_1, &t_list_string, f_matcharg},
569 {"matchdelete", 1, 2, FEARG_1, &t_number, f_matchdelete},
570 {"matchend", 2, 4, FEARG_1, &t_number, f_matchend},
571 {"matchlist", 2, 4, FEARG_1, &t_list_any, f_matchlist},
572 {"matchstr", 2, 4, FEARG_1, &t_string, f_matchstr},
573 {"matchstrpos", 2, 4, FEARG_1, &t_list_any, f_matchstrpos},
574 {"max", 1, 1, FEARG_1, &t_any, f_max},
575 {"min", 1, 1, FEARG_1, &t_any, f_min},
576 {"mkdir", 1, 3, FEARG_1, &t_number, f_mkdir},
577 {"mode", 0, 1, FEARG_1, &t_string, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200578#ifdef FEAT_MZSCHEME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100579 {"mzeval", 1, 1, FEARG_1, &t_any, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200580#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100581 {"nextnonblank", 1, 1, FEARG_1, &t_number, f_nextnonblank},
582 {"nr2char", 1, 2, FEARG_1, &t_string, f_nr2char},
583 {"or", 2, 2, FEARG_1, &t_number, f_or},
584 {"pathshorten", 1, 1, FEARG_1, &t_string, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200585#ifdef FEAT_PERL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100586 {"perleval", 1, 1, FEARG_1, &t_any, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200587#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100588#ifdef FEAT_PROP_POPUP
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100589 {"popup_atcursor", 2, 2, FEARG_1, &t_number, f_popup_atcursor},
590 {"popup_beval", 2, 2, FEARG_1, &t_number, f_popup_beval},
591 {"popup_clear", 0, 0, 0, &t_void, f_popup_clear},
592 {"popup_close", 1, 2, FEARG_1, &t_void, f_popup_close},
593 {"popup_create", 2, 2, FEARG_1, &t_number, f_popup_create},
594 {"popup_dialog", 2, 2, FEARG_1, &t_number, f_popup_dialog},
595 {"popup_filter_menu", 2, 2, 0, &t_number, f_popup_filter_menu},
596 {"popup_filter_yesno", 2, 2, 0, &t_number, f_popup_filter_yesno},
597 {"popup_findinfo", 0, 0, 0, &t_number, f_popup_findinfo},
598 {"popup_findpreview", 0, 0, 0, &t_number, f_popup_findpreview},
599 {"popup_getoptions", 1, 1, FEARG_1, &t_dict_any, f_popup_getoptions},
600 {"popup_getpos", 1, 1, FEARG_1, &t_dict_any, f_popup_getpos},
601 {"popup_hide", 1, 1, FEARG_1, &t_void, f_popup_hide},
602 {"popup_locate", 2, 2, 0, &t_number, f_popup_locate},
603 {"popup_menu", 2, 2, FEARG_1, &t_number, f_popup_menu},
604 {"popup_move", 2, 2, FEARG_1, &t_void, f_popup_move},
605 {"popup_notification", 2, 2, FEARG_1, &t_number, f_popup_notification},
606 {"popup_setoptions", 2, 2, FEARG_1, &t_void, f_popup_setoptions},
607 {"popup_settext", 2, 2, FEARG_1, &t_void, f_popup_settext},
608 {"popup_show", 1, 1, FEARG_1, &t_void, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200609#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200610#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100611 {"pow", 2, 2, FEARG_1, &t_float, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200612#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100613 {"prevnonblank", 1, 1, FEARG_1, &t_number, f_prevnonblank},
614 {"printf", 1, 19, FEARG_2, &t_string, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200615#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100616 {"prompt_setcallback", 2, 2, FEARG_1, &t_void, f_prompt_setcallback},
617 {"prompt_setinterrupt", 2, 2, FEARG_1,&t_void, f_prompt_setinterrupt},
618 {"prompt_setprompt", 2, 2, FEARG_1, &t_void, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200619#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +0100620#ifdef FEAT_PROP_POPUP
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100621 {"prop_add", 3, 3, FEARG_1, &t_void, f_prop_add},
622 {"prop_clear", 1, 3, FEARG_1, &t_void, f_prop_clear},
623 {"prop_find", 1, 2, FEARG_1, &t_dict_any, f_prop_find},
624 {"prop_list", 1, 2, FEARG_1, &t_list_any, f_prop_list},
625 {"prop_remove", 1, 3, FEARG_1, &t_number, f_prop_remove},
626 {"prop_type_add", 2, 2, FEARG_1, &t_void, f_prop_type_add},
627 {"prop_type_change", 2, 2, FEARG_1, &t_void, f_prop_type_change},
628 {"prop_type_delete", 1, 2, FEARG_1, &t_void, f_prop_type_delete},
629 {"prop_type_get", 1, 2, FEARG_1, &t_dict_any, f_prop_type_get},
630 {"prop_type_list", 0, 1, FEARG_1, &t_list_string, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100631#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100632 {"pum_getpos", 0, 0, 0, &t_dict_number, f_pum_getpos},
633 {"pumvisible", 0, 0, 0, &t_number, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200634#ifdef FEAT_PYTHON3
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100635 {"py3eval", 1, 1, FEARG_1, &t_any, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200636#endif
637#ifdef FEAT_PYTHON
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100638 {"pyeval", 1, 1, FEARG_1, &t_any, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200639#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100640#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100641 {"pyxeval", 1, 1, FEARG_1, &t_any, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100642#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100643 {"rand", 0, 1, FEARG_1, &t_number, f_rand},
644 {"range", 1, 3, FEARG_1, &t_list_number, f_range},
645 {"readdir", 1, 2, FEARG_1, &t_list_string, f_readdir},
646 {"readfile", 1, 3, FEARG_1, &t_any, f_readfile},
647 {"reg_executing", 0, 0, 0, &t_string, f_reg_executing},
648 {"reg_recording", 0, 0, 0, &t_string, f_reg_recording},
649 {"reltime", 0, 2, FEARG_1, &t_list_any, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200650#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100651 {"reltimefloat", 1, 1, FEARG_1, &t_float, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200652#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100653 {"reltimestr", 1, 1, FEARG_1, &t_string, f_reltimestr},
654 {"remote_expr", 2, 4, FEARG_1, &t_string, f_remote_expr},
655 {"remote_foreground", 1, 1, FEARG_1, &t_string, f_remote_foreground},
656 {"remote_peek", 1, 2, FEARG_1, &t_number, f_remote_peek},
657 {"remote_read", 1, 2, FEARG_1, &t_string, f_remote_read},
658 {"remote_send", 2, 3, FEARG_1, &t_string, f_remote_send},
659 {"remote_startserver", 1, 1, FEARG_1, &t_void, f_remote_startserver},
660 {"remove", 2, 3, FEARG_1, &t_any, f_remove},
661 {"rename", 2, 2, FEARG_1, &t_number, f_rename},
662 {"repeat", 2, 2, FEARG_1, &t_any, f_repeat},
663 {"resolve", 1, 1, FEARG_1, &t_string, f_resolve},
664 {"reverse", 1, 1, FEARG_1, &t_any, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200665#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100666 {"round", 1, 1, FEARG_1, &t_float, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200667#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100668#ifdef FEAT_RUBY
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100669 {"rubyeval", 1, 1, FEARG_1, &t_any, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100670#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100671 {"screenattr", 2, 2, FEARG_1, &t_number, f_screenattr},
672 {"screenchar", 2, 2, FEARG_1, &t_number, f_screenchar},
673 {"screenchars", 2, 2, FEARG_1, &t_list_number, f_screenchars},
674 {"screencol", 0, 0, 0, &t_number, f_screencol},
675 {"screenpos", 3, 3, FEARG_1, &t_dict_number, f_screenpos},
676 {"screenrow", 0, 0, 0, &t_number, f_screenrow},
677 {"screenstring", 2, 2, FEARG_1, &t_string, f_screenstring},
678 {"search", 1, 4, FEARG_1, &t_number, f_search},
679 {"searchdecl", 1, 3, FEARG_1, &t_number, f_searchdecl},
680 {"searchpair", 3, 7, 0, &t_number, f_searchpair},
681 {"searchpairpos", 3, 7, 0, &t_list_number, f_searchpairpos},
682 {"searchpos", 1, 4, FEARG_1, &t_list_number, f_searchpos},
683 {"server2client", 2, 2, FEARG_1, &t_number, f_server2client},
684 {"serverlist", 0, 0, 0, &t_string, f_serverlist},
685 {"setbufline", 3, 3, FEARG_3, &t_number, f_setbufline},
686 {"setbufvar", 3, 3, FEARG_3, &t_void, f_setbufvar},
687 {"setcharsearch", 1, 1, FEARG_1, &t_void, f_setcharsearch},
688 {"setcmdpos", 1, 1, FEARG_1, &t_number, f_setcmdpos},
689 {"setenv", 2, 2, FEARG_2, &t_void, f_setenv},
690 {"setfperm", 2, 2, FEARG_1, &t_number, f_setfperm},
691 {"setline", 2, 2, FEARG_2, &t_number, f_setline},
692 {"setloclist", 2, 4, FEARG_2, &t_number, f_setloclist},
693 {"setmatches", 1, 2, FEARG_1, &t_number, f_setmatches},
694 {"setpos", 2, 2, FEARG_2, &t_number, f_setpos},
695 {"setqflist", 1, 3, FEARG_1, &t_number, f_setqflist},
696 {"setreg", 2, 3, FEARG_2, &t_number, f_setreg},
697 {"settabvar", 3, 3, FEARG_3, &t_void, f_settabvar},
698 {"settabwinvar", 4, 4, FEARG_4, &t_void, f_settabwinvar},
699 {"settagstack", 2, 3, FEARG_2, &t_number, f_settagstack},
700 {"setwinvar", 3, 3, FEARG_3, &t_void, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200701#ifdef FEAT_CRYPT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100702 {"sha256", 1, 1, FEARG_1, &t_string, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200703#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100704 {"shellescape", 1, 2, FEARG_1, &t_string, f_shellescape},
705 {"shiftwidth", 0, 1, FEARG_1, &t_number, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100706#ifdef FEAT_SIGNS
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100707 {"sign_define", 1, 2, FEARG_1, &t_any, f_sign_define},
708 {"sign_getdefined", 0, 1, FEARG_1, &t_list_dict_any, f_sign_getdefined},
709 {"sign_getplaced", 0, 2, FEARG_1, &t_list_dict_any, f_sign_getplaced},
710 {"sign_jump", 3, 3, FEARG_1, &t_number, f_sign_jump},
711 {"sign_place", 4, 5, FEARG_1, &t_number, f_sign_place},
712 {"sign_placelist", 1, 1, FEARG_1, &t_list_number, f_sign_placelist},
713 {"sign_undefine", 0, 1, FEARG_1, &t_number, f_sign_undefine},
714 {"sign_unplace", 1, 2, FEARG_1, &t_number, f_sign_unplace},
715 {"sign_unplacelist", 1, 2, FEARG_1, &t_list_number, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100716#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100717 {"simplify", 1, 1, 0, &t_string, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200718#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100719 {"sin", 1, 1, FEARG_1, &t_float, f_sin},
720 {"sinh", 1, 1, FEARG_1, &t_float, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200721#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100722 {"sort", 1, 3, FEARG_1, &t_list_any, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200723#ifdef FEAT_SOUND
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100724 {"sound_clear", 0, 0, 0, &t_void, f_sound_clear},
725 {"sound_playevent", 1, 2, FEARG_1, &t_number, f_sound_playevent},
726 {"sound_playfile", 1, 2, FEARG_1, &t_number, f_sound_playfile},
727 {"sound_stop", 1, 1, FEARG_1, &t_void, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200728#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100729 {"soundfold", 1, 1, FEARG_1, &t_string, f_soundfold},
730 {"spellbadword", 0, 1, FEARG_1, &t_list_string, f_spellbadword},
731 {"spellsuggest", 1, 3, FEARG_1, &t_list_string, f_spellsuggest},
732 {"split", 1, 3, FEARG_1, &t_list_string, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200733#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100734 {"sqrt", 1, 1, FEARG_1, &t_float, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200735#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100736 {"srand", 0, 1, FEARG_1, &t_list_number, f_srand},
737 {"state", 0, 1, FEARG_1, &t_string, f_state},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200738#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100739 {"str2float", 1, 1, FEARG_1, &t_float, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200740#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100741 {"str2list", 1, 2, FEARG_1, &t_list_number, f_str2list},
742 {"str2nr", 1, 3, FEARG_1, &t_number, f_str2nr},
743 {"strcharpart", 2, 3, FEARG_1, &t_string, f_strcharpart},
744 {"strchars", 1, 2, FEARG_1, &t_number, f_strchars},
745 {"strdisplaywidth", 1, 2, FEARG_1, &t_number, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200746#ifdef HAVE_STRFTIME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100747 {"strftime", 1, 2, FEARG_1, &t_string, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200748#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100749 {"strgetchar", 2, 2, FEARG_1, &t_number, f_strgetchar},
750 {"stridx", 2, 3, FEARG_1, &t_number, f_stridx},
751 {"string", 1, 1, FEARG_1, &t_string, f_string},
752 {"strlen", 1, 1, FEARG_1, &t_number, f_strlen},
753 {"strpart", 2, 3, FEARG_1, &t_string, f_strpart},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100754#ifdef HAVE_STRPTIME
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100755 {"strptime", 2, 2, FEARG_1, &t_number, f_strptime},
Bram Moolenaar10455d42019-11-21 15:36:18 +0100756#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100757 {"strridx", 2, 3, FEARG_1, &t_number, f_strridx},
758 {"strtrans", 1, 1, FEARG_1, &t_string, f_strtrans},
759 {"strwidth", 1, 1, FEARG_1, &t_number, f_strwidth},
760 {"submatch", 1, 2, FEARG_1, &t_string, f_submatch},
761 {"substitute", 4, 4, FEARG_1, &t_string, f_substitute},
762 {"swapinfo", 1, 1, FEARG_1, &t_dict_any, f_swapinfo},
763 {"swapname", 1, 1, FEARG_1, &t_string, f_swapname},
764 {"synID", 3, 3, 0, &t_number, f_synID},
765 {"synIDattr", 2, 3, FEARG_1, &t_string, f_synIDattr},
766 {"synIDtrans", 1, 1, FEARG_1, &t_number, f_synIDtrans},
767 {"synconcealed", 2, 2, 0, &t_list_any, f_synconcealed},
768 {"synstack", 2, 2, 0, &t_list_number, f_synstack},
769 {"system", 1, 2, FEARG_1, &t_string, f_system},
770 {"systemlist", 1, 2, FEARG_1, &t_list_string, f_systemlist},
771 {"tabpagebuflist", 0, 1, FEARG_1, &t_list_number, f_tabpagebuflist},
772 {"tabpagenr", 0, 1, 0, &t_number, f_tabpagenr},
773 {"tabpagewinnr", 1, 2, FEARG_1, &t_number, f_tabpagewinnr},
774 {"tagfiles", 0, 0, 0, &t_list_string, f_tagfiles},
775 {"taglist", 1, 2, FEARG_1, &t_list_dict_any, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200776#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100777 {"tan", 1, 1, FEARG_1, &t_float, f_tan},
778 {"tanh", 1, 1, FEARG_1, &t_float, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200779#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100780 {"tempname", 0, 0, 0, &t_string, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200781#ifdef FEAT_TERMINAL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100782 {"term_dumpdiff", 2, 3, FEARG_1, &t_number, f_term_dumpdiff},
783 {"term_dumpload", 1, 2, FEARG_1, &t_number, f_term_dumpload},
784 {"term_dumpwrite", 2, 3, FEARG_2, &t_void, f_term_dumpwrite},
785 {"term_getaltscreen", 1, 1, FEARG_1, &t_number, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200786# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100787 {"term_getansicolors", 1, 1, FEARG_1, &t_list_string, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200788# endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100789 {"term_getattr", 2, 2, FEARG_1, &t_number, f_term_getattr},
790 {"term_getcursor", 1, 1, FEARG_1, &t_list_any, f_term_getcursor},
791 {"term_getjob", 1, 1, FEARG_1, &t_job, f_term_getjob},
792 {"term_getline", 2, 2, FEARG_1, &t_string, f_term_getline},
793 {"term_getscrolled", 1, 1, FEARG_1, &t_number, f_term_getscrolled},
794 {"term_getsize", 1, 1, FEARG_1, &t_list_number, f_term_getsize},
795 {"term_getstatus", 1, 1, FEARG_1, &t_string, f_term_getstatus},
796 {"term_gettitle", 1, 1, FEARG_1, &t_string, f_term_gettitle},
797 {"term_gettty", 1, 2, FEARG_1, &t_string, f_term_gettty},
798 {"term_list", 0, 0, 0, &t_list_number, f_term_list},
799 {"term_scrape", 2, 2, FEARG_1, &t_list_dict_any, f_term_scrape},
800 {"term_sendkeys", 2, 2, FEARG_1, &t_void, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200801# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100802 {"term_setansicolors", 2, 2, FEARG_1, &t_void, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200803# endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100804 {"term_setapi", 2, 2, FEARG_1, &t_void, f_term_setapi},
805 {"term_setkill", 2, 2, FEARG_1, &t_void, f_term_setkill},
806 {"term_setrestore", 2, 2, FEARG_1, &t_void, f_term_setrestore},
807 {"term_setsize", 3, 3, FEARG_1, &t_void, f_term_setsize},
808 {"term_start", 1, 2, FEARG_1, &t_number, f_term_start},
809 {"term_wait", 1, 2, FEARG_1, &t_void, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200810#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100811 {"test_alloc_fail", 3, 3, FEARG_1, &t_void, f_test_alloc_fail},
812 {"test_autochdir", 0, 0, 0, &t_void, f_test_autochdir},
813 {"test_feedinput", 1, 1, FEARG_1, &t_void, f_test_feedinput},
814 {"test_garbagecollect_now", 0, 0, 0, &t_void, f_test_garbagecollect_now},
815 {"test_garbagecollect_soon", 0, 0, 0, &t_void, f_test_garbagecollect_soon},
816 {"test_getvalue", 1, 1, FEARG_1, &t_number, f_test_getvalue},
817 {"test_ignore_error", 1, 1, FEARG_1, &t_void, f_test_ignore_error},
818 {"test_null_blob", 0, 0, 0, &t_blob, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100820 {"test_null_channel", 0, 0, 0, &t_channel, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100822 {"test_null_dict", 0, 0, 0, &t_dict_any, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200823#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100824 {"test_null_job", 0, 0, 0, &t_job, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100826 {"test_null_list", 0, 0, 0, &t_list_any, f_test_null_list},
827 {"test_null_partial", 0, 0, 0, &t_partial_void, f_test_null_partial},
828 {"test_null_string", 0, 0, 0, &t_string, f_test_null_string},
829 {"test_option_not_set", 1, 1, FEARG_1,&t_void, f_test_option_not_set},
830 {"test_override", 2, 2, FEARG_2, &t_void, f_test_override},
831 {"test_refcount", 1, 1, FEARG_1, &t_number, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200832#ifdef FEAT_GUI
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100833 {"test_scrollbar", 3, 3, FEARG_2, &t_void, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200834#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100835 {"test_setmouse", 2, 2, 0, &t_void, f_test_setmouse},
836 {"test_settime", 1, 1, FEARG_1, &t_void, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200837#ifdef FEAT_TIMERS
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100838 {"timer_info", 0, 1, FEARG_1, &t_list_dict_any, f_timer_info},
839 {"timer_pause", 2, 2, FEARG_1, &t_void, f_timer_pause},
840 {"timer_start", 2, 3, FEARG_1, &t_number, f_timer_start},
841 {"timer_stop", 1, 1, FEARG_1, &t_void, f_timer_stop},
842 {"timer_stopall", 0, 0, 0, &t_void, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200843#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100844 {"tolower", 1, 1, FEARG_1, &t_string, f_tolower},
845 {"toupper", 1, 1, FEARG_1, &t_string, f_toupper},
846 {"tr", 3, 3, FEARG_1, &t_string, f_tr},
847 {"trim", 1, 2, FEARG_1, &t_string, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848#ifdef FEAT_FLOAT
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100849 {"trunc", 1, 1, FEARG_1, &t_float, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850#endif
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100851 {"type", 1, 1, FEARG_1, &t_number, f_type},
852 {"undofile", 1, 1, FEARG_1, &t_string, f_undofile},
853 {"undotree", 0, 0, 0, &t_dict_any, f_undotree},
854 {"uniq", 1, 3, FEARG_1, &t_list_any, f_uniq},
855 {"values", 1, 1, FEARG_1, &t_list_any, f_values},
856 {"virtcol", 1, 1, FEARG_1, &t_number, f_virtcol},
857 {"visualmode", 0, 1, 0, &t_string, f_visualmode},
858 {"wildmenumode", 0, 0, 0, &t_number, f_wildmenumode},
859 {"win_execute", 2, 3, FEARG_2, &t_string, f_win_execute},
860 {"win_findbuf", 1, 1, FEARG_1, &t_list_number, f_win_findbuf},
861 {"win_getid", 0, 2, FEARG_1, &t_number, f_win_getid},
862 {"win_gotoid", 1, 1, FEARG_1, &t_number, f_win_gotoid},
863 {"win_id2tabwin", 1, 1, FEARG_1, &t_list_number, f_win_id2tabwin},
864 {"win_id2win", 1, 1, FEARG_1, &t_number, f_win_id2win},
865 {"win_screenpos", 1, 1, FEARG_1, &t_list_number, f_win_screenpos},
866 {"win_splitmove", 2, 3, FEARG_1, &t_number, f_win_splitmove},
867 {"winbufnr", 1, 1, FEARG_1, &t_number, f_winbufnr},
868 {"wincol", 0, 0, 0, &t_number, f_wincol},
869 {"windowsversion", 0, 0, 0, &t_string, f_windowsversion},
870 {"winheight", 1, 1, FEARG_1, &t_number, f_winheight},
871 {"winlayout", 0, 1, FEARG_1, &t_list_any, f_winlayout},
872 {"winline", 0, 0, 0, &t_number, f_winline},
873 {"winnr", 0, 1, FEARG_1, &t_number, f_winnr},
874 {"winrestcmd", 0, 0, 0, &t_string, f_winrestcmd},
875 {"winrestview", 1, 1, FEARG_1, &t_void, f_winrestview},
876 {"winsaveview", 0, 0, 0, &t_dict_any, f_winsaveview},
877 {"winwidth", 1, 1, FEARG_1, &t_number, f_winwidth},
878 {"wordcount", 0, 0, 0, &t_dict_number, f_wordcount},
879 {"writefile", 2, 3, FEARG_1, &t_number, f_writefile},
880 {"xor", 2, 2, FEARG_1, &t_number, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200881};
882
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200883/*
884 * Function given to ExpandGeneric() to obtain the list of internal
885 * or user defined function names.
886 */
887 char_u *
888get_function_name(expand_T *xp, int idx)
889{
890 static int intidx = -1;
891 char_u *name;
892
893 if (idx == 0)
894 intidx = -1;
895 if (intidx < 0)
896 {
897 name = get_user_func_name(xp, idx);
898 if (name != NULL)
899 return name;
900 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200901 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200902 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200903 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200904 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200905 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200906 STRCAT(IObuff, ")");
907 return IObuff;
908 }
909
910 return NULL;
911}
912
913/*
914 * Function given to ExpandGeneric() to obtain the list of internal or
915 * user defined variable or function names.
916 */
917 char_u *
918get_expr_name(expand_T *xp, int idx)
919{
920 static int intidx = -1;
921 char_u *name;
922
923 if (idx == 0)
924 intidx = -1;
925 if (intidx < 0)
926 {
927 name = get_function_name(xp, idx);
928 if (name != NULL)
929 return name;
930 }
931 return get_user_var_name(xp, ++intidx);
932}
933
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200934/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200935 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200936 * Return index, or -1 if not found
937 */
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100938 int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200939find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200940{
941 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200942 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200943 int cmp;
944 int x;
945
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200946 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200947
948 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200949 while (first <= last)
950 {
951 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200952 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200953 if (cmp < 0)
954 last = x - 1;
955 else if (cmp > 0)
956 first = x + 1;
957 else
958 return x;
959 }
960 return -1;
961}
962
963 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200964has_internal_func(char_u *name)
965{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200966 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200967}
968
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100969 char *
970internal_func_name(int idx)
971{
972 return global_functions[idx].f_name;
973}
974
975 type_T *
976internal_func_ret_type(int idx, int argcount)
977{
978 funcentry_T *fe = &global_functions[idx];
979
980 if (fe->f_func == f_getline)
981 return argcount == 1 ? &t_string : &t_list_string;
982 return fe->f_rettype;
983}
984
985/*
986 * Check the argument count to use for internal function "idx".
987 * Returns OK or FAIL;
988 */
989 int
990check_internal_func(int idx, int argcount)
991{
992 int res;
993 char *name;
994
995 if (argcount < global_functions[idx].f_min_argc)
996 res = FCERR_TOOFEW;
997 else if (argcount > global_functions[idx].f_max_argc)
998 res = FCERR_TOOMANY;
999 else
1000 return OK;
1001
1002 name = internal_func_name(idx);
1003 if (res == FCERR_TOOMANY)
1004 semsg(_(e_toomanyarg), name);
1005 else
1006 semsg(_(e_toofewarg), name);
1007 return FAIL;
1008}
1009
Bram Moolenaarac92e252019-08-03 21:58:38 +02001010 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001011call_internal_func(
1012 char_u *name,
1013 int argcount,
1014 typval_T *argvars,
1015 typval_T *rettv)
1016{
1017 int i;
1018
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001019 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001020 if (i < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001021 return FCERR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001022 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001023 return FCERR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001024 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001025 return FCERR_TOOMANY;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001026 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001027 global_functions[i].f_func(argvars, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001028 return FCERR_NONE;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001029}
1030
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001031 void
1032call_internal_func_by_idx(
1033 int idx,
1034 typval_T *argvars,
1035 typval_T *rettv)
1036{
1037 global_functions[idx].f_func(argvars, rettv);
1038}
1039
Bram Moolenaarac92e252019-08-03 21:58:38 +02001040/*
1041 * Invoke a method for base->method().
1042 */
1043 int
1044call_internal_method(
1045 char_u *name,
1046 int argcount,
1047 typval_T *argvars,
1048 typval_T *rettv,
1049 typval_T *basetv)
1050{
1051 int i;
1052 int fi;
1053 typval_T argv[MAX_FUNC_ARGS + 1];
1054
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001055 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001056 if (fi < 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001057 return FCERR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001058 if (global_functions[fi].f_argtype == 0)
Bram Moolenaaref140542019-12-31 21:27:13 +01001059 return FCERR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001060 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001061 return FCERR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001062 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaaref140542019-12-31 21:27:13 +01001063 return FCERR_TOOMANY;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001064
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001065 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001066 {
1067 // base value goes last
1068 for (i = 0; i < argcount; ++i)
1069 argv[i] = argvars[i];
1070 argv[argcount] = *basetv;
1071 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001072 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001073 {
1074 // base value goes second
1075 argv[0] = argvars[0];
1076 argv[1] = *basetv;
1077 for (i = 1; i < argcount; ++i)
1078 argv[i + 1] = argvars[i];
1079 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001080 else if (global_functions[fi].f_argtype == FEARG_3)
1081 {
1082 // base value goes third
1083 argv[0] = argvars[0];
1084 argv[1] = argvars[1];
1085 argv[2] = *basetv;
1086 for (i = 2; i < argcount; ++i)
1087 argv[i + 1] = argvars[i];
1088 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001089 else if (global_functions[fi].f_argtype == FEARG_4)
1090 {
1091 // base value goes fourth
1092 argv[0] = argvars[0];
1093 argv[1] = argvars[1];
1094 argv[2] = argvars[2];
1095 argv[3] = *basetv;
1096 for (i = 3; i < argcount; ++i)
1097 argv[i + 1] = argvars[i];
1098 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001099 else
1100 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001101 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001102 argv[0] = *basetv;
1103 for (i = 0; i < argcount; ++i)
1104 argv[i + 1] = argvars[i];
1105 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001106 argv[argcount + 1].v_type = VAR_UNKNOWN;
1107
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001108 global_functions[fi].f_func(argv, rettv);
Bram Moolenaaref140542019-12-31 21:27:13 +01001109 return FCERR_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001110}
1111
1112/*
1113 * Return TRUE for a non-zero Number and a non-empty String.
1114 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001115 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001116non_zero_arg(typval_T *argvars)
1117{
1118 return ((argvars[0].v_type == VAR_NUMBER
1119 && argvars[0].vval.v_number != 0)
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001120 || (argvars[0].v_type == VAR_BOOL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001121 && argvars[0].vval.v_number == VVAL_TRUE)
1122 || (argvars[0].v_type == VAR_STRING
1123 && argvars[0].vval.v_string != NULL
1124 && *argvars[0].vval.v_string != NUL));
1125}
1126
1127/*
1128 * Get the lnum from the first argument.
1129 * Also accepts ".", "$", etc., but that only works for the current buffer.
1130 * Returns -1 on error.
1131 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001132 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001133tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001134{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001135 linenr_T lnum;
1136
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001137 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001138 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001139 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001140 int fnum;
1141 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1142
1143 if (fp != NULL)
1144 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001145 }
1146 return lnum;
1147}
1148
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001149/*
1150 * Get the lnum from the first argument.
1151 * Also accepts "$", then "buf" is used.
1152 * Returns 0 on error.
1153 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001154 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001155tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1156{
1157 if (argvars[0].v_type == VAR_STRING
1158 && argvars[0].vval.v_string != NULL
1159 && argvars[0].vval.v_string[0] == '$'
1160 && buf != NULL)
1161 return buf->b_ml.ml_line_count;
1162 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1163}
1164
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001165#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001166/*
1167 * Get the float value of "argvars[0]" into "f".
1168 * Returns FAIL when the argument is not a Number or Float.
1169 */
1170 static int
1171get_float_arg(typval_T *argvars, float_T *f)
1172{
1173 if (argvars[0].v_type == VAR_FLOAT)
1174 {
1175 *f = argvars[0].vval.v_float;
1176 return OK;
1177 }
1178 if (argvars[0].v_type == VAR_NUMBER)
1179 {
1180 *f = (float_T)argvars[0].vval.v_number;
1181 return OK;
1182 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001183 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001184 return FAIL;
1185}
1186
1187/*
1188 * "abs(expr)" function
1189 */
1190 static void
1191f_abs(typval_T *argvars, typval_T *rettv)
1192{
1193 if (argvars[0].v_type == VAR_FLOAT)
1194 {
1195 rettv->v_type = VAR_FLOAT;
1196 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1197 }
1198 else
1199 {
1200 varnumber_T n;
1201 int error = FALSE;
1202
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001203 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001204 if (error)
1205 rettv->vval.v_number = -1;
1206 else if (n > 0)
1207 rettv->vval.v_number = n;
1208 else
1209 rettv->vval.v_number = -n;
1210 }
1211}
1212
1213/*
1214 * "acos()" function
1215 */
1216 static void
1217f_acos(typval_T *argvars, typval_T *rettv)
1218{
1219 float_T f = 0.0;
1220
1221 rettv->v_type = VAR_FLOAT;
1222 if (get_float_arg(argvars, &f) == OK)
1223 rettv->vval.v_float = acos(f);
1224 else
1225 rettv->vval.v_float = 0.0;
1226}
1227#endif
1228
1229/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001230 * "and(expr, expr)" function
1231 */
1232 static void
1233f_and(typval_T *argvars, typval_T *rettv)
1234{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001235 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1236 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001237}
1238
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001239#ifdef FEAT_FLOAT
1240/*
1241 * "asin()" function
1242 */
1243 static void
1244f_asin(typval_T *argvars, typval_T *rettv)
1245{
1246 float_T f = 0.0;
1247
1248 rettv->v_type = VAR_FLOAT;
1249 if (get_float_arg(argvars, &f) == OK)
1250 rettv->vval.v_float = asin(f);
1251 else
1252 rettv->vval.v_float = 0.0;
1253}
1254
1255/*
1256 * "atan()" function
1257 */
1258 static void
1259f_atan(typval_T *argvars, typval_T *rettv)
1260{
1261 float_T f = 0.0;
1262
1263 rettv->v_type = VAR_FLOAT;
1264 if (get_float_arg(argvars, &f) == OK)
1265 rettv->vval.v_float = atan(f);
1266 else
1267 rettv->vval.v_float = 0.0;
1268}
1269
1270/*
1271 * "atan2()" function
1272 */
1273 static void
1274f_atan2(typval_T *argvars, typval_T *rettv)
1275{
1276 float_T fx = 0.0, fy = 0.0;
1277
1278 rettv->v_type = VAR_FLOAT;
1279 if (get_float_arg(argvars, &fx) == OK
1280 && get_float_arg(&argvars[1], &fy) == OK)
1281 rettv->vval.v_float = atan2(fx, fy);
1282 else
1283 rettv->vval.v_float = 0.0;
1284}
1285#endif
1286
1287/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001288 * "balloon_show()" function
1289 */
1290#ifdef FEAT_BEVAL
1291 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001292f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1293{
1294 rettv->v_type = VAR_STRING;
1295 if (balloonEval != NULL)
1296 {
1297 if (balloonEval->msg == NULL)
1298 rettv->vval.v_string = NULL;
1299 else
1300 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1301 }
1302}
1303
1304 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001305f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1306{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001307 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001308 {
1309 if (argvars[0].v_type == VAR_LIST
1310# ifdef FEAT_GUI
1311 && !gui.in_use
1312# endif
1313 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001314 {
1315 list_T *l = argvars[0].vval.v_list;
1316
1317 // empty list removes the balloon
1318 post_balloon(balloonEval, NULL,
1319 l == NULL || l->lv_len == 0 ? NULL : l);
1320 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001321 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001322 {
1323 char_u *mesg = tv_get_string_chk(&argvars[0]);
1324
1325 if (mesg != NULL)
1326 // empty string removes the balloon
1327 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1328 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001329 }
1330}
1331
Bram Moolenaar669a8282017-11-19 20:13:05 +01001332# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001333 static void
1334f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1335{
1336 if (rettv_list_alloc(rettv) == OK)
1337 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001338 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001339
1340 if (msg != NULL)
1341 {
1342 pumitem_T *array;
1343 int size = split_message(msg, &array);
1344 int i;
1345
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001346 // Skip the first and last item, they are always empty.
Bram Moolenaar246fe032017-11-19 19:56:27 +01001347 for (i = 1; i < size - 1; ++i)
1348 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001349 while (size > 0)
1350 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001351 vim_free(array);
1352 }
1353 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001354}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001355# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001356#endif
1357
1358/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001359 * Get buffer by number or pattern.
1360 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001361 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001362tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001363{
1364 char_u *name = tv->vval.v_string;
1365 buf_T *buf;
1366
1367 if (tv->v_type == VAR_NUMBER)
1368 return buflist_findnr((int)tv->vval.v_number);
1369 if (tv->v_type != VAR_STRING)
1370 return NULL;
1371 if (name == NULL || *name == NUL)
1372 return curbuf;
1373 if (name[0] == '$' && name[1] == NUL)
1374 return lastbuf;
1375
1376 buf = buflist_find_by_name(name, curtab_only);
1377
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001378 // If not found, try expanding the name, like done for bufexists().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001379 if (buf == NULL)
1380 buf = find_buffer(tv);
1381
1382 return buf;
1383}
1384
1385/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001386 * Get the buffer from "arg" and give an error and return NULL if it is not
1387 * valid.
1388 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001389 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001390get_buf_arg(typval_T *arg)
1391{
1392 buf_T *buf;
1393
1394 ++emsg_off;
1395 buf = tv_get_buf(arg, FALSE);
1396 --emsg_off;
1397 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001398 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001399 return buf;
1400}
1401
1402/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001403 * "byte2line(byte)" function
1404 */
1405 static void
1406f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1407{
1408#ifndef FEAT_BYTEOFF
1409 rettv->vval.v_number = -1;
1410#else
1411 long boff = 0;
1412
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001413 boff = tv_get_number(&argvars[0]) - 1; // boff gets -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001414 if (boff < 0)
1415 rettv->vval.v_number = -1;
1416 else
1417 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1418 (linenr_T)0, &boff);
1419#endif
1420}
1421
1422 static void
1423byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1424{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001425 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001426 char_u *str;
1427 varnumber_T idx;
1428
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001429 str = tv_get_string_chk(&argvars[0]);
1430 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001431 rettv->vval.v_number = -1;
1432 if (str == NULL || idx < 0)
1433 return;
1434
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001435 t = str;
1436 for ( ; idx > 0; idx--)
1437 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001438 if (*t == NUL) // EOL reached
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001439 return;
1440 if (enc_utf8 && comp)
1441 t += utf_ptr2len(t);
1442 else
1443 t += (*mb_ptr2len)(t);
1444 }
1445 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001446}
1447
1448/*
1449 * "byteidx()" function
1450 */
1451 static void
1452f_byteidx(typval_T *argvars, typval_T *rettv)
1453{
1454 byteidx(argvars, rettv, FALSE);
1455}
1456
1457/*
1458 * "byteidxcomp()" function
1459 */
1460 static void
1461f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1462{
1463 byteidx(argvars, rettv, TRUE);
1464}
1465
1466/*
1467 * "call(func, arglist [, dict])" function
1468 */
1469 static void
1470f_call(typval_T *argvars, typval_T *rettv)
1471{
1472 char_u *func;
1473 partial_T *partial = NULL;
1474 dict_T *selfdict = NULL;
1475
1476 if (argvars[1].v_type != VAR_LIST)
1477 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001478 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001479 return;
1480 }
1481 if (argvars[1].vval.v_list == NULL)
1482 return;
1483
1484 if (argvars[0].v_type == VAR_FUNC)
1485 func = argvars[0].vval.v_string;
1486 else if (argvars[0].v_type == VAR_PARTIAL)
1487 {
1488 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001489 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001490 }
1491 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001492 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001493 if (*func == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001494 return; // type error or empty name
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001495
1496 if (argvars[2].v_type != VAR_UNKNOWN)
1497 {
1498 if (argvars[2].v_type != VAR_DICT)
1499 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001500 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001501 return;
1502 }
1503 selfdict = argvars[2].vval.v_dict;
1504 }
1505
1506 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1507}
1508
1509#ifdef FEAT_FLOAT
1510/*
1511 * "ceil({float})" function
1512 */
1513 static void
1514f_ceil(typval_T *argvars, typval_T *rettv)
1515{
1516 float_T f = 0.0;
1517
1518 rettv->v_type = VAR_FLOAT;
1519 if (get_float_arg(argvars, &f) == OK)
1520 rettv->vval.v_float = ceil(f);
1521 else
1522 rettv->vval.v_float = 0.0;
1523}
1524#endif
1525
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001526/*
1527 * "changenr()" function
1528 */
1529 static void
1530f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1531{
1532 rettv->vval.v_number = curbuf->b_u_seq_cur;
1533}
1534
1535/*
1536 * "char2nr(string)" function
1537 */
1538 static void
1539f_char2nr(typval_T *argvars, typval_T *rettv)
1540{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001541 if (has_mbyte)
1542 {
1543 int utf8 = 0;
1544
1545 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001546 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001547
1548 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001549 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001550 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001551 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001552 }
1553 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001554 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001555}
1556
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001557 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001558get_optional_window(typval_T *argvars, int idx)
1559{
1560 win_T *win = curwin;
1561
1562 if (argvars[idx].v_type != VAR_UNKNOWN)
1563 {
1564 win = find_win_by_nr_or_id(&argvars[idx]);
1565 if (win == NULL)
1566 {
1567 emsg(_(e_invalwindow));
1568 return NULL;
1569 }
1570 }
1571 return win;
1572}
1573
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001574/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575 * "col(string)" function
1576 */
1577 static void
1578f_col(typval_T *argvars, typval_T *rettv)
1579{
1580 colnr_T col = 0;
1581 pos_T *fp;
1582 int fnum = curbuf->b_fnum;
1583
1584 fp = var2fpos(&argvars[0], FALSE, &fnum);
1585 if (fp != NULL && fnum == curbuf->b_fnum)
1586 {
1587 if (fp->col == MAXCOL)
1588 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001589 // '> can be MAXCOL, get the length of the line then
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001590 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1591 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1592 else
1593 col = MAXCOL;
1594 }
1595 else
1596 {
1597 col = fp->col + 1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001598 // col(".") when the cursor is on the NUL at the end of the line
1599 // because of "coladd" can be seen as an extra column.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001600 if (virtual_active() && fp == &curwin->w_cursor)
1601 {
1602 char_u *p = ml_get_cursor();
1603
1604 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1605 curwin->w_virtcol - curwin->w_cursor.coladd))
1606 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607 int l;
1608
1609 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1610 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001611 }
1612 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001613 }
1614 }
1615 rettv->vval.v_number = col;
1616}
1617
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001618/*
1619 * "confirm(message, buttons[, default [, type]])" function
1620 */
1621 static void
1622f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1623{
1624#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1625 char_u *message;
1626 char_u *buttons = NULL;
1627 char_u buf[NUMBUFLEN];
1628 char_u buf2[NUMBUFLEN];
1629 int def = 1;
1630 int type = VIM_GENERIC;
1631 char_u *typestr;
1632 int error = FALSE;
1633
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001634 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001635 if (message == NULL)
1636 error = TRUE;
1637 if (argvars[1].v_type != VAR_UNKNOWN)
1638 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001639 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001640 if (buttons == NULL)
1641 error = TRUE;
1642 if (argvars[2].v_type != VAR_UNKNOWN)
1643 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001644 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001645 if (argvars[3].v_type != VAR_UNKNOWN)
1646 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001647 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648 if (typestr == NULL)
1649 error = TRUE;
1650 else
1651 {
1652 switch (TOUPPER_ASC(*typestr))
1653 {
1654 case 'E': type = VIM_ERROR; break;
1655 case 'Q': type = VIM_QUESTION; break;
1656 case 'I': type = VIM_INFO; break;
1657 case 'W': type = VIM_WARNING; break;
1658 case 'G': type = VIM_GENERIC; break;
1659 }
1660 }
1661 }
1662 }
1663 }
1664
1665 if (buttons == NULL || *buttons == NUL)
1666 buttons = (char_u *)_("&Ok");
1667
1668 if (!error)
1669 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1670 def, NULL, FALSE);
1671#endif
1672}
1673
1674/*
1675 * "copy()" function
1676 */
1677 static void
1678f_copy(typval_T *argvars, typval_T *rettv)
1679{
1680 item_copy(&argvars[0], rettv, FALSE, 0);
1681}
1682
1683#ifdef FEAT_FLOAT
1684/*
1685 * "cos()" function
1686 */
1687 static void
1688f_cos(typval_T *argvars, typval_T *rettv)
1689{
1690 float_T f = 0.0;
1691
1692 rettv->v_type = VAR_FLOAT;
1693 if (get_float_arg(argvars, &f) == OK)
1694 rettv->vval.v_float = cos(f);
1695 else
1696 rettv->vval.v_float = 0.0;
1697}
1698
1699/*
1700 * "cosh()" function
1701 */
1702 static void
1703f_cosh(typval_T *argvars, typval_T *rettv)
1704{
1705 float_T f = 0.0;
1706
1707 rettv->v_type = VAR_FLOAT;
1708 if (get_float_arg(argvars, &f) == OK)
1709 rettv->vval.v_float = cosh(f);
1710 else
1711 rettv->vval.v_float = 0.0;
1712}
1713#endif
1714
1715/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 * "cursor(lnum, col)" function, or
1717 * "cursor(list)"
1718 *
1719 * Moves the cursor to the specified line and column.
1720 * Returns 0 when the position could be set, -1 otherwise.
1721 */
1722 static void
1723f_cursor(typval_T *argvars, typval_T *rettv)
1724{
1725 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001726 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001727 int set_curswant = TRUE;
1728
1729 rettv->vval.v_number = -1;
1730 if (argvars[1].v_type == VAR_UNKNOWN)
1731 {
1732 pos_T pos;
1733 colnr_T curswant = -1;
1734
1735 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1736 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001737 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001738 return;
1739 }
1740 line = pos.lnum;
1741 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001742 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001743 if (curswant >= 0)
1744 {
1745 curwin->w_curswant = curswant - 1;
1746 set_curswant = FALSE;
1747 }
1748 }
1749 else
1750 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001751 line = tv_get_lnum(argvars);
1752 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001753 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001754 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001755 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001756 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001757 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001758 if (line > 0)
1759 curwin->w_cursor.lnum = line;
1760 if (col > 0)
1761 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001762 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001763
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001764 // Make sure the cursor is in a valid position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001765 check_cursor();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01001766 // Correct cursor for multi-byte character.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001767 if (has_mbyte)
1768 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001769
1770 curwin->w_set_curswant = set_curswant;
1771 rettv->vval.v_number = 0;
1772}
1773
Bram Moolenaar4f974752019-02-17 17:44:42 +01001774#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001775/*
1776 * "debugbreak()" function
1777 */
1778 static void
1779f_debugbreak(typval_T *argvars, typval_T *rettv)
1780{
1781 int pid;
1782
1783 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001784 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001785 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001786 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001787 else
1788 {
1789 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1790
1791 if (hProcess != NULL)
1792 {
1793 DebugBreakProcess(hProcess);
1794 CloseHandle(hProcess);
1795 rettv->vval.v_number = OK;
1796 }
1797 }
1798}
1799#endif
1800
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001801/*
1802 * "deepcopy()" function
1803 */
1804 static void
1805f_deepcopy(typval_T *argvars, typval_T *rettv)
1806{
1807 int noref = 0;
1808 int copyID;
1809
1810 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001811 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001812 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001813 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001814 else
1815 {
1816 copyID = get_copyID();
1817 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1818 }
1819}
1820
1821/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001822 * "did_filetype()" function
1823 */
1824 static void
1825f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1826{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001827 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001828}
1829
1830/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001831 * "empty({expr})" function
1832 */
1833 static void
1834f_empty(typval_T *argvars, typval_T *rettv)
1835{
1836 int n = FALSE;
1837
1838 switch (argvars[0].v_type)
1839 {
1840 case VAR_STRING:
1841 case VAR_FUNC:
1842 n = argvars[0].vval.v_string == NULL
1843 || *argvars[0].vval.v_string == NUL;
1844 break;
1845 case VAR_PARTIAL:
1846 n = FALSE;
1847 break;
1848 case VAR_NUMBER:
1849 n = argvars[0].vval.v_number == 0;
1850 break;
1851 case VAR_FLOAT:
1852#ifdef FEAT_FLOAT
1853 n = argvars[0].vval.v_float == 0.0;
1854 break;
1855#endif
1856 case VAR_LIST:
1857 n = argvars[0].vval.v_list == NULL
Bram Moolenaar50985eb2020-01-27 22:09:39 +01001858 || argvars[0].vval.v_list->lv_len == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001859 break;
1860 case VAR_DICT:
1861 n = argvars[0].vval.v_dict == NULL
1862 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1863 break;
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01001864 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001865 case VAR_SPECIAL:
1866 n = argvars[0].vval.v_number != VVAL_TRUE;
1867 break;
1868
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001869 case VAR_BLOB:
1870 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001871 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1872 break;
1873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001874 case VAR_JOB:
1875#ifdef FEAT_JOB_CHANNEL
1876 n = argvars[0].vval.v_job == NULL
1877 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1878 break;
1879#endif
1880 case VAR_CHANNEL:
1881#ifdef FEAT_JOB_CHANNEL
1882 n = argvars[0].vval.v_channel == NULL
1883 || !channel_is_open(argvars[0].vval.v_channel);
1884 break;
1885#endif
1886 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001887 case VAR_VOID:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001888 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001889 n = TRUE;
1890 break;
1891 }
1892
1893 rettv->vval.v_number = n;
1894}
1895
1896/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001897 * "environ()" function
1898 */
1899 static void
1900f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1901{
1902#if !defined(AMIGA)
1903 int i = 0;
1904 char_u *entry, *value;
1905# ifdef MSWIN
1906 extern wchar_t **_wenviron;
1907# else
1908 extern char **environ;
1909# endif
1910
1911 if (rettv_dict_alloc(rettv) != OK)
1912 return;
1913
1914# ifdef MSWIN
1915 if (*_wenviron == NULL)
1916 return;
1917# else
1918 if (*environ == NULL)
1919 return;
1920# endif
1921
1922 for (i = 0; ; ++i)
1923 {
1924# ifdef MSWIN
1925 short_u *p;
1926
1927 if ((p = (short_u *)_wenviron[i]) == NULL)
1928 return;
1929 entry = utf16_to_enc(p, NULL);
1930# else
1931 if ((entry = (char_u *)environ[i]) == NULL)
1932 return;
1933 entry = vim_strsave(entry);
1934# endif
1935 if (entry == NULL) // out of memory
1936 return;
1937 if ((value = vim_strchr(entry, '=')) == NULL)
1938 {
1939 vim_free(entry);
1940 continue;
1941 }
1942 *value++ = NUL;
1943 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1944 vim_free(entry);
1945 }
1946#endif
1947}
1948
1949/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001950 * "escape({string}, {chars})" function
1951 */
1952 static void
1953f_escape(typval_T *argvars, typval_T *rettv)
1954{
1955 char_u buf[NUMBUFLEN];
1956
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001957 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1958 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001959 rettv->v_type = VAR_STRING;
1960}
1961
1962/*
1963 * "eval()" function
1964 */
1965 static void
1966f_eval(typval_T *argvars, typval_T *rettv)
1967{
1968 char_u *s, *p;
1969
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001970 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001971 if (s != NULL)
1972 s = skipwhite(s);
1973
1974 p = s;
1975 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1976 {
1977 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001978 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001979 need_clr_eos = FALSE;
1980 rettv->v_type = VAR_NUMBER;
1981 rettv->vval.v_number = 0;
1982 }
1983 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001984 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001985}
1986
1987/*
1988 * "eventhandler()" function
1989 */
1990 static void
1991f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1992{
1993 rettv->vval.v_number = vgetc_busy;
1994}
1995
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001996static garray_T redir_execute_ga;
1997
1998/*
1999 * Append "value[value_len]" to the execute() output.
2000 */
2001 void
2002execute_redir_str(char_u *value, int value_len)
2003{
2004 int len;
2005
2006 if (value_len == -1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002007 len = (int)STRLEN(value); // Append the entire string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002008 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002009 len = value_len; // Append only "value_len" characters
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 if (ga_grow(&redir_execute_ga, len) == OK)
2011 {
2012 mch_memmove((char *)redir_execute_ga.ga_data
2013 + redir_execute_ga.ga_len, value, len);
2014 redir_execute_ga.ga_len += len;
2015 }
2016}
2017
2018/*
2019 * Get next line from a list.
2020 * Called by do_cmdline() to get the next line.
2021 * Returns allocated string, or NULL for end of function.
2022 */
2023
2024 static char_u *
2025get_list_line(
2026 int c UNUSED,
2027 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002028 int indent UNUSED,
2029 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002030{
2031 listitem_T **p = (listitem_T **)cookie;
2032 listitem_T *item = *p;
2033 char_u buf[NUMBUFLEN];
2034 char_u *s;
2035
2036 if (item == NULL)
2037 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002038 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039 *p = item->li_next;
2040 return s == NULL ? NULL : vim_strsave(s);
2041}
2042
2043/*
2044 * "execute()" function
2045 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002046 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002047execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002048{
2049 char_u *cmd = NULL;
2050 list_T *list = NULL;
2051 int save_msg_silent = msg_silent;
2052 int save_emsg_silent = emsg_silent;
2053 int save_emsg_noredir = emsg_noredir;
2054 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002055 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002056 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002057 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002058 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002059
2060 rettv->vval.v_string = NULL;
2061 rettv->v_type = VAR_STRING;
2062
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002063 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002064 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002065 list = argvars[arg_off].vval.v_list;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002066 if (list == NULL || list->lv_len == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002067 // empty list, no commands, empty output
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002068 return;
2069 ++list->lv_refcount;
2070 }
Bram Moolenaare2a8f072020-01-08 19:32:18 +01002071 else if (argvars[arg_off].v_type == VAR_JOB
2072 || argvars[arg_off].v_type == VAR_CHANNEL)
2073 {
2074 emsg(_(e_inval_string));
2075 return;
2076 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077 else
2078 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002079 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002080 if (cmd == NULL)
2081 return;
2082 }
2083
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002084 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002085 {
2086 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002087 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088
2089 if (s == NULL)
2090 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002091 if (*s == NUL)
2092 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093 if (STRNCMP(s, "silent", 6) == 0)
2094 ++msg_silent;
2095 if (STRCMP(s, "silent!") == 0)
2096 {
2097 emsg_silent = TRUE;
2098 emsg_noredir = TRUE;
2099 }
2100 }
2101 else
2102 ++msg_silent;
2103
2104 if (redir_execute)
2105 save_ga = redir_execute_ga;
2106 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2107 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002108 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002109 if (!echo_output)
2110 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002111
2112 if (cmd != NULL)
2113 do_cmdline_cmd(cmd);
2114 else
2115 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002116 listitem_T *item;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002117
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002118 range_list_materialize(list);
2119 item = list->lv_first;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120 do_cmdline(NULL, get_list_line, (void *)&item,
2121 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2122 --list->lv_refcount;
2123 }
2124
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002125 // Need to append a NUL to the result.
Bram Moolenaard297f352017-01-29 20:31:21 +01002126 if (ga_grow(&redir_execute_ga, 1) == OK)
2127 {
2128 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2129 rettv->vval.v_string = redir_execute_ga.ga_data;
2130 }
2131 else
2132 {
2133 ga_clear(&redir_execute_ga);
2134 rettv->vval.v_string = NULL;
2135 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002136 msg_silent = save_msg_silent;
2137 emsg_silent = save_emsg_silent;
2138 emsg_noredir = save_emsg_noredir;
2139
2140 redir_execute = save_redir_execute;
2141 if (redir_execute)
2142 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002143 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002144
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002145 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002146 if (echo_output)
2147 // When not working silently: put it in column zero. A following
2148 // "echon" will overwrite the message, unavoidably.
2149 msg_col = 0;
2150 else
2151 // When working silently: Put it back where it was, since nothing
2152 // should have been written.
2153 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154}
2155
2156/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002157 * "execute()" function
2158 */
2159 static void
2160f_execute(typval_T *argvars, typval_T *rettv)
2161{
2162 execute_common(argvars, rettv, 0);
2163}
2164
2165/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002166 * "exists()" function
2167 */
2168 static void
2169f_exists(typval_T *argvars, typval_T *rettv)
2170{
2171 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002174 p = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002175 if (*p == '$') // environment variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002177 // first try "normal" environment variables (fast)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178 if (mch_getenv(p + 1) != NULL)
2179 n = TRUE;
2180 else
2181 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002182 // try expanding things like $VIM and ${HOME}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002183 p = expand_env_save(p);
2184 if (p != NULL && *p != '$')
2185 n = TRUE;
2186 vim_free(p);
2187 }
2188 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002189 else if (*p == '&' || *p == '+') // option
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002190 {
2191 n = (get_option_tv(&p, NULL, TRUE) == OK);
2192 if (*skipwhite(p) != NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002193 n = FALSE; // trailing garbage
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002194 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002195 else if (*p == '*') // internal or user defined function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002196 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002197 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002198 }
2199 else if (*p == ':')
2200 {
2201 n = cmd_exists(p + 1);
2202 }
2203 else if (*p == '#')
2204 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002205 if (p[1] == '#')
2206 n = autocmd_supported(p + 2);
2207 else
2208 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002209 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002210 else // internal variable
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002211 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002212 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002213 }
2214
2215 rettv->vval.v_number = n;
2216}
2217
2218#ifdef FEAT_FLOAT
2219/*
2220 * "exp()" function
2221 */
2222 static void
2223f_exp(typval_T *argvars, typval_T *rettv)
2224{
2225 float_T f = 0.0;
2226
2227 rettv->v_type = VAR_FLOAT;
2228 if (get_float_arg(argvars, &f) == OK)
2229 rettv->vval.v_float = exp(f);
2230 else
2231 rettv->vval.v_float = 0.0;
2232}
2233#endif
2234
2235/*
2236 * "expand()" function
2237 */
2238 static void
2239f_expand(typval_T *argvars, typval_T *rettv)
2240{
2241 char_u *s;
2242 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002243 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002244 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2245 expand_T xpc;
2246 int error = FALSE;
2247 char_u *result;
2248
2249 rettv->v_type = VAR_STRING;
2250 if (argvars[1].v_type != VAR_UNKNOWN
2251 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002252 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002253 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002254 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002255
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002256 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002257 if (*s == '%' || *s == '#' || *s == '<')
2258 {
2259 ++emsg_off;
2260 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2261 --emsg_off;
2262 if (rettv->v_type == VAR_LIST)
2263 {
2264 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2265 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002266 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002267 }
2268 else
2269 rettv->vval.v_string = result;
2270 }
2271 else
2272 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002273 // When the optional second argument is non-zero, don't remove matches
2274 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002275 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002276 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002277 options |= WILD_KEEP_ALL;
2278 if (!error)
2279 {
2280 ExpandInit(&xpc);
2281 xpc.xp_context = EXPAND_FILES;
2282 if (p_wic)
2283 options += WILD_ICASE;
2284 if (rettv->v_type == VAR_STRING)
2285 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2286 options, WILD_ALL);
2287 else if (rettv_list_alloc(rettv) != FAIL)
2288 {
2289 int i;
2290
2291 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2292 for (i = 0; i < xpc.xp_numfiles; i++)
2293 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2294 ExpandCleanup(&xpc);
2295 }
2296 }
2297 else
2298 rettv->vval.v_string = NULL;
2299 }
2300}
2301
2302/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002303 * "expandcmd()" function
2304 * Expand all the special characters in a command string.
2305 */
2306 static void
2307f_expandcmd(typval_T *argvars, typval_T *rettv)
2308{
2309 exarg_T eap;
2310 char_u *cmdstr;
2311 char *errormsg = NULL;
2312
2313 rettv->v_type = VAR_STRING;
2314 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2315
2316 memset(&eap, 0, sizeof(eap));
2317 eap.cmd = cmdstr;
2318 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002319 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002320 eap.usefilter = FALSE;
2321 eap.nextcmd = NULL;
2322 eap.cmdidx = CMD_USER;
2323
2324 expand_filename(&eap, &cmdstr, &errormsg);
2325 if (errormsg != NULL && *errormsg != NUL)
2326 emsg(errormsg);
2327
2328 rettv->vval.v_string = cmdstr;
2329}
2330
2331/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002332 * "feedkeys()" function
2333 */
2334 static void
2335f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2336{
2337 int remap = TRUE;
2338 int insert = FALSE;
2339 char_u *keys, *flags;
2340 char_u nbuf[NUMBUFLEN];
2341 int typed = FALSE;
2342 int execute = FALSE;
2343 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002344 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 char_u *keys_esc;
2346
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002347 // This is not allowed in the sandbox. If the commands would still be
2348 // executed in the sandbox it would be OK, but it probably happens later,
2349 // when "sandbox" is no longer set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002350 if (check_secure())
2351 return;
2352
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002353 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002354
2355 if (argvars[1].v_type != VAR_UNKNOWN)
2356 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002357 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002358 for ( ; *flags != NUL; ++flags)
2359 {
2360 switch (*flags)
2361 {
2362 case 'n': remap = FALSE; break;
2363 case 'm': remap = TRUE; break;
2364 case 't': typed = TRUE; break;
2365 case 'i': insert = TRUE; break;
2366 case 'x': execute = TRUE; break;
2367 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002368 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002369 }
2370 }
2371 }
2372
2373 if (*keys != NUL || execute)
2374 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002375 // Need to escape K_SPECIAL and CSI before putting the string in the
2376 // typeahead buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002377 keys_esc = vim_strsave_escape_csi(keys);
2378 if (keys_esc != NULL)
2379 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002380 if (lowlevel)
2381 {
2382#ifdef USE_INPUT_BUF
2383 add_to_input_buf(keys, (int)STRLEN(keys));
2384#else
2385 emsg(_("E980: lowlevel input not supported"));
2386#endif
2387 }
2388 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002389 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002390 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002391 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002392 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002393#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002394 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002395#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002396 )
2397 typebuf_was_filled = TRUE;
2398 }
2399 vim_free(keys_esc);
2400
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002401 if (execute)
2402 {
2403 int save_msg_scroll = msg_scroll;
2404
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002405 // Avoid a 1 second delay when the keys start Insert mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002406 msg_scroll = FALSE;
2407
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002408 if (!dangerous)
2409 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002410 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002411 if (!dangerous)
2412 --ex_normal_busy;
2413
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414 msg_scroll |= save_msg_scroll;
2415 }
2416 }
2417 }
2418}
2419
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002420#ifdef FEAT_FLOAT
2421/*
2422 * "float2nr({float})" function
2423 */
2424 static void
2425f_float2nr(typval_T *argvars, typval_T *rettv)
2426{
2427 float_T f = 0.0;
2428
2429 if (get_float_arg(argvars, &f) == OK)
2430 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002431 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002432 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002433 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002434 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002435 else
2436 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002437 }
2438}
2439
2440/*
2441 * "floor({float})" function
2442 */
2443 static void
2444f_floor(typval_T *argvars, typval_T *rettv)
2445{
2446 float_T f = 0.0;
2447
2448 rettv->v_type = VAR_FLOAT;
2449 if (get_float_arg(argvars, &f) == OK)
2450 rettv->vval.v_float = floor(f);
2451 else
2452 rettv->vval.v_float = 0.0;
2453}
2454
2455/*
2456 * "fmod()" function
2457 */
2458 static void
2459f_fmod(typval_T *argvars, typval_T *rettv)
2460{
2461 float_T fx = 0.0, fy = 0.0;
2462
2463 rettv->v_type = VAR_FLOAT;
2464 if (get_float_arg(argvars, &fx) == OK
2465 && get_float_arg(&argvars[1], &fy) == OK)
2466 rettv->vval.v_float = fmod(fx, fy);
2467 else
2468 rettv->vval.v_float = 0.0;
2469}
2470#endif
2471
2472/*
2473 * "fnameescape({string})" function
2474 */
2475 static void
2476f_fnameescape(typval_T *argvars, typval_T *rettv)
2477{
2478 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002479 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002480 rettv->v_type = VAR_STRING;
2481}
2482
2483/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002484 * "foreground()" function
2485 */
2486 static void
2487f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2488{
2489#ifdef FEAT_GUI
2490 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002491 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002492 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002493 return;
2494 }
2495#endif
2496#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002497 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002498#endif
2499}
2500
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002501 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002502common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002503{
2504 char_u *s;
2505 char_u *name;
2506 int use_string = FALSE;
2507 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002508 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002509
2510 if (argvars[0].v_type == VAR_FUNC)
2511 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002512 // function(MyFunc, [arg], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002513 s = argvars[0].vval.v_string;
2514 }
2515 else if (argvars[0].v_type == VAR_PARTIAL
2516 && argvars[0].vval.v_partial != NULL)
2517 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002518 // function(dict.MyFunc, [arg])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002519 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002520 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002521 }
2522 else
2523 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002524 // function('MyFunc', [arg], dict)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002525 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526 use_string = TRUE;
2527 }
2528
Bram Moolenaar843b8842016-08-21 14:36:15 +02002529 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002530 {
2531 name = s;
2532 trans_name = trans_function_name(&name, FALSE,
2533 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2534 if (*name != NUL)
2535 s = NULL;
2536 }
2537
Bram Moolenaar843b8842016-08-21 14:36:15 +02002538 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2539 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002540 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002541 // Don't check an autoload name for existence here.
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002542 else if (trans_name != NULL && (is_funcref
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002543 ? find_func(trans_name, NULL) == NULL
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002544 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002545 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002546 else
2547 {
2548 int dict_idx = 0;
2549 int arg_idx = 0;
2550 list_T *list = NULL;
2551
2552 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2553 {
2554 char sid_buf[25];
2555 int off = *s == 's' ? 2 : 5;
2556
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002557 // Expand s: and <SID> into <SNR>nr_, so that the function can
2558 // also be called from another script. Using trans_function_name()
2559 // would also work, but some plugins depend on the name being
2560 // printable text.
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002561 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002562 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563 if (name != NULL)
2564 {
2565 STRCPY(name, sid_buf);
2566 STRCAT(name, s + off);
2567 }
2568 }
2569 else
2570 name = vim_strsave(s);
2571
2572 if (argvars[1].v_type != VAR_UNKNOWN)
2573 {
2574 if (argvars[2].v_type != VAR_UNKNOWN)
2575 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002576 // function(name, [args], dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002577 arg_idx = 1;
2578 dict_idx = 2;
2579 }
2580 else if (argvars[1].v_type == VAR_DICT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002581 // function(name, dict)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 dict_idx = 1;
2583 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002584 // function(name, [args])
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002585 arg_idx = 1;
2586 if (dict_idx > 0)
2587 {
2588 if (argvars[dict_idx].v_type != VAR_DICT)
2589 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002590 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002591 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002592 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593 }
2594 if (argvars[dict_idx].vval.v_dict == NULL)
2595 dict_idx = 0;
2596 }
2597 if (arg_idx > 0)
2598 {
2599 if (argvars[arg_idx].v_type != VAR_LIST)
2600 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002601 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002603 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002604 }
2605 list = argvars[arg_idx].vval.v_list;
2606 if (list == NULL || list->lv_len == 0)
2607 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002608 else if (list->lv_len > MAX_FUNC_ARGS)
2609 {
Bram Moolenaar2118a302019-11-22 19:29:45 +01002610 emsg_funcname((char *)e_toomanyarg, s);
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002611 vim_free(name);
2612 goto theend;
2613 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002614 }
2615 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002616 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002617 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002618 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002619
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002620 // result is a VAR_PARTIAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002621 if (pt == NULL)
2622 vim_free(name);
2623 else
2624 {
2625 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2626 {
2627 listitem_T *li;
2628 int i = 0;
2629 int arg_len = 0;
2630 int lv_len = 0;
2631
2632 if (arg_pt != NULL)
2633 arg_len = arg_pt->pt_argc;
2634 if (list != NULL)
2635 lv_len = list->lv_len;
2636 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002637 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002638 if (pt->pt_argv == NULL)
2639 {
2640 vim_free(pt);
2641 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002642 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002643 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644 for (i = 0; i < arg_len; i++)
2645 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2646 if (lv_len > 0)
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002647 {
2648 range_list_materialize(list);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002649 for (li = list->lv_first; li != NULL;
2650 li = li->li_next)
2651 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar50985eb2020-01-27 22:09:39 +01002652 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653 }
2654
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002655 // For "function(dict.func, [], dict)" and "func" is a partial
2656 // use "dict". That is backwards compatible.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002657 if (dict_idx > 0)
2658 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002659 // The dict is bound explicitly, pt_auto is FALSE.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002660 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2661 ++pt->pt_dict->dv_refcount;
2662 }
2663 else if (arg_pt != NULL)
2664 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002665 // If the dict was bound automatically the result is also
2666 // bound automatically.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002667 pt->pt_dict = arg_pt->pt_dict;
2668 pt->pt_auto = arg_pt->pt_auto;
2669 if (pt->pt_dict != NULL)
2670 ++pt->pt_dict->dv_refcount;
2671 }
2672
2673 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002674 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2675 {
2676 pt->pt_func = arg_pt->pt_func;
2677 func_ptr_ref(pt->pt_func);
2678 vim_free(name);
2679 }
2680 else if (is_funcref)
2681 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002682 pt->pt_func = find_func(trans_name, NULL);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002683 func_ptr_ref(pt->pt_func);
2684 vim_free(name);
2685 }
2686 else
2687 {
2688 pt->pt_name = name;
2689 func_ref(name);
2690 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 }
2692 rettv->v_type = VAR_PARTIAL;
2693 rettv->vval.v_partial = pt;
2694 }
2695 else
2696 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002697 // result is a VAR_FUNC
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002698 rettv->v_type = VAR_FUNC;
2699 rettv->vval.v_string = name;
2700 func_ref(name);
2701 }
2702 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002703theend:
2704 vim_free(trans_name);
2705}
2706
2707/*
2708 * "funcref()" function
2709 */
2710 static void
2711f_funcref(typval_T *argvars, typval_T *rettv)
2712{
2713 common_function(argvars, rettv, TRUE);
2714}
2715
2716/*
2717 * "function()" function
2718 */
2719 static void
2720f_function(typval_T *argvars, typval_T *rettv)
2721{
2722 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002723}
2724
2725/*
2726 * "garbagecollect()" function
2727 */
2728 static void
2729f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2730{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002731 // This is postponed until we are back at the toplevel, because we may be
2732 // using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002733 want_garbage_collect = TRUE;
2734
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002735 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002736 garbage_collect_at_exit = TRUE;
2737}
2738
2739/*
2740 * "get()" function
2741 */
2742 static void
2743f_get(typval_T *argvars, typval_T *rettv)
2744{
2745 listitem_T *li;
2746 list_T *l;
2747 dictitem_T *di;
2748 dict_T *d;
2749 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002750 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002751
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002752 if (argvars[0].v_type == VAR_BLOB)
2753 {
2754 int error = FALSE;
2755 int idx = tv_get_number_chk(&argvars[1], &error);
2756
2757 if (!error)
2758 {
2759 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002760 if (idx < 0)
2761 idx = blob_len(argvars[0].vval.v_blob) + idx;
2762 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2763 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002764 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002765 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002766 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002767 tv = rettv;
2768 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002769 }
2770 }
2771 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002772 {
2773 if ((l = argvars[0].vval.v_list) != NULL)
2774 {
2775 int error = FALSE;
2776
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002777 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002778 if (!error && li != NULL)
2779 tv = &li->li_tv;
2780 }
2781 }
2782 else if (argvars[0].v_type == VAR_DICT)
2783 {
2784 if ((d = argvars[0].vval.v_dict) != NULL)
2785 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002786 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002787 if (di != NULL)
2788 tv = &di->di_tv;
2789 }
2790 }
2791 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2792 {
2793 partial_T *pt;
2794 partial_T fref_pt;
2795
2796 if (argvars[0].v_type == VAR_PARTIAL)
2797 pt = argvars[0].vval.v_partial;
2798 else
2799 {
2800 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2801 fref_pt.pt_name = argvars[0].vval.v_string;
2802 pt = &fref_pt;
2803 }
2804
2805 if (pt != NULL)
2806 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002807 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002808 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002809
2810 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2811 {
2812 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002813 n = partial_name(pt);
2814 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002815 rettv->vval.v_string = NULL;
2816 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002817 {
2818 rettv->vval.v_string = vim_strsave(n);
2819 if (rettv->v_type == VAR_FUNC)
2820 func_ref(rettv->vval.v_string);
2821 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002822 }
2823 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002824 {
2825 what_is_dict = TRUE;
2826 if (pt->pt_dict != NULL)
2827 rettv_dict_set(rettv, pt->pt_dict);
2828 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002829 else if (STRCMP(what, "args") == 0)
2830 {
2831 rettv->v_type = VAR_LIST;
2832 if (rettv_list_alloc(rettv) == OK)
2833 {
2834 int i;
2835
2836 for (i = 0; i < pt->pt_argc; ++i)
2837 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2838 }
2839 }
2840 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002841 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002842
2843 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2844 // third argument
2845 if (!what_is_dict)
2846 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002847 }
2848 }
2849 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002850 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002851
2852 if (tv == NULL)
2853 {
2854 if (argvars[2].v_type != VAR_UNKNOWN)
2855 copy_tv(&argvars[2], rettv);
2856 }
2857 else
2858 copy_tv(tv, rettv);
2859}
2860
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002861/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002862 * "getchangelist()" function
2863 */
2864 static void
2865f_getchangelist(typval_T *argvars, typval_T *rettv)
2866{
2867#ifdef FEAT_JUMPLIST
2868 buf_T *buf;
2869 int i;
2870 list_T *l;
2871 dict_T *d;
2872#endif
2873
2874 if (rettv_list_alloc(rettv) != OK)
2875 return;
2876
2877#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002878 if (argvars[0].v_type == VAR_UNKNOWN)
2879 buf = curbuf;
2880 else
2881 {
2882 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2883 ++emsg_off;
2884 buf = tv_get_buf(&argvars[0], FALSE);
2885 --emsg_off;
2886 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002887 if (buf == NULL)
2888 return;
2889
2890 l = list_alloc();
2891 if (l == NULL)
2892 return;
2893
2894 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2895 return;
2896 /*
2897 * The current window change list index tracks only the position in the
2898 * current buffer change list. For other buffers, use the change list
2899 * length as the current index.
2900 */
2901 list_append_number(rettv->vval.v_list,
2902 (varnumber_T)((buf == curwin->w_buffer)
2903 ? curwin->w_changelistidx : buf->b_changelistlen));
2904
2905 for (i = 0; i < buf->b_changelistlen; ++i)
2906 {
2907 if (buf->b_changelist[i].lnum == 0)
2908 continue;
2909 if ((d = dict_alloc()) == NULL)
2910 return;
2911 if (list_append_dict(l, d) == FAIL)
2912 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002913 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2914 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002915 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002916 }
2917#endif
2918}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002919
2920/*
2921 * "getcharsearch()" function
2922 */
2923 static void
2924f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2925{
2926 if (rettv_dict_alloc(rettv) != FAIL)
2927 {
2928 dict_T *dict = rettv->vval.v_dict;
2929
Bram Moolenaare0be1672018-07-08 16:50:37 +02002930 dict_add_string(dict, "char", last_csearch());
2931 dict_add_number(dict, "forward", last_csearch_forward());
2932 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002933 }
2934}
2935
2936/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002937 * "getcmdwintype()" function
2938 */
2939 static void
2940f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2941{
2942 rettv->v_type = VAR_STRING;
2943 rettv->vval.v_string = NULL;
2944#ifdef FEAT_CMDWIN
2945 rettv->vval.v_string = alloc(2);
2946 if (rettv->vval.v_string != NULL)
2947 {
2948 rettv->vval.v_string[0] = cmdwin_type;
2949 rettv->vval.v_string[1] = NUL;
2950 }
2951#endif
2952}
2953
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002954/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002955 * "getenv()" function
2956 */
2957 static void
2958f_getenv(typval_T *argvars, typval_T *rettv)
2959{
2960 int mustfree = FALSE;
2961 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2962
2963 if (p == NULL)
2964 {
2965 rettv->v_type = VAR_SPECIAL;
2966 rettv->vval.v_number = VVAL_NULL;
2967 return;
2968 }
2969 if (!mustfree)
2970 p = vim_strsave(p);
2971 rettv->vval.v_string = p;
2972 rettv->v_type = VAR_STRING;
2973}
2974
2975/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002976 * "getfontname()" function
2977 */
2978 static void
2979f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2980{
2981 rettv->v_type = VAR_STRING;
2982 rettv->vval.v_string = NULL;
2983#ifdef FEAT_GUI
2984 if (gui.in_use)
2985 {
2986 GuiFont font;
2987 char_u *name = NULL;
2988
2989 if (argvars[0].v_type == VAR_UNKNOWN)
2990 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002991 // Get the "Normal" font. Either the name saved by
2992 // hl_set_font_name() or from the font ID.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002993 font = gui.norm_font;
2994 name = hl_get_font_name();
2995 }
2996 else
2997 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002998 name = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01002999 if (STRCMP(name, "*") == 0) // don't use font dialog
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003000 return;
3001 font = gui_mch_get_font(name, FALSE);
3002 if (font == NOFONT)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003003 return; // Invalid font name, return empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003004 }
3005 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3006 if (argvars[0].v_type != VAR_UNKNOWN)
3007 gui_mch_free_font(font);
3008 }
3009#endif
3010}
3011
3012/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003013 * "getjumplist()" function
3014 */
3015 static void
3016f_getjumplist(typval_T *argvars, typval_T *rettv)
3017{
3018#ifdef FEAT_JUMPLIST
3019 win_T *wp;
3020 int i;
3021 list_T *l;
3022 dict_T *d;
3023#endif
3024
3025 if (rettv_list_alloc(rettv) != OK)
3026 return;
3027
3028#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003029 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003030 if (wp == NULL)
3031 return;
3032
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003033 cleanup_jumplist(wp, TRUE);
3034
Bram Moolenaar4f505882018-02-10 21:06:32 +01003035 l = list_alloc();
3036 if (l == NULL)
3037 return;
3038
3039 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3040 return;
3041 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3042
3043 for (i = 0; i < wp->w_jumplistlen; ++i)
3044 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003045 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3046 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003047 if ((d = dict_alloc()) == NULL)
3048 return;
3049 if (list_append_dict(l, d) == FAIL)
3050 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003051 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3052 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003053 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003054 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003055 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003056 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003057 }
3058#endif
3059}
3060
3061/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062 * "getpid()" function
3063 */
3064 static void
3065f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3066{
3067 rettv->vval.v_number = mch_get_pid();
3068}
3069
3070 static void
3071getpos_both(
3072 typval_T *argvars,
3073 typval_T *rettv,
3074 int getcurpos)
3075{
3076 pos_T *fp;
3077 list_T *l;
3078 int fnum = -1;
3079
3080 if (rettv_list_alloc(rettv) == OK)
3081 {
3082 l = rettv->vval.v_list;
3083 if (getcurpos)
3084 fp = &curwin->w_cursor;
3085 else
3086 fp = var2fpos(&argvars[0], TRUE, &fnum);
3087 if (fnum != -1)
3088 list_append_number(l, (varnumber_T)fnum);
3089 else
3090 list_append_number(l, (varnumber_T)0);
3091 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3092 : (varnumber_T)0);
3093 list_append_number(l, (fp != NULL)
3094 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3095 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003096 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003097 (varnumber_T)0);
3098 if (getcurpos)
3099 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003100 int save_set_curswant = curwin->w_set_curswant;
3101 colnr_T save_curswant = curwin->w_curswant;
3102 colnr_T save_virtcol = curwin->w_virtcol;
3103
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003104 update_curswant();
3105 list_append_number(l, curwin->w_curswant == MAXCOL ?
3106 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003107
3108 // Do not change "curswant", as it is unexpected that a get
3109 // function has a side effect.
3110 if (save_set_curswant)
3111 {
3112 curwin->w_set_curswant = save_set_curswant;
3113 curwin->w_curswant = save_curswant;
3114 curwin->w_virtcol = save_virtcol;
3115 curwin->w_valid &= ~VALID_VIRTCOL;
3116 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003117 }
3118 }
3119 else
3120 rettv->vval.v_number = FALSE;
3121}
3122
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003123/*
3124 * "getcurpos()" function
3125 */
3126 static void
3127f_getcurpos(typval_T *argvars, typval_T *rettv)
3128{
3129 getpos_both(argvars, rettv, TRUE);
3130}
3131
3132/*
3133 * "getpos(string)" function
3134 */
3135 static void
3136f_getpos(typval_T *argvars, typval_T *rettv)
3137{
3138 getpos_both(argvars, rettv, FALSE);
3139}
3140
3141/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003142 * "getreg()" function
3143 */
3144 static void
3145f_getreg(typval_T *argvars, typval_T *rettv)
3146{
3147 char_u *strregname;
3148 int regname;
3149 int arg2 = FALSE;
3150 int return_list = FALSE;
3151 int error = FALSE;
3152
3153 if (argvars[0].v_type != VAR_UNKNOWN)
3154 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003155 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003156 error = strregname == NULL;
3157 if (argvars[1].v_type != VAR_UNKNOWN)
3158 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003159 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003160 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003161 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003162 }
3163 }
3164 else
3165 strregname = get_vim_var_str(VV_REG);
3166
3167 if (error)
3168 return;
3169
3170 regname = (strregname == NULL ? '"' : *strregname);
3171 if (regname == 0)
3172 regname = '"';
3173
3174 if (return_list)
3175 {
3176 rettv->v_type = VAR_LIST;
3177 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3178 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3179 if (rettv->vval.v_list == NULL)
3180 (void)rettv_list_alloc(rettv);
3181 else
3182 ++rettv->vval.v_list->lv_refcount;
3183 }
3184 else
3185 {
3186 rettv->v_type = VAR_STRING;
3187 rettv->vval.v_string = get_reg_contents(regname,
3188 arg2 ? GREG_EXPR_SRC : 0);
3189 }
3190}
3191
3192/*
3193 * "getregtype()" function
3194 */
3195 static void
3196f_getregtype(typval_T *argvars, typval_T *rettv)
3197{
3198 char_u *strregname;
3199 int regname;
3200 char_u buf[NUMBUFLEN + 2];
3201 long reglen = 0;
3202
3203 if (argvars[0].v_type != VAR_UNKNOWN)
3204 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003205 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003206 if (strregname == NULL) // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003207 {
3208 rettv->v_type = VAR_STRING;
3209 rettv->vval.v_string = NULL;
3210 return;
3211 }
3212 }
3213 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003214 // Default to v:register
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003215 strregname = get_vim_var_str(VV_REG);
3216
3217 regname = (strregname == NULL ? '"' : *strregname);
3218 if (regname == 0)
3219 regname = '"';
3220
3221 buf[0] = NUL;
3222 buf[1] = NUL;
3223 switch (get_reg_type(regname, &reglen))
3224 {
3225 case MLINE: buf[0] = 'V'; break;
3226 case MCHAR: buf[0] = 'v'; break;
3227 case MBLOCK:
3228 buf[0] = Ctrl_V;
3229 sprintf((char *)buf + 1, "%ld", reglen + 1);
3230 break;
3231 }
3232 rettv->v_type = VAR_STRING;
3233 rettv->vval.v_string = vim_strsave(buf);
3234}
3235
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003236/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003237 * "gettagstack()" function
3238 */
3239 static void
3240f_gettagstack(typval_T *argvars, typval_T *rettv)
3241{
3242 win_T *wp = curwin; // default is current window
3243
3244 if (rettv_dict_alloc(rettv) != OK)
3245 return;
3246
3247 if (argvars[0].v_type != VAR_UNKNOWN)
3248 {
3249 wp = find_win_by_nr_or_id(&argvars[0]);
3250 if (wp == NULL)
3251 return;
3252 }
3253
3254 get_tagstack(wp, rettv->vval.v_dict);
3255}
3256
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003257// for VIM_VERSION_ defines
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003258#include "version.h"
3259
3260/*
3261 * "has()" function
3262 */
Bram Moolenaara259d8d2020-01-31 20:10:50 +01003263 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003264f_has(typval_T *argvars, typval_T *rettv)
3265{
3266 int i;
3267 char_u *name;
3268 int n = FALSE;
3269 static char *(has_list[]) =
3270 {
3271#ifdef AMIGA
3272 "amiga",
3273# ifdef FEAT_ARP
3274 "arp",
3275# endif
3276#endif
3277#ifdef __BEOS__
3278 "beos",
3279#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003280#if defined(BSD) && !defined(MACOS_X)
3281 "bsd",
3282#endif
3283#ifdef hpux
3284 "hpux",
3285#endif
3286#ifdef __linux__
3287 "linux",
3288#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003289#ifdef MACOS_X
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003290 "mac", // Mac OS X (and, once, Mac OS Classic)
3291 "osx", // Mac OS X
Bram Moolenaard0573012017-10-28 21:11:06 +02003292# ifdef MACOS_X_DARWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003293 "macunix", // Mac OS X, with the darwin feature
3294 "osxdarwin", // synonym for macunix
Bram Moolenaard0573012017-10-28 21:11:06 +02003295# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003296#endif
3297#ifdef __QNX__
3298 "qnx",
3299#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003300#ifdef SUN_SYSTEM
3301 "sun",
3302#else
3303 "moon",
3304#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003305#ifdef UNIX
3306 "unix",
3307#endif
3308#ifdef VMS
3309 "vms",
3310#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003311#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003312 "win32",
3313#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003314#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003315 "win32unix",
3316#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003317#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003318 "win64",
3319#endif
3320#ifdef EBCDIC
3321 "ebcdic",
3322#endif
3323#ifndef CASE_INSENSITIVE_FILENAME
3324 "fname_case",
3325#endif
3326#ifdef HAVE_ACL
3327 "acl",
3328#endif
3329#ifdef FEAT_ARABIC
3330 "arabic",
3331#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003332 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003333#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003334 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003335#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003336#ifdef FEAT_AUTOSERVERNAME
3337 "autoservername",
3338#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003339#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003340 "balloon_eval",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003341# ifndef FEAT_GUI_MSWIN // other GUIs always have multiline balloons
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003342 "balloon_multiline",
3343# endif
3344#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003345#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003346 "balloon_eval_term",
3347#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003348#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3349 "builtin_terms",
3350# ifdef ALL_BUILTIN_TCAPS
3351 "all_builtin_terms",
3352# endif
3353#endif
3354#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003355 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003356 || defined(FEAT_GUI_MOTIF))
3357 "browsefilter",
3358#endif
3359#ifdef FEAT_BYTEOFF
3360 "byte_offset",
3361#endif
3362#ifdef FEAT_JOB_CHANNEL
3363 "channel",
3364#endif
3365#ifdef FEAT_CINDENT
3366 "cindent",
3367#endif
3368#ifdef FEAT_CLIENTSERVER
3369 "clientserver",
3370#endif
3371#ifdef FEAT_CLIPBOARD
3372 "clipboard",
3373#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003374 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003375 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003376 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377#ifdef FEAT_CONCEAL
3378 "conceal",
3379#endif
3380#ifdef FEAT_CRYPT
3381 "cryptv",
3382 "crypt-blowfish",
3383 "crypt-blowfish2",
3384#endif
3385#ifdef FEAT_CSCOPE
3386 "cscope",
3387#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003388 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003389#ifdef CURSOR_SHAPE
3390 "cursorshape",
3391#endif
3392#ifdef DEBUG
3393 "debug",
3394#endif
3395#ifdef FEAT_CON_DIALOG
3396 "dialog_con",
3397#endif
3398#ifdef FEAT_GUI_DIALOG
3399 "dialog_gui",
3400#endif
3401#ifdef FEAT_DIFF
3402 "diff",
3403#endif
3404#ifdef FEAT_DIGRAPHS
3405 "digraphs",
3406#endif
3407#ifdef FEAT_DIRECTX
3408 "directx",
3409#endif
3410#ifdef FEAT_DND
3411 "dnd",
3412#endif
3413#ifdef FEAT_EMACS_TAGS
3414 "emacs_tags",
3415#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003416 "eval", // always present, of course!
3417 "ex_extra", // graduated feature
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003418#ifdef FEAT_SEARCH_EXTRA
3419 "extra_search",
3420#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003421#ifdef FEAT_SEARCHPATH
3422 "file_in_path",
3423#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003424#if defined(FEAT_FILTERPIPE) && !defined(VIMDLL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003425 "filterpipe",
3426#endif
3427#ifdef FEAT_FIND_ID
3428 "find_in_path",
3429#endif
3430#ifdef FEAT_FLOAT
3431 "float",
3432#endif
3433#ifdef FEAT_FOLDING
3434 "folding",
3435#endif
3436#ifdef FEAT_FOOTER
3437 "footer",
3438#endif
3439#if !defined(USE_SYSTEM) && defined(UNIX)
3440 "fork",
3441#endif
3442#ifdef FEAT_GETTEXT
3443 "gettext",
3444#endif
3445#ifdef FEAT_GUI
3446 "gui",
3447#endif
3448#ifdef FEAT_GUI_ATHENA
3449# ifdef FEAT_GUI_NEXTAW
3450 "gui_neXtaw",
3451# else
3452 "gui_athena",
3453# endif
3454#endif
3455#ifdef FEAT_GUI_GTK
3456 "gui_gtk",
3457# ifdef USE_GTK3
3458 "gui_gtk3",
3459# else
3460 "gui_gtk2",
3461# endif
3462#endif
3463#ifdef FEAT_GUI_GNOME
3464 "gui_gnome",
3465#endif
3466#ifdef FEAT_GUI_MAC
3467 "gui_mac",
3468#endif
3469#ifdef FEAT_GUI_MOTIF
3470 "gui_motif",
3471#endif
3472#ifdef FEAT_GUI_PHOTON
3473 "gui_photon",
3474#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003475#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003476 "gui_win32",
3477#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003478#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3479 "iconv",
3480#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003481 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003482#ifdef FEAT_JOB_CHANNEL
3483 "job",
3484#endif
3485#ifdef FEAT_JUMPLIST
3486 "jumplist",
3487#endif
3488#ifdef FEAT_KEYMAP
3489 "keymap",
3490#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003491 "lambda", // always with FEAT_EVAL, since 7.4.2120 with closure
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492#ifdef FEAT_LANGMAP
3493 "langmap",
3494#endif
3495#ifdef FEAT_LIBCALL
3496 "libcall",
3497#endif
3498#ifdef FEAT_LINEBREAK
3499 "linebreak",
3500#endif
3501#ifdef FEAT_LISP
3502 "lispindent",
3503#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003504 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003505 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003506#ifdef FEAT_LUA
3507# ifndef DYNAMIC_LUA
3508 "lua",
3509# endif
3510#endif
3511#ifdef FEAT_MENU
3512 "menu",
3513#endif
3514#ifdef FEAT_SESSION
3515 "mksession",
3516#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003518 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003519#ifdef FEAT_MOUSESHAPE
3520 "mouseshape",
3521#endif
3522#if defined(UNIX) || defined(VMS)
3523# ifdef FEAT_MOUSE_DEC
3524 "mouse_dec",
3525# endif
3526# ifdef FEAT_MOUSE_GPM
3527 "mouse_gpm",
3528# endif
3529# ifdef FEAT_MOUSE_JSB
3530 "mouse_jsbterm",
3531# endif
3532# ifdef FEAT_MOUSE_NET
3533 "mouse_netterm",
3534# endif
3535# ifdef FEAT_MOUSE_PTERM
3536 "mouse_pterm",
3537# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003538# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003539 "mouse_sgr",
3540# endif
3541# ifdef FEAT_SYSMOUSE
3542 "mouse_sysmouse",
3543# endif
3544# ifdef FEAT_MOUSE_URXVT
3545 "mouse_urxvt",
3546# endif
3547# ifdef FEAT_MOUSE_XTERM
3548 "mouse_xterm",
3549# endif
3550#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003551 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003552#ifdef FEAT_MBYTE_IME
3553 "multi_byte_ime",
3554#endif
3555#ifdef FEAT_MULTI_LANG
3556 "multi_lang",
3557#endif
3558#ifdef FEAT_MZSCHEME
3559#ifndef DYNAMIC_MZSCHEME
3560 "mzscheme",
3561#endif
3562#endif
3563#ifdef FEAT_NUM64
3564 "num64",
3565#endif
3566#ifdef FEAT_OLE
3567 "ole",
3568#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003569#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003570 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003571#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572#ifdef FEAT_PATH_EXTRA
3573 "path_extra",
3574#endif
3575#ifdef FEAT_PERL
3576#ifndef DYNAMIC_PERL
3577 "perl",
3578#endif
3579#endif
3580#ifdef FEAT_PERSISTENT_UNDO
3581 "persistent_undo",
3582#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003583#if defined(FEAT_PYTHON)
3584 "python_compiled",
3585# if defined(DYNAMIC_PYTHON)
3586 "python_dynamic",
3587# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003588 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003589 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003590# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003591#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003592#if defined(FEAT_PYTHON3)
3593 "python3_compiled",
3594# if defined(DYNAMIC_PYTHON3)
3595 "python3_dynamic",
3596# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003597 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003598 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003599# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003601#ifdef FEAT_PROP_POPUP
3602 "popupwin",
3603#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003604#ifdef FEAT_POSTSCRIPT
3605 "postscript",
3606#endif
3607#ifdef FEAT_PRINTER
3608 "printer",
3609#endif
3610#ifdef FEAT_PROFILE
3611 "profile",
3612#endif
3613#ifdef FEAT_RELTIME
3614 "reltime",
3615#endif
3616#ifdef FEAT_QUICKFIX
3617 "quickfix",
3618#endif
3619#ifdef FEAT_RIGHTLEFT
3620 "rightleft",
3621#endif
3622#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3623 "ruby",
3624#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003625 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003626#ifdef FEAT_CMDL_INFO
3627 "showcmd",
3628 "cmdline_info",
3629#endif
3630#ifdef FEAT_SIGNS
3631 "signs",
3632#endif
3633#ifdef FEAT_SMARTINDENT
3634 "smartindent",
3635#endif
3636#ifdef STARTUPTIME
3637 "startuptime",
3638#endif
3639#ifdef FEAT_STL_OPT
3640 "statusline",
3641#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003642#ifdef FEAT_NETBEANS_INTG
3643 "netbeans_intg",
3644#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003645#ifdef FEAT_SOUND
3646 "sound",
3647#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003648#ifdef FEAT_SPELL
3649 "spell",
3650#endif
3651#ifdef FEAT_SYN_HL
3652 "syntax",
3653#endif
3654#if defined(USE_SYSTEM) || !defined(UNIX)
3655 "system",
3656#endif
3657#ifdef FEAT_TAG_BINS
3658 "tag_binary",
3659#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003660#ifdef FEAT_TCL
3661# ifndef DYNAMIC_TCL
3662 "tcl",
3663# endif
3664#endif
3665#ifdef FEAT_TERMGUICOLORS
3666 "termguicolors",
3667#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003668#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003669 "terminal",
3670#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003671#ifdef TERMINFO
3672 "terminfo",
3673#endif
3674#ifdef FEAT_TERMRESPONSE
3675 "termresponse",
3676#endif
3677#ifdef FEAT_TEXTOBJ
3678 "textobjects",
3679#endif
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01003680#ifdef FEAT_PROP_POPUP
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003681 "textprop",
3682#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003683#ifdef HAVE_TGETENT
3684 "tgetent",
3685#endif
3686#ifdef FEAT_TIMERS
3687 "timers",
3688#endif
3689#ifdef FEAT_TITLE
3690 "title",
3691#endif
3692#ifdef FEAT_TOOLBAR
3693 "toolbar",
3694#endif
3695#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3696 "unnamedplus",
3697#endif
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003698 "user-commands", // was accidentally included in 5.4
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003699 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003700#ifdef FEAT_VARTABS
3701 "vartabs",
3702#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003703 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003704#ifdef FEAT_VIMINFO
3705 "viminfo",
3706#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003707 "vimscript-1",
3708 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003709 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003710 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003711 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003712 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003713 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003715#ifdef FEAT_VTP
3716 "vtp",
3717#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003718#ifdef FEAT_WILDIGN
3719 "wildignore",
3720#endif
3721#ifdef FEAT_WILDMENU
3722 "wildmenu",
3723#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003724 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003725#ifdef FEAT_WAK
3726 "winaltkeys",
3727#endif
3728#ifdef FEAT_WRITEBACKUP
3729 "writebackup",
3730#endif
3731#ifdef FEAT_XIM
3732 "xim",
3733#endif
3734#ifdef FEAT_XFONTSET
3735 "xfontset",
3736#endif
3737#ifdef FEAT_XPM_W32
3738 "xpm",
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003739 "xpm_w32", // for backward compatibility
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003740#else
3741# if defined(HAVE_XPM)
3742 "xpm",
3743# endif
3744#endif
3745#ifdef USE_XSMP
3746 "xsmp",
3747#endif
3748#ifdef USE_XSMP_INTERACT
3749 "xsmp_interact",
3750#endif
3751#ifdef FEAT_XCLIPBOARD
3752 "xterm_clipboard",
3753#endif
3754#ifdef FEAT_XTERM_SAVE
3755 "xterm_save",
3756#endif
3757#if defined(UNIX) && defined(FEAT_X11)
3758 "X11",
3759#endif
3760 NULL
3761 };
3762
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003763 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003764 for (i = 0; has_list[i] != NULL; ++i)
3765 if (STRICMP(name, has_list[i]) == 0)
3766 {
3767 n = TRUE;
3768 break;
3769 }
3770
3771 if (n == FALSE)
3772 {
3773 if (STRNICMP(name, "patch", 5) == 0)
3774 {
3775 if (name[5] == '-'
3776 && STRLEN(name) >= 11
3777 && vim_isdigit(name[6])
3778 && vim_isdigit(name[8])
3779 && vim_isdigit(name[10]))
3780 {
3781 int major = atoi((char *)name + 6);
3782 int minor = atoi((char *)name + 8);
3783
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003784 // Expect "patch-9.9.01234".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003785 n = (major < VIM_VERSION_MAJOR
3786 || (major == VIM_VERSION_MAJOR
3787 && (minor < VIM_VERSION_MINOR
3788 || (minor == VIM_VERSION_MINOR
3789 && has_patch(atoi((char *)name + 10))))));
3790 }
3791 else
3792 n = has_patch(atoi((char *)name + 5));
3793 }
3794 else if (STRICMP(name, "vim_starting") == 0)
3795 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003796 else if (STRICMP(name, "ttyin") == 0)
3797 n = mch_input_isatty();
3798 else if (STRICMP(name, "ttyout") == 0)
3799 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003800 else if (STRICMP(name, "multi_byte_encoding") == 0)
3801 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003802#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003803 else if (STRICMP(name, "balloon_multiline") == 0)
3804 n = multiline_balloon_available();
3805#endif
3806#ifdef DYNAMIC_TCL
3807 else if (STRICMP(name, "tcl") == 0)
3808 n = tcl_enabled(FALSE);
3809#endif
3810#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3811 else if (STRICMP(name, "iconv") == 0)
3812 n = iconv_enabled(FALSE);
3813#endif
3814#ifdef DYNAMIC_LUA
3815 else if (STRICMP(name, "lua") == 0)
3816 n = lua_enabled(FALSE);
3817#endif
3818#ifdef DYNAMIC_MZSCHEME
3819 else if (STRICMP(name, "mzscheme") == 0)
3820 n = mzscheme_enabled(FALSE);
3821#endif
3822#ifdef DYNAMIC_RUBY
3823 else if (STRICMP(name, "ruby") == 0)
3824 n = ruby_enabled(FALSE);
3825#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003826#ifdef DYNAMIC_PYTHON
3827 else if (STRICMP(name, "python") == 0)
3828 n = python_enabled(FALSE);
3829#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003830#ifdef DYNAMIC_PYTHON3
3831 else if (STRICMP(name, "python3") == 0)
3832 n = python3_enabled(FALSE);
3833#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003834#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3835 else if (STRICMP(name, "pythonx") == 0)
3836 {
3837# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3838 if (p_pyx == 0)
3839 n = python3_enabled(FALSE) || python_enabled(FALSE);
3840 else if (p_pyx == 3)
3841 n = python3_enabled(FALSE);
3842 else if (p_pyx == 2)
3843 n = python_enabled(FALSE);
3844# elif defined(DYNAMIC_PYTHON)
3845 n = python_enabled(FALSE);
3846# elif defined(DYNAMIC_PYTHON3)
3847 n = python3_enabled(FALSE);
3848# endif
3849 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003850#endif
3851#ifdef DYNAMIC_PERL
3852 else if (STRICMP(name, "perl") == 0)
3853 n = perl_enabled(FALSE);
3854#endif
3855#ifdef FEAT_GUI
3856 else if (STRICMP(name, "gui_running") == 0)
3857 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003858# ifdef FEAT_BROWSE
3859 else if (STRICMP(name, "browse") == 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003860 n = gui.in_use; // gui_mch_browse() works when GUI is running
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003861# endif
3862#endif
3863#ifdef FEAT_SYN_HL
3864 else if (STRICMP(name, "syntax_items") == 0)
3865 n = syntax_present(curwin);
3866#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003867#ifdef FEAT_VTP
3868 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003869 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003870#endif
3871#ifdef FEAT_NETBEANS_INTG
3872 else if (STRICMP(name, "netbeans_enabled") == 0)
3873 n = netbeans_active();
3874#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003875#ifdef FEAT_MOUSE_GPM
3876 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3877 n = gpm_enabled();
3878#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003879#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003880 else if (STRICMP(name, "terminal") == 0)
3881 n = terminal_enabled();
3882#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003883#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003884 else if (STRICMP(name, "conpty") == 0)
3885 n = use_conpty();
3886#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003887#ifdef FEAT_CLIPBOARD
3888 else if (STRICMP(name, "clipboard_working") == 0)
3889 n = clip_star.available;
3890#endif
Bram Moolenaar310c32e2019-11-29 23:15:25 +01003891#ifdef VIMDLL
3892 else if (STRICMP(name, "filterpipe") == 0)
3893 n = gui.in_use || gui.starting;
3894#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003895 }
3896
3897 rettv->vval.v_number = n;
3898}
3899
3900/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003901 * "haslocaldir()" function
3902 */
3903 static void
3904f_haslocaldir(typval_T *argvars, typval_T *rettv)
3905{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003906 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003907 win_T *wp = NULL;
3908
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003909 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3910
3911 // Check for window-local and tab-local directories
3912 if (wp != NULL && wp->w_localdir != NULL)
3913 rettv->vval.v_number = 1;
3914 else if (tp != NULL && tp->tp_localdir != NULL)
3915 rettv->vval.v_number = 2;
3916 else
3917 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003918}
3919
3920/*
3921 * "hasmapto()" function
3922 */
3923 static void
3924f_hasmapto(typval_T *argvars, typval_T *rettv)
3925{
3926 char_u *name;
3927 char_u *mode;
3928 char_u buf[NUMBUFLEN];
3929 int abbr = FALSE;
3930
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003931 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003932 if (argvars[1].v_type == VAR_UNKNOWN)
3933 mode = (char_u *)"nvo";
3934 else
3935 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003936 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003937 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003938 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003939 }
3940
3941 if (map_to_exists(name, mode, abbr))
3942 rettv->vval.v_number = TRUE;
3943 else
3944 rettv->vval.v_number = FALSE;
3945}
3946
3947/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003948 * "highlightID(name)" function
3949 */
3950 static void
3951f_hlID(typval_T *argvars, typval_T *rettv)
3952{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003953 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003954}
3955
3956/*
3957 * "highlight_exists()" function
3958 */
3959 static void
3960f_hlexists(typval_T *argvars, typval_T *rettv)
3961{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003962 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003963}
3964
3965/*
3966 * "hostname()" function
3967 */
3968 static void
3969f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3970{
3971 char_u hostname[256];
3972
3973 mch_get_host_name(hostname, 256);
3974 rettv->v_type = VAR_STRING;
3975 rettv->vval.v_string = vim_strsave(hostname);
3976}
3977
3978/*
3979 * iconv() function
3980 */
3981 static void
3982f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3983{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984 char_u buf1[NUMBUFLEN];
3985 char_u buf2[NUMBUFLEN];
3986 char_u *from, *to, *str;
3987 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003988
3989 rettv->v_type = VAR_STRING;
3990 rettv->vval.v_string = NULL;
3991
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003992 str = tv_get_string(&argvars[0]);
3993 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3994 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003995 vimconv.vc_type = CONV_NONE;
3996 convert_setup(&vimconv, from, to);
3997
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01003998 // If the encodings are equal, no conversion needed.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003999 if (vimconv.vc_type == CONV_NONE)
4000 rettv->vval.v_string = vim_strsave(str);
4001 else
4002 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
4003
4004 convert_setup(&vimconv, NULL, NULL);
4005 vim_free(from);
4006 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007}
4008
4009/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004010 * "index()" function
4011 */
4012 static void
4013f_index(typval_T *argvars, typval_T *rettv)
4014{
4015 list_T *l;
4016 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004017 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004018 long idx = 0;
4019 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004020 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004021
4022 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004023 if (argvars[0].v_type == VAR_BLOB)
4024 {
4025 typval_T tv;
4026 int start = 0;
4027
4028 if (argvars[2].v_type != VAR_UNKNOWN)
4029 {
4030 start = tv_get_number_chk(&argvars[2], &error);
4031 if (error)
4032 return;
4033 }
4034 b = argvars[0].vval.v_blob;
4035 if (b == NULL)
4036 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01004037 if (start < 0)
4038 {
4039 start = blob_len(b) + start;
4040 if (start < 0)
4041 start = 0;
4042 }
4043
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004044 for (idx = start; idx < blob_len(b); ++idx)
4045 {
4046 tv.v_type = VAR_NUMBER;
4047 tv.vval.v_number = blob_get(b, idx);
4048 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4049 {
4050 rettv->vval.v_number = idx;
4051 return;
4052 }
4053 }
4054 return;
4055 }
4056 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004057 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004058 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004059 return;
4060 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004062 l = argvars[0].vval.v_list;
4063 if (l != NULL)
4064 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004065 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004066 item = l->lv_first;
4067 if (argvars[2].v_type != VAR_UNKNOWN)
4068 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004069 // Start at specified item. Use the cached index that list_find()
4070 // sets, so that a negative number also works.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004071 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004072 idx = l->lv_u.mat.lv_idx;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004073 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004074 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004075 if (error)
4076 item = NULL;
4077 }
4078
4079 for ( ; item != NULL; item = item->li_next, ++idx)
4080 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4081 {
4082 rettv->vval.v_number = idx;
4083 break;
4084 }
4085 }
4086}
4087
4088static int inputsecret_flag = 0;
4089
4090/*
4091 * "input()" function
4092 * Also handles inputsecret() when inputsecret is set.
4093 */
4094 static void
4095f_input(typval_T *argvars, typval_T *rettv)
4096{
4097 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4098}
4099
4100/*
4101 * "inputdialog()" function
4102 */
4103 static void
4104f_inputdialog(typval_T *argvars, typval_T *rettv)
4105{
4106#if defined(FEAT_GUI_TEXTDIALOG)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004107 // Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions'
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004108 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4109 {
4110 char_u *message;
4111 char_u buf[NUMBUFLEN];
4112 char_u *defstr = (char_u *)"";
4113
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004114 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004115 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004116 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004117 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4118 else
4119 IObuff[0] = NUL;
4120 if (message != NULL && defstr != NULL
4121 && do_dialog(VIM_QUESTION, NULL, message,
4122 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4123 rettv->vval.v_string = vim_strsave(IObuff);
4124 else
4125 {
4126 if (message != NULL && defstr != NULL
4127 && argvars[1].v_type != VAR_UNKNOWN
4128 && argvars[2].v_type != VAR_UNKNOWN)
4129 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004130 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004131 else
4132 rettv->vval.v_string = NULL;
4133 }
4134 rettv->v_type = VAR_STRING;
4135 }
4136 else
4137#endif
4138 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4139}
4140
4141/*
4142 * "inputlist()" function
4143 */
4144 static void
4145f_inputlist(typval_T *argvars, typval_T *rettv)
4146{
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004147 list_T *l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004148 listitem_T *li;
4149 int selected;
4150 int mouse_used;
4151
4152#ifdef NO_CONSOLE_INPUT
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004153 // While starting up, there is no place to enter text. When running tests
4154 // with --not-a-term we assume feedkeys() will be used.
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004155 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156 return;
4157#endif
4158 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4159 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004160 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004161 return;
4162 }
4163
4164 msg_start();
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004165 msg_row = Rows - 1; // for when 'cmdheight' > 1
4166 lines_left = Rows; // avoid more prompt
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004167 msg_scroll = TRUE;
4168 msg_clr_eos();
4169
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004170 l = argvars[0].vval.v_list;
4171 range_list_materialize(l);
4172 for (li = l->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004173 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004174 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004175 msg_putchar('\n');
4176 }
4177
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004178 // Ask for choice.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004179 selected = prompt_for_number(&mouse_used);
4180 if (mouse_used)
4181 selected -= lines_left;
4182
4183 rettv->vval.v_number = selected;
4184}
4185
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004186static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4187
4188/*
4189 * "inputrestore()" function
4190 */
4191 static void
4192f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4193{
4194 if (ga_userinput.ga_len > 0)
4195 {
4196 --ga_userinput.ga_len;
4197 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4198 + ga_userinput.ga_len);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004199 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004200 }
4201 else if (p_verbose > 1)
4202 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004203 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004204 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004205 }
4206}
4207
4208/*
4209 * "inputsave()" function
4210 */
4211 static void
4212f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4213{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004214 // Add an entry to the stack of typeahead storage.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004215 if (ga_grow(&ga_userinput, 1) == OK)
4216 {
4217 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4218 + ga_userinput.ga_len);
4219 ++ga_userinput.ga_len;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004220 // default return is zero == OK
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004221 }
4222 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004223 rettv->vval.v_number = 1; // Failed
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004224}
4225
4226/*
4227 * "inputsecret()" function
4228 */
4229 static void
4230f_inputsecret(typval_T *argvars, typval_T *rettv)
4231{
4232 ++cmdline_star;
4233 ++inputsecret_flag;
4234 f_input(argvars, rettv);
4235 --cmdline_star;
4236 --inputsecret_flag;
4237}
4238
4239/*
Bram Moolenaar67a2deb2019-11-25 00:05:32 +01004240 * "interrupt()" function
4241 */
4242 static void
4243f_interrupt(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4244{
4245 got_int = TRUE;
4246}
4247
4248/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004249 * "invert(expr)" function
4250 */
4251 static void
4252f_invert(typval_T *argvars, typval_T *rettv)
4253{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004254 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004255}
4256
4257/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004258 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4259 * or it refers to a List or Dictionary that is locked.
4260 */
4261 static int
4262tv_islocked(typval_T *tv)
4263{
4264 return (tv->v_lock & VAR_LOCKED)
4265 || (tv->v_type == VAR_LIST
4266 && tv->vval.v_list != NULL
4267 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4268 || (tv->v_type == VAR_DICT
4269 && tv->vval.v_dict != NULL
4270 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4271}
4272
4273/*
4274 * "islocked()" function
4275 */
4276 static void
4277f_islocked(typval_T *argvars, typval_T *rettv)
4278{
4279 lval_T lv;
4280 char_u *end;
4281 dictitem_T *di;
4282
4283 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004284 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004285 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004286 if (end != NULL && lv.ll_name != NULL)
4287 {
4288 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004289 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004290 else
4291 {
4292 if (lv.ll_tv == NULL)
4293 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004294 di = find_var(lv.ll_name, NULL, TRUE);
4295 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004296 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004297 // Consider a variable locked when:
4298 // 1. the variable itself is locked
4299 // 2. the value of the variable is locked.
4300 // 3. the List or Dict value is locked.
Bram Moolenaar79518e22017-02-17 16:31:35 +01004301 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4302 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004303 }
4304 }
4305 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004306 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004307 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004308 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004309 else if (lv.ll_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004310 // List item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004311 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4312 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004313 // Dictionary item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004314 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4315 }
4316 }
4317
4318 clear_lval(&lv);
4319}
4320
4321#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4322/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004323 * "isinf()" function
4324 */
4325 static void
4326f_isinf(typval_T *argvars, typval_T *rettv)
4327{
4328 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4329 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4330}
4331
4332/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004333 * "isnan()" function
4334 */
4335 static void
4336f_isnan(typval_T *argvars, typval_T *rettv)
4337{
4338 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4339 && isnan(argvars[0].vval.v_float);
4340}
4341#endif
4342
4343/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004344 * "last_buffer_nr()" function.
4345 */
4346 static void
4347f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4348{
4349 int n = 0;
4350 buf_T *buf;
4351
Bram Moolenaar29323592016-07-24 22:04:11 +02004352 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004353 if (n < buf->b_fnum)
4354 n = buf->b_fnum;
4355
4356 rettv->vval.v_number = n;
4357}
4358
4359/*
4360 * "len()" function
4361 */
4362 static void
4363f_len(typval_T *argvars, typval_T *rettv)
4364{
4365 switch (argvars[0].v_type)
4366 {
4367 case VAR_STRING:
4368 case VAR_NUMBER:
4369 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004370 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004371 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004372 case VAR_BLOB:
4373 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4374 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004375 case VAR_LIST:
4376 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4377 break;
4378 case VAR_DICT:
4379 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4380 break;
4381 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01004382 case VAR_VOID:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01004383 case VAR_BOOL:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004384 case VAR_SPECIAL:
4385 case VAR_FLOAT:
4386 case VAR_FUNC:
4387 case VAR_PARTIAL:
4388 case VAR_JOB:
4389 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004390 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004391 break;
4392 }
4393}
4394
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004395 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004396libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397{
4398#ifdef FEAT_LIBCALL
4399 char_u *string_in;
4400 char_u **string_result;
4401 int nr_result;
4402#endif
4403
4404 rettv->v_type = type;
4405 if (type != VAR_NUMBER)
4406 rettv->vval.v_string = NULL;
4407
4408 if (check_restricted() || check_secure())
4409 return;
4410
4411#ifdef FEAT_LIBCALL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004412 // The first two args must be strings, otherwise it's meaningless
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004413 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4414 {
4415 string_in = NULL;
4416 if (argvars[2].v_type == VAR_STRING)
4417 string_in = argvars[2].vval.v_string;
4418 if (type == VAR_NUMBER)
4419 string_result = NULL;
4420 else
4421 string_result = &rettv->vval.v_string;
4422 if (mch_libcall(argvars[0].vval.v_string,
4423 argvars[1].vval.v_string,
4424 string_in,
4425 argvars[2].vval.v_number,
4426 string_result,
4427 &nr_result) == OK
4428 && type == VAR_NUMBER)
4429 rettv->vval.v_number = nr_result;
4430 }
4431#endif
4432}
4433
4434/*
4435 * "libcall()" function
4436 */
4437 static void
4438f_libcall(typval_T *argvars, typval_T *rettv)
4439{
4440 libcall_common(argvars, rettv, VAR_STRING);
4441}
4442
4443/*
4444 * "libcallnr()" function
4445 */
4446 static void
4447f_libcallnr(typval_T *argvars, typval_T *rettv)
4448{
4449 libcall_common(argvars, rettv, VAR_NUMBER);
4450}
4451
4452/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004453 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004454 */
4455 static void
4456f_line(typval_T *argvars, typval_T *rettv)
4457{
4458 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004459 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004460 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004461 int id;
4462 tabpage_T *tp;
4463 win_T *wp;
4464 win_T *save_curwin;
4465 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004466
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004467 if (argvars[1].v_type != VAR_UNKNOWN)
4468 {
4469 // use window specified in the second argument
4470 id = (int)tv_get_number(&argvars[1]);
4471 wp = win_id2wp_tp(id, &tp);
4472 if (wp != NULL && tp != NULL)
4473 {
4474 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4475 == OK)
4476 {
4477 check_cursor();
4478 fp = var2fpos(&argvars[0], TRUE, &fnum);
4479 }
4480 restore_win_noblock(save_curwin, save_curtab, TRUE);
4481 }
4482 }
4483 else
4484 // use current window
4485 fp = var2fpos(&argvars[0], TRUE, &fnum);
4486
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487 if (fp != NULL)
4488 lnum = fp->lnum;
4489 rettv->vval.v_number = lnum;
4490}
4491
4492/*
4493 * "line2byte(lnum)" function
4494 */
4495 static void
4496f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4497{
4498#ifndef FEAT_BYTEOFF
4499 rettv->vval.v_number = -1;
4500#else
4501 linenr_T lnum;
4502
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004503 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004504 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4505 rettv->vval.v_number = -1;
4506 else
4507 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4508 if (rettv->vval.v_number >= 0)
4509 ++rettv->vval.v_number;
4510#endif
4511}
4512
4513/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004514 * "localtime()" function
4515 */
4516 static void
4517f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4518{
4519 rettv->vval.v_number = (varnumber_T)time(NULL);
4520}
4521
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004522#ifdef FEAT_FLOAT
4523/*
4524 * "log()" function
4525 */
4526 static void
4527f_log(typval_T *argvars, typval_T *rettv)
4528{
4529 float_T f = 0.0;
4530
4531 rettv->v_type = VAR_FLOAT;
4532 if (get_float_arg(argvars, &f) == OK)
4533 rettv->vval.v_float = log(f);
4534 else
4535 rettv->vval.v_float = 0.0;
4536}
4537
4538/*
4539 * "log10()" function
4540 */
4541 static void
4542f_log10(typval_T *argvars, typval_T *rettv)
4543{
4544 float_T f = 0.0;
4545
4546 rettv->v_type = VAR_FLOAT;
4547 if (get_float_arg(argvars, &f) == OK)
4548 rettv->vval.v_float = log10(f);
4549 else
4550 rettv->vval.v_float = 0.0;
4551}
4552#endif
4553
4554#ifdef FEAT_LUA
4555/*
4556 * "luaeval()" function
4557 */
4558 static void
4559f_luaeval(typval_T *argvars, typval_T *rettv)
4560{
4561 char_u *str;
4562 char_u buf[NUMBUFLEN];
4563
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004564 if (check_restricted() || check_secure())
4565 return;
4566
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004567 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004568 do_luaeval(str, argvars + 1, rettv);
4569}
4570#endif
4571
4572/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004573 * "maparg()" function
4574 */
4575 static void
4576f_maparg(typval_T *argvars, typval_T *rettv)
4577{
4578 get_maparg(argvars, rettv, TRUE);
4579}
4580
4581/*
4582 * "mapcheck()" function
4583 */
4584 static void
4585f_mapcheck(typval_T *argvars, typval_T *rettv)
4586{
4587 get_maparg(argvars, rettv, FALSE);
4588}
4589
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004590typedef enum
4591{
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004592 MATCH_END, // matchend()
4593 MATCH_MATCH, // match()
4594 MATCH_STR, // matchstr()
4595 MATCH_LIST, // matchlist()
4596 MATCH_POS // matchstrpos()
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004597} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004598
4599 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004600find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004601{
4602 char_u *str = NULL;
4603 long len = 0;
4604 char_u *expr = NULL;
4605 char_u *pat;
4606 regmatch_T regmatch;
4607 char_u patbuf[NUMBUFLEN];
4608 char_u strbuf[NUMBUFLEN];
4609 char_u *save_cpo;
4610 long start = 0;
4611 long nth = 1;
4612 colnr_T startcol = 0;
4613 int match = 0;
4614 list_T *l = NULL;
4615 listitem_T *li = NULL;
4616 long idx = 0;
4617 char_u *tofree = NULL;
4618
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004619 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004620 save_cpo = p_cpo;
4621 p_cpo = (char_u *)"";
4622
4623 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004624 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004625 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004626 // type MATCH_LIST: return empty list when there are no matches.
4627 // type MATCH_POS: return ["", -1, -1, -1]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004628 if (rettv_list_alloc(rettv) == FAIL)
4629 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004630 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004631 && (list_append_string(rettv->vval.v_list,
4632 (char_u *)"", 0) == FAIL
4633 || list_append_number(rettv->vval.v_list,
4634 (varnumber_T)-1) == FAIL
4635 || list_append_number(rettv->vval.v_list,
4636 (varnumber_T)-1) == FAIL
4637 || list_append_number(rettv->vval.v_list,
4638 (varnumber_T)-1) == FAIL))
4639 {
4640 list_free(rettv->vval.v_list);
4641 rettv->vval.v_list = NULL;
4642 goto theend;
4643 }
4644 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004645 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004646 {
4647 rettv->v_type = VAR_STRING;
4648 rettv->vval.v_string = NULL;
4649 }
4650
4651 if (argvars[0].v_type == VAR_LIST)
4652 {
4653 if ((l = argvars[0].vval.v_list) == NULL)
4654 goto theend;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01004655 range_list_materialize(l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004656 li = l->lv_first;
4657 }
4658 else
4659 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004660 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004661 len = (long)STRLEN(str);
4662 }
4663
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004664 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004665 if (pat == NULL)
4666 goto theend;
4667
4668 if (argvars[2].v_type != VAR_UNKNOWN)
4669 {
4670 int error = FALSE;
4671
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004672 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004673 if (error)
4674 goto theend;
4675 if (l != NULL)
4676 {
4677 li = list_find(l, start);
4678 if (li == NULL)
4679 goto theend;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01004680 idx = l->lv_u.mat.lv_idx; // use the cached index
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004681 }
4682 else
4683 {
4684 if (start < 0)
4685 start = 0;
4686 if (start > len)
4687 goto theend;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004688 // When "count" argument is there ignore matches before "start",
4689 // otherwise skip part of the string. Differs when pattern is "^"
4690 // or "\<".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004691 if (argvars[3].v_type != VAR_UNKNOWN)
4692 startcol = start;
4693 else
4694 {
4695 str += start;
4696 len -= start;
4697 }
4698 }
4699
4700 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004701 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004702 if (error)
4703 goto theend;
4704 }
4705
4706 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4707 if (regmatch.regprog != NULL)
4708 {
4709 regmatch.rm_ic = p_ic;
4710
4711 for (;;)
4712 {
4713 if (l != NULL)
4714 {
4715 if (li == NULL)
4716 {
4717 match = FALSE;
4718 break;
4719 }
4720 vim_free(tofree);
4721 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4722 if (str == NULL)
4723 break;
4724 }
4725
4726 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4727
4728 if (match && --nth <= 0)
4729 break;
4730 if (l == NULL && !match)
4731 break;
4732
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004733 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 if (l != NULL)
4735 {
4736 li = li->li_next;
4737 ++idx;
4738 }
4739 else
4740 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004741 startcol = (colnr_T)(regmatch.startp[0]
4742 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004743 if (startcol > (colnr_T)len
4744 || str + startcol <= regmatch.startp[0])
4745 {
4746 match = FALSE;
4747 break;
4748 }
4749 }
4750 }
4751
4752 if (match)
4753 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004754 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004755 {
4756 listitem_T *li1 = rettv->vval.v_list->lv_first;
4757 listitem_T *li2 = li1->li_next;
4758 listitem_T *li3 = li2->li_next;
4759 listitem_T *li4 = li3->li_next;
4760
4761 vim_free(li1->li_tv.vval.v_string);
4762 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4763 (int)(regmatch.endp[0] - regmatch.startp[0]));
4764 li3->li_tv.vval.v_number =
4765 (varnumber_T)(regmatch.startp[0] - expr);
4766 li4->li_tv.vval.v_number =
4767 (varnumber_T)(regmatch.endp[0] - expr);
4768 if (l != NULL)
4769 li2->li_tv.vval.v_number = (varnumber_T)idx;
4770 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004771 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004772 {
4773 int i;
4774
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004775 // return list with matched string and submatches
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004776 for (i = 0; i < NSUBEXP; ++i)
4777 {
4778 if (regmatch.endp[i] == NULL)
4779 {
4780 if (list_append_string(rettv->vval.v_list,
4781 (char_u *)"", 0) == FAIL)
4782 break;
4783 }
4784 else if (list_append_string(rettv->vval.v_list,
4785 regmatch.startp[i],
4786 (int)(regmatch.endp[i] - regmatch.startp[i]))
4787 == FAIL)
4788 break;
4789 }
4790 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004791 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004792 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004793 // return matched string
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004794 if (l != NULL)
4795 copy_tv(&li->li_tv, rettv);
4796 else
4797 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4798 (int)(regmatch.endp[0] - regmatch.startp[0]));
4799 }
4800 else if (l != NULL)
4801 rettv->vval.v_number = idx;
4802 else
4803 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004804 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004805 rettv->vval.v_number =
4806 (varnumber_T)(regmatch.startp[0] - str);
4807 else
4808 rettv->vval.v_number =
4809 (varnumber_T)(regmatch.endp[0] - str);
4810 rettv->vval.v_number += (varnumber_T)(str - expr);
4811 }
4812 }
4813 vim_regfree(regmatch.regprog);
4814 }
4815
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004816theend:
4817 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01004818 // matchstrpos() without a list: drop the second item.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004819 listitem_remove(rettv->vval.v_list,
4820 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004821 vim_free(tofree);
4822 p_cpo = save_cpo;
4823}
4824
4825/*
4826 * "match()" function
4827 */
4828 static void
4829f_match(typval_T *argvars, typval_T *rettv)
4830{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004831 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004832}
4833
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004834/*
4835 * "matchend()" function
4836 */
4837 static void
4838f_matchend(typval_T *argvars, typval_T *rettv)
4839{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004840 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004841}
4842
4843/*
4844 * "matchlist()" function
4845 */
4846 static void
4847f_matchlist(typval_T *argvars, typval_T *rettv)
4848{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004849 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850}
4851
4852/*
4853 * "matchstr()" function
4854 */
4855 static void
4856f_matchstr(typval_T *argvars, typval_T *rettv)
4857{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004858 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859}
4860
4861/*
4862 * "matchstrpos()" function
4863 */
4864 static void
4865f_matchstrpos(typval_T *argvars, typval_T *rettv)
4866{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004867 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004868}
4869
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004870 static void
4871max_min(typval_T *argvars, typval_T *rettv, int domax)
4872{
4873 varnumber_T n = 0;
4874 varnumber_T i;
4875 int error = FALSE;
4876
4877 if (argvars[0].v_type == VAR_LIST)
4878 {
4879 list_T *l;
4880 listitem_T *li;
4881
4882 l = argvars[0].vval.v_list;
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004883 if (l != NULL && l->lv_len > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004884 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004885 if (l->lv_first == &range_list_item)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004886 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004887 if ((l->lv_u.nonmat.lv_stride > 0) ^ domax)
4888 n = l->lv_u.nonmat.lv_start;
4889 else
4890 n = l->lv_u.nonmat.lv_start + (l->lv_len - 1)
4891 * l->lv_u.nonmat.lv_stride;
4892 }
4893 else
4894 {
4895 li = l->lv_first;
4896 if (li != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004897 {
Bram Moolenaar9f2d0202020-01-30 16:40:10 +01004898 n = tv_get_number_chk(&li->li_tv, &error);
4899 for (;;)
4900 {
4901 li = li->li_next;
4902 if (li == NULL)
4903 break;
4904 i = tv_get_number_chk(&li->li_tv, &error);
4905 if (domax ? i > n : i < n)
4906 n = i;
4907 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004908 }
4909 }
4910 }
4911 }
4912 else if (argvars[0].v_type == VAR_DICT)
4913 {
4914 dict_T *d;
4915 int first = TRUE;
4916 hashitem_T *hi;
4917 int todo;
4918
4919 d = argvars[0].vval.v_dict;
4920 if (d != NULL)
4921 {
4922 todo = (int)d->dv_hashtab.ht_used;
4923 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4924 {
4925 if (!HASHITEM_EMPTY(hi))
4926 {
4927 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004928 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004929 if (first)
4930 {
4931 n = i;
4932 first = FALSE;
4933 }
4934 else if (domax ? i > n : i < n)
4935 n = i;
4936 }
4937 }
4938 }
4939 }
4940 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004941 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942 rettv->vval.v_number = error ? 0 : n;
4943}
4944
4945/*
4946 * "max()" function
4947 */
4948 static void
4949f_max(typval_T *argvars, typval_T *rettv)
4950{
4951 max_min(argvars, rettv, TRUE);
4952}
4953
4954/*
4955 * "min()" function
4956 */
4957 static void
4958f_min(typval_T *argvars, typval_T *rettv)
4959{
4960 max_min(argvars, rettv, FALSE);
4961}
4962
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004963#if defined(FEAT_MZSCHEME) || defined(PROTO)
4964/*
4965 * "mzeval()" function
4966 */
4967 static void
4968f_mzeval(typval_T *argvars, typval_T *rettv)
4969{
4970 char_u *str;
4971 char_u buf[NUMBUFLEN];
4972
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004973 if (check_restricted() || check_secure())
4974 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004975 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004976 do_mzeval(str, rettv);
4977}
4978
4979 void
4980mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4981{
4982 typval_T argvars[3];
4983
4984 argvars[0].v_type = VAR_STRING;
4985 argvars[0].vval.v_string = name;
4986 copy_tv(args, &argvars[1]);
4987 argvars[2].v_type = VAR_UNKNOWN;
4988 f_call(argvars, rettv);
4989 clear_tv(&argvars[1]);
4990}
4991#endif
4992
4993/*
4994 * "nextnonblank()" function
4995 */
4996 static void
4997f_nextnonblank(typval_T *argvars, typval_T *rettv)
4998{
4999 linenr_T lnum;
5000
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005001 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005002 {
5003 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5004 {
5005 lnum = 0;
5006 break;
5007 }
5008 if (*skipwhite(ml_get(lnum)) != NUL)
5009 break;
5010 }
5011 rettv->vval.v_number = lnum;
5012}
5013
5014/*
5015 * "nr2char()" function
5016 */
5017 static void
5018f_nr2char(typval_T *argvars, typval_T *rettv)
5019{
5020 char_u buf[NUMBUFLEN];
5021
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005022 if (has_mbyte)
5023 {
5024 int utf8 = 0;
5025
5026 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005027 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005028 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005029 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005030 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005031 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005032 }
5033 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005034 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005035 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005036 buf[1] = NUL;
5037 }
5038 rettv->v_type = VAR_STRING;
5039 rettv->vval.v_string = vim_strsave(buf);
5040}
5041
5042/*
5043 * "or(expr, expr)" function
5044 */
5045 static void
5046f_or(typval_T *argvars, typval_T *rettv)
5047{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005048 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5049 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005050}
5051
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005052#ifdef FEAT_PERL
5053/*
5054 * "perleval()" function
5055 */
5056 static void
5057f_perleval(typval_T *argvars, typval_T *rettv)
5058{
5059 char_u *str;
5060 char_u buf[NUMBUFLEN];
5061
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005062 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005063 do_perleval(str, rettv);
5064}
5065#endif
5066
5067#ifdef FEAT_FLOAT
5068/*
5069 * "pow()" function
5070 */
5071 static void
5072f_pow(typval_T *argvars, typval_T *rettv)
5073{
5074 float_T fx = 0.0, fy = 0.0;
5075
5076 rettv->v_type = VAR_FLOAT;
5077 if (get_float_arg(argvars, &fx) == OK
5078 && get_float_arg(&argvars[1], &fy) == OK)
5079 rettv->vval.v_float = pow(fx, fy);
5080 else
5081 rettv->vval.v_float = 0.0;
5082}
5083#endif
5084
5085/*
5086 * "prevnonblank()" function
5087 */
5088 static void
5089f_prevnonblank(typval_T *argvars, typval_T *rettv)
5090{
5091 linenr_T lnum;
5092
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005093 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5095 lnum = 0;
5096 else
5097 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5098 --lnum;
5099 rettv->vval.v_number = lnum;
5100}
5101
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005102// This dummy va_list is here because:
5103// - passing a NULL pointer doesn't work when va_list isn't a pointer
5104// - locally in the function results in a "used before set" warning
5105// - using va_start() to initialize it gives "function with fixed args" error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106static va_list ap;
5107
5108/*
5109 * "printf()" function
5110 */
5111 static void
5112f_printf(typval_T *argvars, typval_T *rettv)
5113{
5114 char_u buf[NUMBUFLEN];
5115 int len;
5116 char_u *s;
5117 int saved_did_emsg = did_emsg;
5118 char *fmt;
5119
5120 rettv->v_type = VAR_STRING;
5121 rettv->vval.v_string = NULL;
5122
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005123 // Get the required length, allocate the buffer and do it for real.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005124 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005125 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005126 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005127 if (!did_emsg)
5128 {
5129 s = alloc(len + 1);
5130 if (s != NULL)
5131 {
5132 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005133 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5134 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005135 }
5136 }
5137 did_emsg |= saved_did_emsg;
5138}
5139
5140/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005141 * "pum_getpos()" function
5142 */
5143 static void
5144f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5145{
5146 if (rettv_dict_alloc(rettv) != OK)
5147 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005148 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005149}
5150
5151/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005152 * "pumvisible()" function
5153 */
5154 static void
5155f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5156{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005157 if (pum_visible())
5158 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005159}
5160
5161#ifdef FEAT_PYTHON3
5162/*
5163 * "py3eval()" function
5164 */
5165 static void
5166f_py3eval(typval_T *argvars, typval_T *rettv)
5167{
5168 char_u *str;
5169 char_u buf[NUMBUFLEN];
5170
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005171 if (check_restricted() || check_secure())
5172 return;
5173
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005174 if (p_pyx == 0)
5175 p_pyx = 3;
5176
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005177 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005178 do_py3eval(str, rettv);
5179}
5180#endif
5181
5182#ifdef FEAT_PYTHON
5183/*
5184 * "pyeval()" function
5185 */
5186 static void
5187f_pyeval(typval_T *argvars, typval_T *rettv)
5188{
5189 char_u *str;
5190 char_u buf[NUMBUFLEN];
5191
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005192 if (check_restricted() || check_secure())
5193 return;
5194
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005195 if (p_pyx == 0)
5196 p_pyx = 2;
5197
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005198 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 do_pyeval(str, rettv);
5200}
5201#endif
5202
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005203#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5204/*
5205 * "pyxeval()" function
5206 */
5207 static void
5208f_pyxeval(typval_T *argvars, typval_T *rettv)
5209{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005210 if (check_restricted() || check_secure())
5211 return;
5212
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005213# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5214 init_pyxversion();
5215 if (p_pyx == 2)
5216 f_pyeval(argvars, rettv);
5217 else
5218 f_py3eval(argvars, rettv);
5219# elif defined(FEAT_PYTHON)
5220 f_pyeval(argvars, rettv);
5221# elif defined(FEAT_PYTHON3)
5222 f_py3eval(argvars, rettv);
5223# endif
5224}
5225#endif
5226
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005227/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005228 * "rand()" function
5229 */
5230 static void
5231f_rand(typval_T *argvars, typval_T *rettv)
5232{
5233 list_T *l = NULL;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005234 static list_T *globl = NULL;
5235 UINT32_T x, y, z, w, t, result;
5236 listitem_T *lx, *ly, *lz, *lw;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005237
5238 if (argvars[0].v_type == VAR_UNKNOWN)
5239 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005240 // When no argument is given use the global seed list.
5241 if (globl == NULL)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005242 {
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005243 // Initialize the global seed list.
5244 f_srand(argvars, rettv);
5245 l = rettv->vval.v_list;
5246 if (l == NULL || list_len(l) != 4)
5247 {
5248 clear_tv(rettv);
5249 goto theend;
5250 }
5251 globl = l;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005252 }
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005253 else
5254 l = globl;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005255 }
5256 else if (argvars[0].v_type == VAR_LIST)
5257 {
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005258 l = argvars[0].vval.v_list;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005259 if (l == NULL || list_len(l) != 4)
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005260 goto theend;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005261 }
5262 else
5263 goto theend;
5264
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005265 lx = list_find(l, 0L);
5266 ly = list_find(l, 1L);
5267 lz = list_find(l, 2L);
5268 lw = list_find(l, 3L);
5269 if (lx->li_tv.v_type != VAR_NUMBER) goto theend;
5270 if (ly->li_tv.v_type != VAR_NUMBER) goto theend;
5271 if (lz->li_tv.v_type != VAR_NUMBER) goto theend;
5272 if (lw->li_tv.v_type != VAR_NUMBER) goto theend;
5273 x = (UINT32_T)lx->li_tv.vval.v_number;
5274 y = (UINT32_T)ly->li_tv.vval.v_number;
5275 z = (UINT32_T)lz->li_tv.vval.v_number;
5276 w = (UINT32_T)lw->li_tv.vval.v_number;
5277
5278 // SHUFFLE_XOSHIRO128STARSTAR
5279#define ROTL(x, k) ((x << k) | (x >> (32 - k)))
5280 result = ROTL(y * 5, 7) * 9;
5281 t = y << 9;
5282 z ^= x;
5283 w ^= y;
5284 y ^= z, x ^= w;
5285 z ^= t;
5286 w = ROTL(w, 11);
5287#undef ROTL
5288
5289 lx->li_tv.vval.v_number = (varnumber_T)x;
5290 ly->li_tv.vval.v_number = (varnumber_T)y;
5291 lz->li_tv.vval.v_number = (varnumber_T)z;
5292 lw->li_tv.vval.v_number = (varnumber_T)w;
5293
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005294 rettv->v_type = VAR_NUMBER;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005295 rettv->vval.v_number = (varnumber_T)result;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005296 return;
5297
5298theend:
5299 semsg(_(e_invarg2), tv_get_string(&argvars[0]));
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01005300 rettv->v_type = VAR_NUMBER;
5301 rettv->vval.v_number = -1;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01005302}
5303
5304/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005305 * "range()" function
5306 */
5307 static void
5308f_range(typval_T *argvars, typval_T *rettv)
5309{
5310 varnumber_T start;
5311 varnumber_T end;
5312 varnumber_T stride = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005313 int error = FALSE;
5314
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005315 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005316 if (argvars[1].v_type == VAR_UNKNOWN)
5317 {
5318 end = start - 1;
5319 start = 0;
5320 }
5321 else
5322 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005323 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005324 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005325 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005326 }
5327
5328 if (error)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005329 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005330 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005331 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005332 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005333 emsg(_("E727: Start past end"));
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005334 else if (rettv_list_alloc(rettv) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005335 {
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005336 list_T *list = rettv->vval.v_list;
5337
5338 // Create a non-materialized list. This is much more efficient and
5339 // works with ":for". If used otherwise range_list_materialize() must
5340 // be called.
5341 list->lv_first = &range_list_item;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005342 list->lv_u.nonmat.lv_start = start;
5343 list->lv_u.nonmat.lv_end = end;
5344 list->lv_u.nonmat.lv_stride = stride;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01005345 list->lv_len = (end - start) / stride + 1;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005346 }
5347}
5348
5349/*
5350 * If "list" is a non-materialized list then materialize it now.
5351 */
5352 void
5353range_list_materialize(list_T *list)
5354{
5355 if (list->lv_first == &range_list_item)
5356 {
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005357 varnumber_T start = list->lv_u.nonmat.lv_start;
5358 varnumber_T end = list->lv_u.nonmat.lv_end;
5359 int stride = list->lv_u.nonmat.lv_stride;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005360 varnumber_T i;
5361
5362 list->lv_first = NULL;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005363 list->lv_u.mat.lv_last = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005364 list->lv_len = 0;
Bram Moolenaar0ff6aad2020-01-29 21:27:21 +01005365 list->lv_u.mat.lv_idx_item = NULL;
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01005366 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5367 if (list_append_number(list, (varnumber_T)i) == FAIL)
5368 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005369 }
5370}
5371
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005372 static void
5373return_register(int regname, typval_T *rettv)
5374{
5375 char_u buf[2] = {0, 0};
5376
5377 buf[0] = (char_u)regname;
5378 rettv->v_type = VAR_STRING;
5379 rettv->vval.v_string = vim_strsave(buf);
5380}
5381
5382/*
5383 * "reg_executing()" function
5384 */
5385 static void
5386f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5387{
5388 return_register(reg_executing, rettv);
5389}
5390
5391/*
5392 * "reg_recording()" function
5393 */
5394 static void
5395f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5396{
5397 return_register(reg_recording, rettv);
5398}
5399
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005400#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005401/*
5402 * Convert a List to proftime_T.
5403 * Return FAIL when there is something wrong.
5404 */
5405 static int
5406list2proftime(typval_T *arg, proftime_T *tm)
5407{
5408 long n1, n2;
5409 int error = FALSE;
5410
5411 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5412 || arg->vval.v_list->lv_len != 2)
5413 return FAIL;
5414 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5415 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005416# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 tm->HighPart = n1;
5418 tm->LowPart = n2;
5419# else
5420 tm->tv_sec = n1;
5421 tm->tv_usec = n2;
5422# endif
5423 return error ? FAIL : OK;
5424}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005425#endif // FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005426
5427/*
5428 * "reltime()" function
5429 */
5430 static void
5431f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5432{
5433#ifdef FEAT_RELTIME
5434 proftime_T res;
5435 proftime_T start;
5436
5437 if (argvars[0].v_type == VAR_UNKNOWN)
5438 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005439 // No arguments: get current time.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005440 profile_start(&res);
5441 }
5442 else if (argvars[1].v_type == VAR_UNKNOWN)
5443 {
5444 if (list2proftime(&argvars[0], &res) == FAIL)
5445 return;
5446 profile_end(&res);
5447 }
5448 else
5449 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005450 // Two arguments: compute the difference.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005451 if (list2proftime(&argvars[0], &start) == FAIL
5452 || list2proftime(&argvars[1], &res) == FAIL)
5453 return;
5454 profile_sub(&res, &start);
5455 }
5456
5457 if (rettv_list_alloc(rettv) == OK)
5458 {
5459 long n1, n2;
5460
Bram Moolenaar4f974752019-02-17 17:44:42 +01005461# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005462 n1 = res.HighPart;
5463 n2 = res.LowPart;
5464# else
5465 n1 = res.tv_sec;
5466 n2 = res.tv_usec;
5467# endif
5468 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5469 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5470 }
5471#endif
5472}
5473
5474#ifdef FEAT_FLOAT
5475/*
5476 * "reltimefloat()" function
5477 */
5478 static void
5479f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5480{
5481# ifdef FEAT_RELTIME
5482 proftime_T tm;
5483# endif
5484
5485 rettv->v_type = VAR_FLOAT;
5486 rettv->vval.v_float = 0;
5487# ifdef FEAT_RELTIME
5488 if (list2proftime(&argvars[0], &tm) == OK)
5489 rettv->vval.v_float = profile_float(&tm);
5490# endif
5491}
5492#endif
5493
5494/*
5495 * "reltimestr()" function
5496 */
5497 static void
5498f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5499{
5500#ifdef FEAT_RELTIME
5501 proftime_T tm;
5502#endif
5503
5504 rettv->v_type = VAR_STRING;
5505 rettv->vval.v_string = NULL;
5506#ifdef FEAT_RELTIME
5507 if (list2proftime(&argvars[0], &tm) == OK)
5508 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5509#endif
5510}
5511
5512#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005513 static void
5514make_connection(void)
5515{
5516 if (X_DISPLAY == NULL
5517# ifdef FEAT_GUI
5518 && !gui.in_use
5519# endif
5520 )
5521 {
5522 x_force_connect = TRUE;
5523 setup_term_clip();
5524 x_force_connect = FALSE;
5525 }
5526}
5527
5528 static int
5529check_connection(void)
5530{
5531 make_connection();
5532 if (X_DISPLAY == NULL)
5533 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005534 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005535 return FAIL;
5536 }
5537 return OK;
5538}
5539#endif
5540
5541#ifdef FEAT_CLIENTSERVER
5542 static void
5543remote_common(typval_T *argvars, typval_T *rettv, int expr)
5544{
5545 char_u *server_name;
5546 char_u *keys;
5547 char_u *r = NULL;
5548 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005549 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005550# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005551 HWND w;
5552# else
5553 Window w;
5554# endif
5555
5556 if (check_restricted() || check_secure())
5557 return;
5558
5559# ifdef FEAT_X11
5560 if (check_connection() == FAIL)
5561 return;
5562# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005563 if (argvars[2].v_type != VAR_UNKNOWN
5564 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005565 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005566
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005567 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005568 if (server_name == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005569 return; // type error; errmsg already given
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005570 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005571# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005572 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005573# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005574 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5575 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005576# endif
5577 {
5578 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005579 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005580 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005581 vim_free(r);
5582 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005583 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005584 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005585 return;
5586 }
5587
5588 rettv->vval.v_string = r;
5589
5590 if (argvars[2].v_type != VAR_UNKNOWN)
5591 {
5592 dictitem_T v;
5593 char_u str[30];
5594 char_u *idvar;
5595
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005596 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005597 if (idvar != NULL && *idvar != NUL)
5598 {
5599 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5600 v.di_tv.v_type = VAR_STRING;
5601 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005602 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005603 vim_free(v.di_tv.vval.v_string);
5604 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005605 }
5606}
5607#endif
5608
5609/*
5610 * "remote_expr()" function
5611 */
5612 static void
5613f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5614{
5615 rettv->v_type = VAR_STRING;
5616 rettv->vval.v_string = NULL;
5617#ifdef FEAT_CLIENTSERVER
5618 remote_common(argvars, rettv, TRUE);
5619#endif
5620}
5621
5622/*
5623 * "remote_foreground()" function
5624 */
5625 static void
5626f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5627{
5628#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005629# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005630 // On Win32 it's done in this application.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005631 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005632 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005633
5634 if (server_name != NULL)
5635 serverForeground(server_name);
5636 }
5637# else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005638 // Send a foreground() expression to the server.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005639 argvars[1].v_type = VAR_STRING;
5640 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5641 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005642 rettv->v_type = VAR_STRING;
5643 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005644 remote_common(argvars, rettv, TRUE);
5645 vim_free(argvars[1].vval.v_string);
5646# endif
5647#endif
5648}
5649
5650 static void
5651f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5652{
5653#ifdef FEAT_CLIENTSERVER
5654 dictitem_T v;
5655 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005656# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005657 long_u n = 0;
5658# endif
5659 char_u *serverid;
5660
5661 if (check_restricted() || check_secure())
5662 {
5663 rettv->vval.v_number = -1;
5664 return;
5665 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005666 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005667 if (serverid == NULL)
5668 {
5669 rettv->vval.v_number = -1;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005670 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005671 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005672# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005673 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5674 if (n == 0)
5675 rettv->vval.v_number = -1;
5676 else
5677 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005678 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005679 rettv->vval.v_number = (s != NULL);
5680 }
5681# else
5682 if (check_connection() == FAIL)
5683 return;
5684
5685 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5686 serverStrToWin(serverid), &s);
5687# endif
5688
5689 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5690 {
5691 char_u *retvar;
5692
5693 v.di_tv.v_type = VAR_STRING;
5694 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005695 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005696 if (retvar != NULL)
5697 set_var(retvar, &v.di_tv, FALSE);
5698 vim_free(v.di_tv.vval.v_string);
5699 }
5700#else
5701 rettv->vval.v_number = -1;
5702#endif
5703}
5704
5705 static void
5706f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5707{
5708 char_u *r = NULL;
5709
5710#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005711 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005712
5713 if (serverid != NULL && !check_restricted() && !check_secure())
5714 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005715 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005716# ifdef MSWIN
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005717 // The server's HWND is encoded in the 'id' parameter
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005718 long_u n = 0;
5719# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005720
5721 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005722 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005723
Bram Moolenaar4f974752019-02-17 17:44:42 +01005724# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005725 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5726 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005727 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005728 if (r == NULL)
5729# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005730 if (check_connection() == FAIL
5731 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5732 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005733# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005734 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005735 }
5736#endif
5737 rettv->v_type = VAR_STRING;
5738 rettv->vval.v_string = r;
5739}
5740
5741/*
5742 * "remote_send()" function
5743 */
5744 static void
5745f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5746{
5747 rettv->v_type = VAR_STRING;
5748 rettv->vval.v_string = NULL;
5749#ifdef FEAT_CLIENTSERVER
5750 remote_common(argvars, rettv, FALSE);
5751#endif
5752}
5753
5754/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005755 * "remote_startserver()" function
5756 */
5757 static void
5758f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5759{
5760#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005761 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005762
5763 if (server == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005764 return; // type error; errmsg already given
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005765 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005766 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005767 else
5768 {
5769# ifdef FEAT_X11
5770 if (check_connection() == OK)
5771 serverRegisterName(X_DISPLAY, server);
5772# else
5773 serverSetName(server);
5774# endif
5775 }
5776#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005777 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005778#endif
5779}
5780
5781/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005782 * "rename({from}, {to})" function
5783 */
5784 static void
5785f_rename(typval_T *argvars, typval_T *rettv)
5786{
5787 char_u buf[NUMBUFLEN];
5788
5789 if (check_restricted() || check_secure())
5790 rettv->vval.v_number = -1;
5791 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005792 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5793 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005794}
5795
5796/*
5797 * "repeat()" function
5798 */
5799 static void
5800f_repeat(typval_T *argvars, typval_T *rettv)
5801{
5802 char_u *p;
5803 int n;
5804 int slen;
5805 int len;
5806 char_u *r;
5807 int i;
5808
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005809 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005810 if (argvars[0].v_type == VAR_LIST)
5811 {
5812 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5813 while (n-- > 0)
5814 if (list_extend(rettv->vval.v_list,
5815 argvars[0].vval.v_list, NULL) == FAIL)
5816 break;
5817 }
5818 else
5819 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005820 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005821 rettv->v_type = VAR_STRING;
5822 rettv->vval.v_string = NULL;
5823
5824 slen = (int)STRLEN(p);
5825 len = slen * n;
5826 if (len <= 0)
5827 return;
5828
5829 r = alloc(len + 1);
5830 if (r != NULL)
5831 {
5832 for (i = 0; i < n; i++)
5833 mch_memmove(r + i * slen, p, (size_t)slen);
5834 r[len] = NUL;
5835 }
5836
5837 rettv->vval.v_string = r;
5838 }
5839}
5840
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005841#define SP_NOMOVE 0x01 // don't move cursor
5842#define SP_REPEAT 0x02 // repeat to find outer pair
5843#define SP_RETCOUNT 0x04 // return matchcount
5844#define SP_SETPCMARK 0x08 // set previous context mark
5845#define SP_START 0x10 // accept match at start position
5846#define SP_SUBPAT 0x20 // return nr of matching sub-pattern
5847#define SP_END 0x40 // leave cursor at end of match
5848#define SP_COLUMN 0x80 // start at cursor column
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005849
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005850/*
5851 * Get flags for a search function.
5852 * Possibly sets "p_ws".
5853 * Returns BACKWARD, FORWARD or zero (for an error).
5854 */
5855 static int
5856get_search_arg(typval_T *varp, int *flagsp)
5857{
5858 int dir = FORWARD;
5859 char_u *flags;
5860 char_u nbuf[NUMBUFLEN];
5861 int mask;
5862
5863 if (varp->v_type != VAR_UNKNOWN)
5864 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005865 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005866 if (flags == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005867 return 0; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 while (*flags != NUL)
5869 {
5870 switch (*flags)
5871 {
5872 case 'b': dir = BACKWARD; break;
5873 case 'w': p_ws = TRUE; break;
5874 case 'W': p_ws = FALSE; break;
5875 default: mask = 0;
5876 if (flagsp != NULL)
5877 switch (*flags)
5878 {
5879 case 'c': mask = SP_START; break;
5880 case 'e': mask = SP_END; break;
5881 case 'm': mask = SP_RETCOUNT; break;
5882 case 'n': mask = SP_NOMOVE; break;
5883 case 'p': mask = SP_SUBPAT; break;
5884 case 'r': mask = SP_REPEAT; break;
5885 case 's': mask = SP_SETPCMARK; break;
5886 case 'z': mask = SP_COLUMN; break;
5887 }
5888 if (mask == 0)
5889 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005890 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005891 dir = 0;
5892 }
5893 else
5894 *flagsp |= mask;
5895 }
5896 if (dir == 0)
5897 break;
5898 ++flags;
5899 }
5900 }
5901 return dir;
5902}
5903
5904/*
5905 * Shared by search() and searchpos() functions.
5906 */
5907 static int
5908search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5909{
5910 int flags;
5911 char_u *pat;
5912 pos_T pos;
5913 pos_T save_cursor;
5914 int save_p_ws = p_ws;
5915 int dir;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005916 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005917 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005918#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005919 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005920 long time_limit = 0;
5921#endif
5922 int options = SEARCH_KEEP;
5923 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005924 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005925
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005926 pat = tv_get_string(&argvars[0]);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005927 dir = get_search_arg(&argvars[1], flagsp); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005928 if (dir == 0)
5929 goto theend;
5930 flags = *flagsp;
5931 if (flags & SP_START)
5932 options |= SEARCH_START;
5933 if (flags & SP_END)
5934 options |= SEARCH_END;
5935 if (flags & SP_COLUMN)
5936 options |= SEARCH_COL;
5937
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005938 // Optional arguments: line number to stop searching and timeout.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005939 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5940 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005941 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005942 if (lnum_stop < 0)
5943 goto theend;
5944#ifdef FEAT_RELTIME
5945 if (argvars[3].v_type != VAR_UNKNOWN)
5946 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005947 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005948 if (time_limit < 0)
5949 goto theend;
5950 }
5951#endif
5952 }
5953
5954#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005955 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005956 profile_setlimit(time_limit, &tm);
5957#endif
5958
5959 /*
5960 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5961 * Check to make sure only those flags are set.
5962 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5963 * flags cannot be set. Check for that condition also.
5964 */
5965 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5966 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5967 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005968 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005969 goto theend;
5970 }
5971
5972 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005973 vim_memset(&sia, 0, sizeof(sia));
5974 sia.sa_stop_lnum = (linenr_T)lnum_stop;
5975#ifdef FEAT_RELTIME
5976 sia.sa_tm = &tm;
5977#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005978 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005979 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005980 if (subpatnum != FAIL)
5981 {
5982 if (flags & SP_SUBPAT)
5983 retval = subpatnum;
5984 else
5985 retval = pos.lnum;
5986 if (flags & SP_SETPCMARK)
5987 setpcmark();
5988 curwin->w_cursor = pos;
5989 if (match_pos != NULL)
5990 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005991 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005992 match_pos->lnum = pos.lnum;
5993 match_pos->col = pos.col + 1;
5994 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01005995 // "/$" will put the cursor after the end of the line, may need to
5996 // correct that here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005997 check_cursor();
5998 }
5999
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006000 // If 'n' flag is used: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006001 if (flags & SP_NOMOVE)
6002 curwin->w_cursor = save_cursor;
6003 else
6004 curwin->w_set_curswant = TRUE;
6005theend:
6006 p_ws = save_p_ws;
6007
6008 return retval;
6009}
6010
6011#ifdef FEAT_FLOAT
6012
6013/*
6014 * round() is not in C90, use ceil() or floor() instead.
6015 */
6016 float_T
6017vim_round(float_T f)
6018{
6019 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
6020}
6021
6022/*
6023 * "round({float})" function
6024 */
6025 static void
6026f_round(typval_T *argvars, typval_T *rettv)
6027{
6028 float_T f = 0.0;
6029
6030 rettv->v_type = VAR_FLOAT;
6031 if (get_float_arg(argvars, &f) == OK)
6032 rettv->vval.v_float = vim_round(f);
6033 else
6034 rettv->vval.v_float = 0.0;
6035}
6036#endif
6037
Bram Moolenaare99be0e2019-03-26 22:51:09 +01006038#ifdef FEAT_RUBY
6039/*
6040 * "rubyeval()" function
6041 */
6042 static void
6043f_rubyeval(typval_T *argvars, typval_T *rettv)
6044{
6045 char_u *str;
6046 char_u buf[NUMBUFLEN];
6047
6048 str = tv_get_string_buf(&argvars[0], buf);
6049 do_rubyeval(str, rettv);
6050}
6051#endif
6052
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006053/*
6054 * "screenattr()" function
6055 */
6056 static void
6057f_screenattr(typval_T *argvars, typval_T *rettv)
6058{
6059 int row;
6060 int col;
6061 int c;
6062
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006063 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6064 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065 if (row < 0 || row >= screen_Rows
6066 || col < 0 || col >= screen_Columns)
6067 c = -1;
6068 else
6069 c = ScreenAttrs[LineOffset[row] + col];
6070 rettv->vval.v_number = c;
6071}
6072
6073/*
6074 * "screenchar()" function
6075 */
6076 static void
6077f_screenchar(typval_T *argvars, typval_T *rettv)
6078{
6079 int row;
6080 int col;
6081 int off;
6082 int c;
6083
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006084 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6085 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006086 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006087 c = -1;
6088 else
6089 {
6090 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006091 if (enc_utf8 && ScreenLinesUC[off] != 0)
6092 c = ScreenLinesUC[off];
6093 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006094 c = ScreenLines[off];
6095 }
6096 rettv->vval.v_number = c;
6097}
6098
6099/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006100 * "screenchars()" function
6101 */
6102 static void
6103f_screenchars(typval_T *argvars, typval_T *rettv)
6104{
6105 int row;
6106 int col;
6107 int off;
6108 int c;
6109 int i;
6110
6111 if (rettv_list_alloc(rettv) == FAIL)
6112 return;
6113 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6114 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6115 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6116 return;
6117
6118 off = LineOffset[row] + col;
6119 if (enc_utf8 && ScreenLinesUC[off] != 0)
6120 c = ScreenLinesUC[off];
6121 else
6122 c = ScreenLines[off];
6123 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6124
6125 if (enc_utf8)
6126
6127 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6128 list_append_number(rettv->vval.v_list,
6129 (varnumber_T)ScreenLinesC[i][off]);
6130}
6131
6132/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006133 * "screencol()" function
6134 *
6135 * First column is 1 to be consistent with virtcol().
6136 */
6137 static void
6138f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6139{
6140 rettv->vval.v_number = screen_screencol() + 1;
6141}
6142
6143/*
6144 * "screenrow()" function
6145 */
6146 static void
6147f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6148{
6149 rettv->vval.v_number = screen_screenrow() + 1;
6150}
6151
6152/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006153 * "screenstring()" function
6154 */
6155 static void
6156f_screenstring(typval_T *argvars, typval_T *rettv)
6157{
6158 int row;
6159 int col;
6160 int off;
6161 int c;
6162 int i;
6163 char_u buf[MB_MAXBYTES + 1];
6164 int buflen = 0;
6165
6166 rettv->vval.v_string = NULL;
6167 rettv->v_type = VAR_STRING;
6168
6169 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6170 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6171 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6172 return;
6173
6174 off = LineOffset[row] + col;
6175 if (enc_utf8 && ScreenLinesUC[off] != 0)
6176 c = ScreenLinesUC[off];
6177 else
6178 c = ScreenLines[off];
6179 buflen += mb_char2bytes(c, buf);
6180
6181 if (enc_utf8)
6182 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6183 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6184
6185 buf[buflen] = NUL;
6186 rettv->vval.v_string = vim_strsave(buf);
6187}
6188
6189/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190 * "search()" function
6191 */
6192 static void
6193f_search(typval_T *argvars, typval_T *rettv)
6194{
6195 int flags = 0;
6196
6197 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6198}
6199
6200/*
6201 * "searchdecl()" function
6202 */
6203 static void
6204f_searchdecl(typval_T *argvars, typval_T *rettv)
6205{
6206 int locally = 1;
6207 int thisblock = 0;
6208 int error = FALSE;
6209 char_u *name;
6210
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006211 rettv->vval.v_number = 1; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006212
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006213 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006214 if (argvars[1].v_type != VAR_UNKNOWN)
6215 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006216 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006217 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006218 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006219 }
6220 if (!error && name != NULL)
6221 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6222 locally, thisblock, SEARCH_KEEP) == FAIL;
6223}
6224
6225/*
6226 * Used by searchpair() and searchpairpos()
6227 */
6228 static int
6229searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6230{
6231 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006232 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006233 int save_p_ws = p_ws;
6234 int dir;
6235 int flags = 0;
6236 char_u nbuf1[NUMBUFLEN];
6237 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006238 int retval = 0; // default: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006239 long lnum_stop = 0;
6240 long time_limit = 0;
6241
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006242 // Get the three pattern arguments: start, middle, end. Will result in an
6243 // error if not a valid argument.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006244 spat = tv_get_string_chk(&argvars[0]);
6245 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6246 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006247 if (spat == NULL || mpat == NULL || epat == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006248 goto theend; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006249
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006250 // Handle the optional fourth argument: flags
6251 dir = get_search_arg(&argvars[3], &flags); // may set p_ws
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006252 if (dir == 0)
6253 goto theend;
6254
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006255 // Don't accept SP_END or SP_SUBPAT.
6256 // Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006257 if ((flags & (SP_END | SP_SUBPAT)) != 0
6258 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6259 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006260 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006261 goto theend;
6262 }
6263
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006264 // Using 'r' implies 'W', otherwise it doesn't work.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006265 if (flags & SP_REPEAT)
6266 p_ws = FALSE;
6267
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006268 // Optional fifth argument: skip expression
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006269 if (argvars[3].v_type == VAR_UNKNOWN
6270 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006271 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 else
6273 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006274 skip = &argvars[4];
6275 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6276 && skip->v_type != VAR_STRING)
6277 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006278 // Type error
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006279 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006280 goto theend;
6281 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006282 if (argvars[5].v_type != VAR_UNKNOWN)
6283 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006284 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006285 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006286 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006287 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006288 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006289 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290#ifdef FEAT_RELTIME
6291 if (argvars[6].v_type != VAR_UNKNOWN)
6292 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006293 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006294 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006295 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006296 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006298 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006299 }
6300#endif
6301 }
6302 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006303
6304 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6305 match_pos, lnum_stop, time_limit);
6306
6307theend:
6308 p_ws = save_p_ws;
6309
6310 return retval;
6311}
6312
6313/*
6314 * "searchpair()" function
6315 */
6316 static void
6317f_searchpair(typval_T *argvars, typval_T *rettv)
6318{
6319 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6320}
6321
6322/*
6323 * "searchpairpos()" function
6324 */
6325 static void
6326f_searchpairpos(typval_T *argvars, typval_T *rettv)
6327{
6328 pos_T match_pos;
6329 int lnum = 0;
6330 int col = 0;
6331
6332 if (rettv_list_alloc(rettv) == FAIL)
6333 return;
6334
6335 if (searchpair_cmn(argvars, &match_pos) > 0)
6336 {
6337 lnum = match_pos.lnum;
6338 col = match_pos.col;
6339 }
6340
6341 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6342 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6343}
6344
6345/*
6346 * Search for a start/middle/end thing.
6347 * Used by searchpair(), see its documentation for the details.
6348 * Returns 0 or -1 for no match,
6349 */
6350 long
6351do_searchpair(
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006352 char_u *spat, // start pattern
6353 char_u *mpat, // middle pattern
6354 char_u *epat, // end pattern
6355 int dir, // BACKWARD or FORWARD
6356 typval_T *skip, // skip expression
6357 int flags, // SP_SETPCMARK and other SP_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006358 pos_T *match_pos,
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006359 linenr_T lnum_stop, // stop at this line if not zero
6360 long time_limit UNUSED) // stop after this many msec
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006361{
6362 char_u *save_cpo;
6363 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6364 long retval = 0;
6365 pos_T pos;
6366 pos_T firstpos;
6367 pos_T foundpos;
6368 pos_T save_cursor;
6369 pos_T save_pos;
6370 int n;
6371 int r;
6372 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006373 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006374 int err;
6375 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006376#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006377 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006378#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006379
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006380 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006381 save_cpo = p_cpo;
6382 p_cpo = empty_option;
6383
6384#ifdef FEAT_RELTIME
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006385 // Set the time limit, if there is one.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006386 profile_setlimit(time_limit, &tm);
6387#endif
6388
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006389 // Make two search patterns: start/end (pat2, for in nested pairs) and
6390 // start/middle/end (pat3, for the top pair).
Bram Moolenaar964b3742019-05-24 18:54:09 +02006391 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6392 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393 if (pat2 == NULL || pat3 == NULL)
6394 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006395 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396 if (*mpat == NUL)
6397 STRCPY(pat3, pat2);
6398 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006399 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006400 spat, epat, mpat);
6401 if (flags & SP_START)
6402 options |= SEARCH_START;
6403
Bram Moolenaar48570482017-10-30 21:48:41 +01006404 if (skip != NULL)
6405 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006406 // Empty string means to not use the skip expression.
Bram Moolenaar48570482017-10-30 21:48:41 +01006407 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6408 use_skip = skip->vval.v_string != NULL
6409 && *skip->vval.v_string != NUL;
6410 }
6411
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412 save_cursor = curwin->w_cursor;
6413 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006414 CLEAR_POS(&firstpos);
6415 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 pat = pat3;
6417 for (;;)
6418 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006419 searchit_arg_T sia;
6420
6421 vim_memset(&sia, 0, sizeof(sia));
6422 sia.sa_stop_lnum = lnum_stop;
6423#ifdef FEAT_RELTIME
6424 sia.sa_tm = &tm;
6425#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006426 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006427 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006428 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006429 // didn't find it or found the first match again: FAIL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006430 break;
6431
6432 if (firstpos.lnum == 0)
6433 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006434 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006435 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006436 // Found the same position again. Can happen with a pattern that
6437 // has "\zs" at the end and searching backwards. Advance one
6438 // character and try again.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006439 if (dir == BACKWARD)
6440 decl(&pos);
6441 else
6442 incl(&pos);
6443 }
6444 foundpos = pos;
6445
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006446 // clear the start flag to avoid getting stuck here
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006447 options &= ~SEARCH_START;
6448
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006449 // If the skip pattern matches, ignore this match.
Bram Moolenaar48570482017-10-30 21:48:41 +01006450 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006451 {
6452 save_pos = curwin->w_cursor;
6453 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006454 err = FALSE;
6455 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006456 curwin->w_cursor = save_pos;
6457 if (err)
6458 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006459 // Evaluating {skip} caused an error, break here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006460 curwin->w_cursor = save_cursor;
6461 retval = -1;
6462 break;
6463 }
6464 if (r)
6465 continue;
6466 }
6467
6468 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6469 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006470 // Found end when searching backwards or start when searching
6471 // forward: nested pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006472 ++nest;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006473 pat = pat2; // nested, don't search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 }
6475 else
6476 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006477 // Found end when searching forward or start when searching
6478 // backward: end of (nested) pair; or found middle in outer pair.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006479 if (--nest == 1)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006480 pat = pat3; // outer level, search for middle
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006481 }
6482
6483 if (nest == 0)
6484 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006485 // Found the match: return matchcount or line number.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486 if (flags & SP_RETCOUNT)
6487 ++retval;
6488 else
6489 retval = pos.lnum;
6490 if (flags & SP_SETPCMARK)
6491 setpcmark();
6492 curwin->w_cursor = pos;
6493 if (!(flags & SP_REPEAT))
6494 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006495 nest = 1; // search for next unmatched
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006496 }
6497 }
6498
6499 if (match_pos != NULL)
6500 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006501 // Store the match cursor position
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502 match_pos->lnum = curwin->w_cursor.lnum;
6503 match_pos->col = curwin->w_cursor.col + 1;
6504 }
6505
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006506 // If 'n' flag is used or search failed: restore cursor position.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507 if ((flags & SP_NOMOVE) || retval == 0)
6508 curwin->w_cursor = save_cursor;
6509
6510theend:
6511 vim_free(pat2);
6512 vim_free(pat3);
6513 if (p_cpo == empty_option)
6514 p_cpo = save_cpo;
6515 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006516 // Darn, evaluating the {skip} expression changed the value.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006517 free_string_option(save_cpo);
6518
6519 return retval;
6520}
6521
6522/*
6523 * "searchpos()" function
6524 */
6525 static void
6526f_searchpos(typval_T *argvars, typval_T *rettv)
6527{
6528 pos_T match_pos;
6529 int lnum = 0;
6530 int col = 0;
6531 int n;
6532 int flags = 0;
6533
6534 if (rettv_list_alloc(rettv) == FAIL)
6535 return;
6536
6537 n = search_cmn(argvars, &match_pos, &flags);
6538 if (n > 0)
6539 {
6540 lnum = match_pos.lnum;
6541 col = match_pos.col;
6542 }
6543
6544 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6545 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6546 if (flags & SP_SUBPAT)
6547 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6548}
6549
6550 static void
6551f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6552{
6553#ifdef FEAT_CLIENTSERVER
6554 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006555 char_u *server = tv_get_string_chk(&argvars[0]);
6556 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006557
6558 rettv->vval.v_number = -1;
6559 if (server == NULL || reply == NULL)
6560 return;
6561 if (check_restricted() || check_secure())
6562 return;
6563# ifdef FEAT_X11
6564 if (check_connection() == FAIL)
6565 return;
6566# endif
6567
6568 if (serverSendReply(server, reply) < 0)
6569 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006570 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006571 return;
6572 }
6573 rettv->vval.v_number = 0;
6574#else
6575 rettv->vval.v_number = -1;
6576#endif
6577}
6578
6579 static void
6580f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6581{
6582 char_u *r = NULL;
6583
6584#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006585# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006586 r = serverGetVimNames();
6587# else
6588 make_connection();
6589 if (X_DISPLAY != NULL)
6590 r = serverGetVimNames(X_DISPLAY);
6591# endif
6592#endif
6593 rettv->v_type = VAR_STRING;
6594 rettv->vval.v_string = r;
6595}
6596
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006597 static void
6598f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6599{
6600 dict_T *d;
6601 dictitem_T *di;
6602 char_u *csearch;
6603
6604 if (argvars[0].v_type != VAR_DICT)
6605 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006606 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006607 return;
6608 }
6609
6610 if ((d = argvars[0].vval.v_dict) != NULL)
6611 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006612 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006613 if (csearch != NULL)
6614 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006615 if (enc_utf8)
6616 {
6617 int pcc[MAX_MCO];
6618 int c = utfc_ptr2char(csearch, pcc);
6619
6620 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6621 }
6622 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006623 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006624 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006625 }
6626
6627 di = dict_find(d, (char_u *)"forward", -1);
6628 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006629 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006630 ? FORWARD : BACKWARD);
6631
6632 di = dict_find(d, (char_u *)"until", -1);
6633 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006634 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006635 }
6636}
6637
6638/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006639 * "setenv()" function
6640 */
6641 static void
6642f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6643{
6644 char_u namebuf[NUMBUFLEN];
6645 char_u valbuf[NUMBUFLEN];
6646 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6647
6648 if (argvars[1].v_type == VAR_SPECIAL
6649 && argvars[1].vval.v_number == VVAL_NULL)
6650 vim_unsetenv(name);
6651 else
6652 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6653}
6654
6655/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006656 * "setfperm({fname}, {mode})" function
6657 */
6658 static void
6659f_setfperm(typval_T *argvars, typval_T *rettv)
6660{
6661 char_u *fname;
6662 char_u modebuf[NUMBUFLEN];
6663 char_u *mode_str;
6664 int i;
6665 int mask;
6666 int mode = 0;
6667
6668 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006669 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006670 if (fname == NULL)
6671 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006672 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006673 if (mode_str == NULL)
6674 return;
6675 if (STRLEN(mode_str) != 9)
6676 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006677 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006678 return;
6679 }
6680
6681 mask = 1;
6682 for (i = 8; i >= 0; --i)
6683 {
6684 if (mode_str[i] != '-')
6685 mode |= mask;
6686 mask = mask << 1;
6687 }
6688 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6689}
6690
6691/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006692 * "setpos()" function
6693 */
6694 static void
6695f_setpos(typval_T *argvars, typval_T *rettv)
6696{
6697 pos_T pos;
6698 int fnum;
6699 char_u *name;
6700 colnr_T curswant = -1;
6701
6702 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006703 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006704 if (name != NULL)
6705 {
6706 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6707 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01006708 if (pos.col != MAXCOL && --pos.col < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006709 pos.col = 0;
6710 if (name[0] == '.' && name[1] == NUL)
6711 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006712 // set cursor; "fnum" is ignored
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006713 curwin->w_cursor = pos;
6714 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006715 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006716 curwin->w_curswant = curswant - 1;
6717 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006718 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006719 check_cursor();
6720 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006721 }
6722 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6723 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006724 // set mark
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006725 if (setmark_pos(name[1], &pos, fnum) == OK)
6726 rettv->vval.v_number = 0;
6727 }
6728 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006729 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006730 }
6731 }
6732}
6733
6734/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006735 * "setreg()" function
6736 */
6737 static void
6738f_setreg(typval_T *argvars, typval_T *rettv)
6739{
6740 int regname;
6741 char_u *strregname;
6742 char_u *stropt;
6743 char_u *strval;
6744 int append;
6745 char_u yank_type;
6746 long block_len;
6747
6748 block_len = -1;
6749 yank_type = MAUTO;
6750 append = FALSE;
6751
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006752 strregname = tv_get_string_chk(argvars);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006753 rettv->vval.v_number = 1; // FAIL is default
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006754
6755 if (strregname == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006756 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006757 regname = *strregname;
6758 if (regname == 0 || regname == '@')
6759 regname = '"';
6760
6761 if (argvars[2].v_type != VAR_UNKNOWN)
6762 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006763 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006764 if (stropt == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006765 return; // type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006766 for (; *stropt != NUL; ++stropt)
6767 switch (*stropt)
6768 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006769 case 'a': case 'A': // append
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006770 append = TRUE;
6771 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006772 case 'v': case 'c': // character-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006773 yank_type = MCHAR;
6774 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006775 case 'V': case 'l': // line-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776 yank_type = MLINE;
6777 break;
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006778 case 'b': case Ctrl_V: // block-wise selection
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 yank_type = MBLOCK;
6780 if (VIM_ISDIGIT(stropt[1]))
6781 {
6782 ++stropt;
6783 block_len = getdigits(&stropt) - 1;
6784 --stropt;
6785 }
6786 break;
6787 }
6788 }
6789
6790 if (argvars[1].v_type == VAR_LIST)
6791 {
6792 char_u **lstval;
6793 char_u **allocval;
6794 char_u buf[NUMBUFLEN];
6795 char_u **curval;
6796 char_u **curallocval;
6797 list_T *ll = argvars[1].vval.v_list;
6798 listitem_T *li;
6799 int len;
6800
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006801 // If the list is NULL handle like an empty list.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802 len = ll == NULL ? 0 : ll->lv_len;
6803
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006804 // First half: use for pointers to result lines; second half: use for
6805 // pointers to allocated copies.
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006806 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006807 if (lstval == NULL)
6808 return;
6809 curval = lstval;
6810 allocval = lstval + len + 2;
6811 curallocval = allocval;
6812
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006813 if (ll != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006814 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006815 range_list_materialize(ll);
6816 for (li = ll->lv_first; li != NULL; li = li->li_next)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006817 {
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006818 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006819 if (strval == NULL)
6820 goto free_lstval;
Bram Moolenaar50985eb2020-01-27 22:09:39 +01006821 if (strval == buf)
6822 {
6823 // Need to make a copy, next tv_get_string_buf_chk() will
6824 // overwrite the string.
6825 strval = vim_strsave(buf);
6826 if (strval == NULL)
6827 goto free_lstval;
6828 *curallocval++ = strval;
6829 }
6830 *curval++ = strval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006832 }
6833 *curval++ = NULL;
6834
6835 write_reg_contents_lst(regname, lstval, -1,
6836 append, yank_type, block_len);
6837free_lstval:
6838 while (curallocval > allocval)
6839 vim_free(*--curallocval);
6840 vim_free(lstval);
6841 }
6842 else
6843 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006844 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006845 if (strval == NULL)
6846 return;
6847 write_reg_contents_ex(regname, strval, -1,
6848 append, yank_type, block_len);
6849 }
6850 rettv->vval.v_number = 0;
6851}
6852
6853/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006854 * "settagstack()" function
6855 */
6856 static void
6857f_settagstack(typval_T *argvars, typval_T *rettv)
6858{
6859 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6860 win_T *wp;
6861 dict_T *d;
6862 int action = 'r';
6863
6864 rettv->vval.v_number = -1;
6865
6866 // first argument: window number or id
6867 wp = find_win_by_nr_or_id(&argvars[0]);
6868 if (wp == NULL)
6869 return;
6870
6871 // second argument: dict with items to set in the tag stack
6872 if (argvars[1].v_type != VAR_DICT)
6873 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006874 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006875 return;
6876 }
6877 d = argvars[1].vval.v_dict;
6878 if (d == NULL)
6879 return;
6880
6881 // third argument: action - 'a' for append and 'r' for replace.
6882 // default is to replace the stack.
6883 if (argvars[2].v_type == VAR_UNKNOWN)
6884 action = 'r';
6885 else if (argvars[2].v_type == VAR_STRING)
6886 {
6887 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006888 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006889 if (actstr == NULL)
6890 return;
Bram Moolenaar271fa082020-01-02 14:02:16 +01006891 if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
6892 && actstr[1] == NUL)
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006893 action = *actstr;
6894 else
6895 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006896 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006897 return;
6898 }
6899 }
6900 else
6901 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006902 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006903 return;
6904 }
6905
6906 if (set_tagstack(wp, d, action) == OK)
6907 rettv->vval.v_number = 0;
6908}
6909
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006910#ifdef FEAT_CRYPT
6911/*
6912 * "sha256({string})" function
6913 */
6914 static void
6915f_sha256(typval_T *argvars, typval_T *rettv)
6916{
6917 char_u *p;
6918
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006919 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006920 rettv->vval.v_string = vim_strsave(
6921 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6922 rettv->v_type = VAR_STRING;
6923}
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01006924#endif // FEAT_CRYPT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006925
6926/*
6927 * "shellescape({string})" function
6928 */
6929 static void
6930f_shellescape(typval_T *argvars, typval_T *rettv)
6931{
Bram Moolenaar20615522017-06-05 18:46:26 +02006932 int do_special = non_zero_arg(&argvars[1]);
6933
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006934 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006935 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006936 rettv->v_type = VAR_STRING;
6937}
6938
6939/*
6940 * shiftwidth() function
6941 */
6942 static void
6943f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6944{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006945 rettv->vval.v_number = 0;
6946
6947 if (argvars[0].v_type != VAR_UNKNOWN)
6948 {
6949 long col;
6950
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006951 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006952 if (col < 0)
6953 return; // type error; errmsg already given
6954#ifdef FEAT_VARTABS
6955 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6956 return;
6957#endif
6958 }
6959
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006960 rettv->vval.v_number = get_sw_value(curbuf);
6961}
6962
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006963#ifdef FEAT_FLOAT
6964/*
6965 * "sin()" function
6966 */
6967 static void
6968f_sin(typval_T *argvars, typval_T *rettv)
6969{
6970 float_T f = 0.0;
6971
6972 rettv->v_type = VAR_FLOAT;
6973 if (get_float_arg(argvars, &f) == OK)
6974 rettv->vval.v_float = sin(f);
6975 else
6976 rettv->vval.v_float = 0.0;
6977}
6978
6979/*
6980 * "sinh()" function
6981 */
6982 static void
6983f_sinh(typval_T *argvars, typval_T *rettv)
6984{
6985 float_T f = 0.0;
6986
6987 rettv->v_type = VAR_FLOAT;
6988 if (get_float_arg(argvars, &f) == OK)
6989 rettv->vval.v_float = sinh(f);
6990 else
6991 rettv->vval.v_float = 0.0;
6992}
6993#endif
6994
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006995/*
6996 * "soundfold({word})" function
6997 */
6998 static void
6999f_soundfold(typval_T *argvars, typval_T *rettv)
7000{
7001 char_u *s;
7002
7003 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007004 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007005#ifdef FEAT_SPELL
7006 rettv->vval.v_string = eval_soundfold(s);
7007#else
7008 rettv->vval.v_string = vim_strsave(s);
7009#endif
7010}
7011
7012/*
7013 * "spellbadword()" function
7014 */
7015 static void
7016f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
7017{
7018 char_u *word = (char_u *)"";
7019 hlf_T attr = HLF_COUNT;
7020 int len = 0;
7021
7022 if (rettv_list_alloc(rettv) == FAIL)
7023 return;
7024
7025#ifdef FEAT_SPELL
7026 if (argvars[0].v_type == VAR_UNKNOWN)
7027 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007028 // Find the start and length of the badly spelled word.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007029 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
7030 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007031 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007032 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01007033 curwin->w_set_curswant = TRUE;
7034 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007035 }
7036 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
7037 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007038 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007039 int capcol = -1;
7040
7041 if (str != NULL)
7042 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007043 // Check the argument for spelling.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007044 while (*str != NUL)
7045 {
7046 len = spell_check(curwin, str, &attr, &capcol, FALSE);
7047 if (attr != HLF_COUNT)
7048 {
7049 word = str;
7050 break;
7051 }
7052 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02007053 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02007054 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007055 }
7056 }
7057 }
7058#endif
7059
7060 list_append_string(rettv->vval.v_list, word, len);
7061 list_append_string(rettv->vval.v_list, (char_u *)(
7062 attr == HLF_SPB ? "bad" :
7063 attr == HLF_SPR ? "rare" :
7064 attr == HLF_SPL ? "local" :
7065 attr == HLF_SPC ? "caps" :
7066 ""), -1);
7067}
7068
7069/*
7070 * "spellsuggest()" function
7071 */
7072 static void
7073f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
7074{
7075#ifdef FEAT_SPELL
7076 char_u *str;
7077 int typeerr = FALSE;
7078 int maxcount;
7079 garray_T ga;
7080 int i;
7081 listitem_T *li;
7082 int need_capital = FALSE;
7083#endif
7084
7085 if (rettv_list_alloc(rettv) == FAIL)
7086 return;
7087
7088#ifdef FEAT_SPELL
7089 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7090 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007091 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 if (argvars[1].v_type != VAR_UNKNOWN)
7093 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007094 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007095 if (maxcount <= 0)
7096 return;
7097 if (argvars[2].v_type != VAR_UNKNOWN)
7098 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007099 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007100 if (typeerr)
7101 return;
7102 }
7103 }
7104 else
7105 maxcount = 25;
7106
7107 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7108
7109 for (i = 0; i < ga.ga_len; ++i)
7110 {
7111 str = ((char_u **)ga.ga_data)[i];
7112
7113 li = listitem_alloc();
7114 if (li == NULL)
7115 vim_free(str);
7116 else
7117 {
7118 li->li_tv.v_type = VAR_STRING;
7119 li->li_tv.v_lock = 0;
7120 li->li_tv.vval.v_string = str;
7121 list_append(rettv->vval.v_list, li);
7122 }
7123 }
7124 ga_clear(&ga);
7125 }
7126#endif
7127}
7128
7129 static void
7130f_split(typval_T *argvars, typval_T *rettv)
7131{
7132 char_u *str;
7133 char_u *end;
7134 char_u *pat = NULL;
7135 regmatch_T regmatch;
7136 char_u patbuf[NUMBUFLEN];
7137 char_u *save_cpo;
7138 int match;
7139 colnr_T col = 0;
7140 int keepempty = FALSE;
7141 int typeerr = FALSE;
7142
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007143 // Make 'cpoptions' empty, the 'l' flag should not be used here.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007144 save_cpo = p_cpo;
7145 p_cpo = (char_u *)"";
7146
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007147 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 if (argvars[1].v_type != VAR_UNKNOWN)
7149 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007150 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007151 if (pat == NULL)
7152 typeerr = TRUE;
7153 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007154 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007155 }
7156 if (pat == NULL || *pat == NUL)
7157 pat = (char_u *)"[\\x01- ]\\+";
7158
7159 if (rettv_list_alloc(rettv) == FAIL)
7160 return;
7161 if (typeerr)
7162 return;
7163
7164 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7165 if (regmatch.regprog != NULL)
7166 {
7167 regmatch.rm_ic = FALSE;
7168 while (*str != NUL || keepempty)
7169 {
7170 if (*str == NUL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007171 match = FALSE; // empty item at the end
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007172 else
7173 match = vim_regexec_nl(&regmatch, str, col);
7174 if (match)
7175 end = regmatch.startp[0];
7176 else
7177 end = str + STRLEN(str);
7178 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7179 && *str != NUL && match && end < regmatch.endp[0]))
7180 {
7181 if (list_append_string(rettv->vval.v_list, str,
7182 (int)(end - str)) == FAIL)
7183 break;
7184 }
7185 if (!match)
7186 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007187 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188 if (regmatch.endp[0] > str)
7189 col = 0;
7190 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007191 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007192 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007193 str = regmatch.endp[0];
7194 }
7195
7196 vim_regfree(regmatch.regprog);
7197 }
7198
7199 p_cpo = save_cpo;
7200}
7201
7202#ifdef FEAT_FLOAT
7203/*
7204 * "sqrt()" function
7205 */
7206 static void
7207f_sqrt(typval_T *argvars, typval_T *rettv)
7208{
7209 float_T f = 0.0;
7210
7211 rettv->v_type = VAR_FLOAT;
7212 if (get_float_arg(argvars, &f) == OK)
7213 rettv->vval.v_float = sqrt(f);
7214 else
7215 rettv->vval.v_float = 0.0;
7216}
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007217#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218
7219/*
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007220 * "srand()" function
7221 */
7222 static void
7223f_srand(typval_T *argvars, typval_T *rettv)
7224{
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007225 static int dev_urandom_state = -1; // FAIL or OK once tried
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007226 UINT32_T x = 0, z;
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007227
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007228 if (rettv_list_alloc(rettv) == FAIL)
7229 return;
7230 if (argvars[0].v_type == VAR_UNKNOWN)
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007231 {
7232 if (dev_urandom_state != FAIL)
7233 {
7234 int fd = open("/dev/urandom", O_RDONLY);
7235 struct {
7236 union {
7237 UINT32_T number;
7238 char bytes[sizeof(UINT32_T)];
7239 } cont;
7240 } buf;
7241
7242 // Attempt reading /dev/urandom.
7243 if (fd == -1)
7244 dev_urandom_state = FAIL;
7245 else
7246 {
7247 buf.cont.number = 0;
7248 if (read(fd, buf.cont.bytes, sizeof(UINT32_T))
7249 != sizeof(UINT32_T))
7250 dev_urandom_state = FAIL;
7251 else
7252 {
7253 dev_urandom_state = OK;
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007254 x = buf.cont.number;
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007255 }
7256 close(fd);
7257 }
7258
7259 }
7260 if (dev_urandom_state != OK)
7261 // Reading /dev/urandom doesn't work, fall back to time().
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007262 x = vim_time();
Bram Moolenaar07e4a192019-11-26 12:23:30 +01007263 }
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007264 else
7265 {
7266 int error = FALSE;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007267
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007268 x = (UINT32_T)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007269 if (error)
7270 return;
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007271 }
Bram Moolenaarf8c1f922019-11-28 22:13:14 +01007272
7273#define SPLITMIX32 ( \
7274 z = (x += 0x9e3779b9), \
7275 z = (z ^ (z >> 16)) * 0x85ebca6b, \
7276 z = (z ^ (z >> 13)) * 0xc2b2ae35, \
7277 z ^ (z >> 16) \
7278 )
7279
7280 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7281 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7282 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
7283 list_append_number(rettv->vval.v_list, (varnumber_T)SPLITMIX32);
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007284}
7285
Bram Moolenaar0387cae2019-11-29 21:07:58 +01007286#ifdef FEAT_FLOAT
Bram Moolenaar06b0b4b2019-11-25 15:40:55 +01007287/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 * "str2float()" function
7289 */
7290 static void
7291f_str2float(typval_T *argvars, typval_T *rettv)
7292{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007293 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007294 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007295
Bram Moolenaar08243d22017-01-10 16:12:29 +01007296 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007297 p = skipwhite(p + 1);
7298 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007299 if (isneg)
7300 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007301 rettv->v_type = VAR_FLOAT;
7302}
7303#endif
7304
7305/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007306 * "str2list()" function
7307 */
7308 static void
7309f_str2list(typval_T *argvars, typval_T *rettv)
7310{
7311 char_u *p;
7312 int utf8 = FALSE;
7313
7314 if (rettv_list_alloc(rettv) == FAIL)
7315 return;
7316
7317 if (argvars[1].v_type != VAR_UNKNOWN)
7318 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7319
7320 p = tv_get_string(&argvars[0]);
7321
7322 if (has_mbyte || utf8)
7323 {
7324 int (*ptr2len)(char_u *);
7325 int (*ptr2char)(char_u *);
7326
7327 if (utf8 || enc_utf8)
7328 {
7329 ptr2len = utf_ptr2len;
7330 ptr2char = utf_ptr2char;
7331 }
7332 else
7333 {
7334 ptr2len = mb_ptr2len;
7335 ptr2char = mb_ptr2char;
7336 }
7337
7338 for ( ; *p != NUL; p += (*ptr2len)(p))
7339 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7340 }
7341 else
7342 for ( ; *p != NUL; ++p)
7343 list_append_number(rettv->vval.v_list, *p);
7344}
7345
7346/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007347 * "str2nr()" function
7348 */
7349 static void
7350f_str2nr(typval_T *argvars, typval_T *rettv)
7351{
7352 int base = 10;
7353 char_u *p;
7354 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007355 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007356 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007357
7358 if (argvars[1].v_type != VAR_UNKNOWN)
7359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007360 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007361 if (base != 2 && base != 8 && base != 10 && base != 16)
7362 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007363 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007364 return;
7365 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007366 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7367 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368 }
7369
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007370 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007371 isneg = (*p == '-');
7372 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007373 p = skipwhite(p + 1);
7374 switch (base)
7375 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007376 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7377 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7378 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007379 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007380 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7381 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007382 if (isneg)
7383 rettv->vval.v_number = -n;
7384 else
7385 rettv->vval.v_number = n;
7386
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387}
7388
7389#ifdef HAVE_STRFTIME
7390/*
7391 * "strftime({format}[, {time}])" function
7392 */
7393 static void
7394f_strftime(typval_T *argvars, typval_T *rettv)
7395{
7396 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007397 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398 struct tm *curtime;
7399 time_t seconds;
7400 char_u *p;
7401
7402 rettv->v_type = VAR_STRING;
7403
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007404 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405 if (argvars[1].v_type == VAR_UNKNOWN)
7406 seconds = time(NULL);
7407 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007408 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007409 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007410 // MSVC returns NULL for an invalid value of seconds.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007411 if (curtime == NULL)
7412 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7413 else
7414 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007415 vimconv_T conv;
7416 char_u *enc;
7417
7418 conv.vc_type = CONV_NONE;
7419 enc = enc_locale();
7420 convert_setup(&conv, p_enc, enc);
7421 if (conv.vc_type != CONV_NONE)
7422 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423 if (p != NULL)
7424 (void)strftime((char *)result_buf, sizeof(result_buf),
7425 (char *)p, curtime);
7426 else
7427 result_buf[0] = NUL;
7428
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007429 if (conv.vc_type != CONV_NONE)
7430 vim_free(p);
7431 convert_setup(&conv, enc, p_enc);
7432 if (conv.vc_type != CONV_NONE)
7433 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7434 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007435 rettv->vval.v_string = vim_strsave(result_buf);
7436
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007437 // Release conversion descriptors
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007438 convert_setup(&conv, NULL, NULL);
7439 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 }
7441}
7442#endif
7443
7444/*
7445 * "strgetchar()" function
7446 */
7447 static void
7448f_strgetchar(typval_T *argvars, typval_T *rettv)
7449{
7450 char_u *str;
7451 int len;
7452 int error = FALSE;
7453 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007454 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007455
7456 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007457 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007458 if (str == NULL)
7459 return;
7460 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007461 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007462 if (error)
7463 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007464
Bram Moolenaar13505972019-01-24 15:04:48 +01007465 while (charidx >= 0 && byteidx < len)
7466 {
7467 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007468 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007469 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7470 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007472 --charidx;
7473 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007474 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007475}
7476
7477/*
7478 * "stridx()" function
7479 */
7480 static void
7481f_stridx(typval_T *argvars, typval_T *rettv)
7482{
7483 char_u buf[NUMBUFLEN];
7484 char_u *needle;
7485 char_u *haystack;
7486 char_u *save_haystack;
7487 char_u *pos;
7488 int start_idx;
7489
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007490 needle = tv_get_string_chk(&argvars[1]);
7491 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007492 rettv->vval.v_number = -1;
7493 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007494 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495
7496 if (argvars[2].v_type != VAR_UNKNOWN)
7497 {
7498 int error = FALSE;
7499
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007500 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007501 if (error || start_idx >= (int)STRLEN(haystack))
7502 return;
7503 if (start_idx >= 0)
7504 haystack += start_idx;
7505 }
7506
7507 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7508 if (pos != NULL)
7509 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7510}
7511
7512/*
7513 * "string()" function
7514 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007515 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007516f_string(typval_T *argvars, typval_T *rettv)
7517{
7518 char_u *tofree;
7519 char_u numbuf[NUMBUFLEN];
7520
7521 rettv->v_type = VAR_STRING;
7522 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7523 get_copyID());
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007524 // Make a copy if we have a value but it's not in allocated memory.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007525 if (rettv->vval.v_string != NULL && tofree == NULL)
7526 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7527}
7528
7529/*
7530 * "strlen()" function
7531 */
7532 static void
7533f_strlen(typval_T *argvars, typval_T *rettv)
7534{
7535 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007536 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537}
7538
7539/*
7540 * "strchars()" function
7541 */
7542 static void
7543f_strchars(typval_T *argvars, typval_T *rettv)
7544{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007545 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007547 varnumber_T len = 0;
7548 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007549
7550 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007551 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007552 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007553 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554 else
7555 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007556 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7557 while (*s != NUL)
7558 {
7559 func_mb_ptr2char_adv(&s);
7560 ++len;
7561 }
7562 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007563 }
7564}
7565
7566/*
7567 * "strdisplaywidth()" function
7568 */
7569 static void
7570f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7571{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007572 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007573 int col = 0;
7574
7575 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577
7578 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7579}
7580
7581/*
7582 * "strwidth()" function
7583 */
7584 static void
7585f_strwidth(typval_T *argvars, typval_T *rettv)
7586{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007587 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588
Bram Moolenaar13505972019-01-24 15:04:48 +01007589 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007590}
7591
7592/*
7593 * "strcharpart()" function
7594 */
7595 static void
7596f_strcharpart(typval_T *argvars, typval_T *rettv)
7597{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007598 char_u *p;
7599 int nchar;
7600 int nbyte = 0;
7601 int charlen;
7602 int len = 0;
7603 int slen;
7604 int error = FALSE;
7605
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007606 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007607 slen = (int)STRLEN(p);
7608
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007609 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 if (!error)
7611 {
7612 if (nchar > 0)
7613 while (nchar > 0 && nbyte < slen)
7614 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007615 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007616 --nchar;
7617 }
7618 else
7619 nbyte = nchar;
7620 if (argvars[2].v_type != VAR_UNKNOWN)
7621 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007622 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007623 while (charlen > 0 && nbyte + len < slen)
7624 {
7625 int off = nbyte + len;
7626
7627 if (off < 0)
7628 len += 1;
7629 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007630 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007631 --charlen;
7632 }
7633 }
7634 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007635 len = slen - nbyte; // default: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007636 }
7637
7638 /*
7639 * Only return the overlap between the specified part and the actual
7640 * string.
7641 */
7642 if (nbyte < 0)
7643 {
7644 len += nbyte;
7645 nbyte = 0;
7646 }
7647 else if (nbyte > slen)
7648 nbyte = slen;
7649 if (len < 0)
7650 len = 0;
7651 else if (nbyte + len > slen)
7652 len = slen - nbyte;
7653
7654 rettv->v_type = VAR_STRING;
7655 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007656}
7657
7658/*
7659 * "strpart()" function
7660 */
7661 static void
7662f_strpart(typval_T *argvars, typval_T *rettv)
7663{
7664 char_u *p;
7665 int n;
7666 int len;
7667 int slen;
7668 int error = FALSE;
7669
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007670 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007671 slen = (int)STRLEN(p);
7672
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007673 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007674 if (error)
7675 len = 0;
7676 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007677 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007679 len = slen - n; // default len: all bytes that are available.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007680
7681 /*
7682 * Only return the overlap between the specified part and the actual
7683 * string.
7684 */
7685 if (n < 0)
7686 {
7687 len += n;
7688 n = 0;
7689 }
7690 else if (n > slen)
7691 n = slen;
7692 if (len < 0)
7693 len = 0;
7694 else if (n + len > slen)
7695 len = slen - n;
7696
7697 rettv->v_type = VAR_STRING;
7698 rettv->vval.v_string = vim_strnsave(p + n, len);
7699}
7700
Bram Moolenaar10455d42019-11-21 15:36:18 +01007701#ifdef HAVE_STRPTIME
7702/*
7703 * "strptime({format}, {timestring})" function
7704 */
7705 static void
7706f_strptime(typval_T *argvars, typval_T *rettv)
7707{
7708 struct tm tmval;
7709 char_u *fmt;
7710 char_u *str;
7711 vimconv_T conv;
7712 char_u *enc;
7713
7714 vim_memset(&tmval, NUL, sizeof(tmval));
7715 fmt = tv_get_string(&argvars[0]);
7716 str = tv_get_string(&argvars[1]);
7717
7718 conv.vc_type = CONV_NONE;
7719 enc = enc_locale();
7720 convert_setup(&conv, p_enc, enc);
7721 if (conv.vc_type != CONV_NONE)
7722 fmt = string_convert(&conv, fmt, NULL);
7723 if (fmt == NULL
7724 || strptime((char *)str, (char *)fmt, &tmval) == NULL
7725 || (rettv->vval.v_number = mktime(&tmval)) == -1)
7726 rettv->vval.v_number = 0;
7727
7728 if (conv.vc_type != CONV_NONE)
7729 vim_free(fmt);
7730 convert_setup(&conv, NULL, NULL);
7731 vim_free(enc);
7732}
7733#endif
7734
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007735/*
7736 * "strridx()" function
7737 */
7738 static void
7739f_strridx(typval_T *argvars, typval_T *rettv)
7740{
7741 char_u buf[NUMBUFLEN];
7742 char_u *needle;
7743 char_u *haystack;
7744 char_u *rest;
7745 char_u *lastmatch = NULL;
7746 int haystack_len, end_idx;
7747
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007748 needle = tv_get_string_chk(&argvars[1]);
7749 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750
7751 rettv->vval.v_number = -1;
7752 if (needle == NULL || haystack == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007753 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007754
7755 haystack_len = (int)STRLEN(haystack);
7756 if (argvars[2].v_type != VAR_UNKNOWN)
7757 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007758 // Third argument: upper limit for index
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007759 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007760 if (end_idx < 0)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007761 return; // can never find a match
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007762 }
7763 else
7764 end_idx = haystack_len;
7765
7766 if (*needle == NUL)
7767 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007768 // Empty string matches past the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007769 lastmatch = haystack + end_idx;
7770 }
7771 else
7772 {
7773 for (rest = haystack; *rest != '\0'; ++rest)
7774 {
7775 rest = (char_u *)strstr((char *)rest, (char *)needle);
7776 if (rest == NULL || rest > haystack + end_idx)
7777 break;
7778 lastmatch = rest;
7779 }
7780 }
7781
7782 if (lastmatch == NULL)
7783 rettv->vval.v_number = -1;
7784 else
7785 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7786}
7787
7788/*
7789 * "strtrans()" function
7790 */
7791 static void
7792f_strtrans(typval_T *argvars, typval_T *rettv)
7793{
7794 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007795 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007796}
7797
7798/*
7799 * "submatch()" function
7800 */
7801 static void
7802f_submatch(typval_T *argvars, typval_T *rettv)
7803{
7804 int error = FALSE;
7805 int no;
7806 int retList = 0;
7807
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007808 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007809 if (error)
7810 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007811 if (no < 0 || no >= NSUBEXP)
7812 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007813 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007814 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007815 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007816 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007817 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007818 if (error)
7819 return;
7820
7821 if (retList == 0)
7822 {
7823 rettv->v_type = VAR_STRING;
7824 rettv->vval.v_string = reg_submatch(no);
7825 }
7826 else
7827 {
7828 rettv->v_type = VAR_LIST;
7829 rettv->vval.v_list = reg_submatch_list(no);
7830 }
7831}
7832
7833/*
7834 * "substitute()" function
7835 */
7836 static void
7837f_substitute(typval_T *argvars, typval_T *rettv)
7838{
7839 char_u patbuf[NUMBUFLEN];
7840 char_u subbuf[NUMBUFLEN];
7841 char_u flagsbuf[NUMBUFLEN];
7842
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007843 char_u *str = tv_get_string_chk(&argvars[0]);
7844 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007845 char_u *sub = NULL;
7846 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007847 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007849 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7850 expr = &argvars[2];
7851 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007852 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007853
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007855 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7856 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007857 rettv->vval.v_string = NULL;
7858 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007859 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007860}
7861
7862/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007863 * "swapinfo(swap_filename)" function
7864 */
7865 static void
7866f_swapinfo(typval_T *argvars, typval_T *rettv)
7867{
7868 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007869 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007870}
7871
7872/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007873 * "swapname(expr)" function
7874 */
7875 static void
7876f_swapname(typval_T *argvars, typval_T *rettv)
7877{
7878 buf_T *buf;
7879
7880 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007881 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007882 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7883 || buf->b_ml.ml_mfp->mf_fname == NULL)
7884 rettv->vval.v_string = NULL;
7885 else
7886 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7887}
7888
7889/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 * "synID(lnum, col, trans)" function
7891 */
7892 static void
7893f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7894{
7895 int id = 0;
7896#ifdef FEAT_SYN_HL
7897 linenr_T lnum;
7898 colnr_T col;
7899 int trans;
7900 int transerr = FALSE;
7901
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007902 lnum = tv_get_lnum(argvars); // -1 on type error
7903 col = (linenr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007904 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007905
7906 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7907 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7908 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7909#endif
7910
7911 rettv->vval.v_number = id;
7912}
7913
7914/*
7915 * "synIDattr(id, what [, mode])" function
7916 */
7917 static void
7918f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7919{
7920 char_u *p = NULL;
7921#ifdef FEAT_SYN_HL
7922 int id;
7923 char_u *what;
7924 char_u *mode;
7925 char_u modebuf[NUMBUFLEN];
7926 int modec;
7927
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007928 id = (int)tv_get_number(&argvars[0]);
7929 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007930 if (argvars[2].v_type != VAR_UNKNOWN)
7931 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007932 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007933 modec = TOLOWER_ASC(mode[0]);
7934 if (modec != 't' && modec != 'c' && modec != 'g')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007935 modec = 0; // replace invalid with current
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936 }
7937 else
7938 {
7939#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7940 if (USE_24BIT)
7941 modec = 'g';
7942 else
7943#endif
7944 if (t_colors > 1)
7945 modec = 'c';
7946 else
7947 modec = 't';
7948 }
7949
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950 switch (TOLOWER_ASC(what[0]))
7951 {
7952 case 'b':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007953 if (TOLOWER_ASC(what[1]) == 'g') // bg[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007954 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007955 else // bold
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007956 p = highlight_has_attr(id, HL_BOLD, modec);
7957 break;
7958
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007959 case 'f': // fg[#] or font
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960 p = highlight_color(id, what, modec);
7961 break;
7962
7963 case 'i':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007964 if (TOLOWER_ASC(what[1]) == 'n') // inverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007965 p = highlight_has_attr(id, HL_INVERSE, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007966 else // italic
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007967 p = highlight_has_attr(id, HL_ITALIC, modec);
7968 break;
7969
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007970 case 'n': // name
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007971 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007972 break;
7973
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007974 case 'r': // reverse
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007975 p = highlight_has_attr(id, HL_INVERSE, modec);
7976 break;
7977
7978 case 's':
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007979 if (TOLOWER_ASC(what[1]) == 'p') // sp[#]
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007980 p = highlight_color(id, what, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007981 // strikeout
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007982 else if (TOLOWER_ASC(what[1]) == 't' &&
7983 TOLOWER_ASC(what[2]) == 'r')
7984 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007985 else // standout
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007986 p = highlight_has_attr(id, HL_STANDOUT, modec);
7987 break;
7988
7989 case 'u':
7990 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007991 // underline
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7993 else
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01007994 // undercurl
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7996 break;
7997 }
7998
7999 if (p != NULL)
8000 p = vim_strsave(p);
8001#endif
8002 rettv->v_type = VAR_STRING;
8003 rettv->vval.v_string = p;
8004}
8005
8006/*
8007 * "synIDtrans(id)" function
8008 */
8009 static void
8010f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
8011{
8012 int id;
8013
8014#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008015 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008016
8017 if (id > 0)
8018 id = syn_get_final_id(id);
8019 else
8020#endif
8021 id = 0;
8022
8023 rettv->vval.v_number = id;
8024}
8025
8026/*
8027 * "synconcealed(lnum, col)" function
8028 */
8029 static void
8030f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
8031{
8032#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
8033 linenr_T lnum;
8034 colnr_T col;
8035 int syntax_flags = 0;
8036 int cchar;
8037 int matchid = 0;
8038 char_u str[NUMBUFLEN];
8039#endif
8040
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008041 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042
8043#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008044 lnum = tv_get_lnum(argvars); // -1 on type error
8045 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008046
8047 vim_memset(str, NUL, sizeof(str));
8048
8049 if (rettv_list_alloc(rettv) != FAIL)
8050 {
8051 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8052 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8053 && curwin->w_p_cole > 0)
8054 {
8055 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
8056 syntax_flags = get_syntax_info(&matchid);
8057
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008058 // get the conceal character
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008059 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
8060 {
8061 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02008062 if (cchar == NUL && curwin->w_p_cole == 1)
8063 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008064 if (cchar != NUL)
8065 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066 if (has_mbyte)
8067 (*mb_char2bytes)(cchar, str);
8068 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069 str[0] = cchar;
8070 }
8071 }
8072 }
8073
8074 list_append_number(rettv->vval.v_list,
8075 (syntax_flags & HL_CONCEAL) != 0);
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008076 // -1 to auto-determine strlen
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008077 list_append_string(rettv->vval.v_list, str, -1);
8078 list_append_number(rettv->vval.v_list, matchid);
8079 }
8080#endif
8081}
8082
8083/*
8084 * "synstack(lnum, col)" function
8085 */
8086 static void
8087f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
8088{
8089#ifdef FEAT_SYN_HL
8090 linenr_T lnum;
8091 colnr_T col;
8092 int i;
8093 int id;
8094#endif
8095
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008096 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008097
8098#ifdef FEAT_SYN_HL
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008099 lnum = tv_get_lnum(argvars); // -1 on type error
8100 col = (colnr_T)tv_get_number(&argvars[1]) - 1; // -1 on type error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008101
8102 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
8103 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
8104 && rettv_list_alloc(rettv) != FAIL)
8105 {
8106 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
8107 for (i = 0; ; ++i)
8108 {
8109 id = syn_get_stack_item(i);
8110 if (id < 0)
8111 break;
8112 if (list_append_number(rettv->vval.v_list, id) == FAIL)
8113 break;
8114 }
8115 }
8116#endif
8117}
8118
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119/*
8120 * "tabpagebuflist()" function
8121 */
8122 static void
8123f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8124{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008125 tabpage_T *tp;
8126 win_T *wp = NULL;
8127
8128 if (argvars[0].v_type == VAR_UNKNOWN)
8129 wp = firstwin;
8130 else
8131 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008132 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133 if (tp != NULL)
8134 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
8135 }
8136 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
8137 {
8138 for (; wp != NULL; wp = wp->w_next)
8139 if (list_append_number(rettv->vval.v_list,
8140 wp->w_buffer->b_fnum) == FAIL)
8141 break;
8142 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008143}
8144
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008145/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146 * "tagfiles()" function
8147 */
8148 static void
8149f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
8150{
8151 char_u *fname;
8152 tagname_T tn;
8153 int first;
8154
8155 if (rettv_list_alloc(rettv) == FAIL)
8156 return;
8157 fname = alloc(MAXPATHL);
8158 if (fname == NULL)
8159 return;
8160
8161 for (first = TRUE; ; first = FALSE)
8162 if (get_tagfname(&tn, first, fname) == FAIL
8163 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
8164 break;
8165 tagname_free(&tn);
8166 vim_free(fname);
8167}
8168
8169/*
8170 * "taglist()" function
8171 */
8172 static void
8173f_taglist(typval_T *argvars, typval_T *rettv)
8174{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008175 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 char_u *tag_pattern;
8177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008178 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179
8180 rettv->vval.v_number = FALSE;
8181 if (*tag_pattern == NUL)
8182 return;
8183
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008184 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008185 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008186 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008187 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188}
8189
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190#ifdef FEAT_FLOAT
8191/*
8192 * "tan()" function
8193 */
8194 static void
8195f_tan(typval_T *argvars, typval_T *rettv)
8196{
8197 float_T f = 0.0;
8198
8199 rettv->v_type = VAR_FLOAT;
8200 if (get_float_arg(argvars, &f) == OK)
8201 rettv->vval.v_float = tan(f);
8202 else
8203 rettv->vval.v_float = 0.0;
8204}
8205
8206/*
8207 * "tanh()" function
8208 */
8209 static void
8210f_tanh(typval_T *argvars, typval_T *rettv)
8211{
8212 float_T f = 0.0;
8213
8214 rettv->v_type = VAR_FLOAT;
8215 if (get_float_arg(argvars, &f) == OK)
8216 rettv->vval.v_float = tanh(f);
8217 else
8218 rettv->vval.v_float = 0.0;
8219}
8220#endif
8221
8222/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008223 * "tolower(string)" function
8224 */
8225 static void
8226f_tolower(typval_T *argvars, typval_T *rettv)
8227{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008228 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008229 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008230}
8231
8232/*
8233 * "toupper(string)" function
8234 */
8235 static void
8236f_toupper(typval_T *argvars, typval_T *rettv)
8237{
8238 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008239 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008240}
8241
8242/*
8243 * "tr(string, fromstr, tostr)" function
8244 */
8245 static void
8246f_tr(typval_T *argvars, typval_T *rettv)
8247{
8248 char_u *in_str;
8249 char_u *fromstr;
8250 char_u *tostr;
8251 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008252 int inlen;
8253 int fromlen;
8254 int tolen;
8255 int idx;
8256 char_u *cpstr;
8257 int cplen;
8258 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008259 char_u buf[NUMBUFLEN];
8260 char_u buf2[NUMBUFLEN];
8261 garray_T ga;
8262
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008263 in_str = tv_get_string(&argvars[0]);
8264 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8265 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008266
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008267 // Default return value: empty string.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008268 rettv->v_type = VAR_STRING;
8269 rettv->vval.v_string = NULL;
8270 if (fromstr == NULL || tostr == NULL)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008271 return; // type error; errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008272 ga_init2(&ga, (int)sizeof(char), 80);
8273
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008274 if (!has_mbyte)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008275 // not multi-byte: fromstr and tostr must be the same length
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008276 if (STRLEN(fromstr) != STRLEN(tostr))
8277 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008278error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008279 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008280 ga_clear(&ga);
8281 return;
8282 }
8283
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008284 // fromstr and tostr have to contain the same number of chars
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008285 while (*in_str != NUL)
8286 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008287 if (has_mbyte)
8288 {
8289 inlen = (*mb_ptr2len)(in_str);
8290 cpstr = in_str;
8291 cplen = inlen;
8292 idx = 0;
8293 for (p = fromstr; *p != NUL; p += fromlen)
8294 {
8295 fromlen = (*mb_ptr2len)(p);
8296 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8297 {
8298 for (p = tostr; *p != NUL; p += tolen)
8299 {
8300 tolen = (*mb_ptr2len)(p);
8301 if (idx-- == 0)
8302 {
8303 cplen = tolen;
8304 cpstr = p;
8305 break;
8306 }
8307 }
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008308 if (*p == NUL) // tostr is shorter than fromstr
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008309 goto error;
8310 break;
8311 }
8312 ++idx;
8313 }
8314
8315 if (first && cpstr == in_str)
8316 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008317 // Check that fromstr and tostr have the same number of
8318 // (multi-byte) characters. Done only once when a character
8319 // of in_str doesn't appear in fromstr.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008320 first = FALSE;
8321 for (p = tostr; *p != NUL; p += tolen)
8322 {
8323 tolen = (*mb_ptr2len)(p);
8324 --idx;
8325 }
8326 if (idx != 0)
8327 goto error;
8328 }
8329
8330 (void)ga_grow(&ga, cplen);
8331 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8332 ga.ga_len += cplen;
8333
8334 in_str += inlen;
8335 }
8336 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008337 {
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008338 // When not using multi-byte chars we can do it faster.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339 p = vim_strchr(fromstr, *in_str);
8340 if (p != NULL)
8341 ga_append(&ga, tostr[p - fromstr]);
8342 else
8343 ga_append(&ga, *in_str);
8344 ++in_str;
8345 }
8346 }
8347
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008348 // add a terminating NUL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008349 (void)ga_grow(&ga, 1);
8350 ga_append(&ga, NUL);
8351
8352 rettv->vval.v_string = ga.ga_data;
8353}
8354
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008355/*
8356 * "trim({expr})" function
8357 */
8358 static void
8359f_trim(typval_T *argvars, typval_T *rettv)
8360{
8361 char_u buf1[NUMBUFLEN];
8362 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008363 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008364 char_u *mask = NULL;
8365 char_u *tail;
8366 char_u *prev;
8367 char_u *p;
8368 int c1;
8369
8370 rettv->v_type = VAR_STRING;
8371 if (head == NULL)
8372 {
8373 rettv->vval.v_string = NULL;
8374 return;
8375 }
8376
8377 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008378 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008379
8380 while (*head != NUL)
8381 {
8382 c1 = PTR2CHAR(head);
8383 if (mask == NULL)
8384 {
8385 if (c1 > ' ' && c1 != 0xa0)
8386 break;
8387 }
8388 else
8389 {
8390 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8391 if (c1 == PTR2CHAR(p))
8392 break;
8393 if (*p == NUL)
8394 break;
8395 }
8396 MB_PTR_ADV(head);
8397 }
8398
8399 for (tail = head + STRLEN(head); tail > head; tail = prev)
8400 {
8401 prev = tail;
8402 MB_PTR_BACK(head, prev);
8403 c1 = PTR2CHAR(prev);
8404 if (mask == NULL)
8405 {
8406 if (c1 > ' ' && c1 != 0xa0)
8407 break;
8408 }
8409 else
8410 {
8411 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8412 if (c1 == PTR2CHAR(p))
8413 break;
8414 if (*p == NUL)
8415 break;
8416 }
8417 }
8418 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8419}
8420
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008421#ifdef FEAT_FLOAT
8422/*
8423 * "trunc({float})" function
8424 */
8425 static void
8426f_trunc(typval_T *argvars, typval_T *rettv)
8427{
8428 float_T f = 0.0;
8429
8430 rettv->v_type = VAR_FLOAT;
8431 if (get_float_arg(argvars, &f) == OK)
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008432 // trunc() is not in C90, use floor() or ceil() instead.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008433 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8434 else
8435 rettv->vval.v_float = 0.0;
8436}
8437#endif
8438
8439/*
8440 * "type(expr)" function
8441 */
8442 static void
8443f_type(typval_T *argvars, typval_T *rettv)
8444{
8445 int n = -1;
8446
8447 switch (argvars[0].v_type)
8448 {
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008449 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8450 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008451 case VAR_PARTIAL:
Bram Moolenaar9b4a15d2020-01-11 16:05:23 +01008452 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8453 case VAR_LIST: n = VAR_TYPE_LIST; break;
8454 case VAR_DICT: n = VAR_TYPE_DICT; break;
8455 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
8456 case VAR_BOOL: n = VAR_TYPE_BOOL; break;
8457 case VAR_SPECIAL: n = VAR_TYPE_NONE; break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008458 case VAR_JOB: n = VAR_TYPE_JOB; break;
8459 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008460 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008461 case VAR_UNKNOWN:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008462 case VAR_VOID:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008463 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008464 n = -1;
8465 break;
8466 }
8467 rettv->vval.v_number = n;
8468}
8469
8470/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008471 * "virtcol(string)" function
8472 */
8473 static void
8474f_virtcol(typval_T *argvars, typval_T *rettv)
8475{
8476 colnr_T vcol = 0;
8477 pos_T *fp;
8478 int fnum = curbuf->b_fnum;
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008479 int len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480
8481 fp = var2fpos(&argvars[0], FALSE, &fnum);
8482 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8483 && fnum == curbuf->b_fnum)
8484 {
Bram Moolenaarb3d33d82020-01-15 20:36:55 +01008485 // Limit the column to a valid value, getvvcol() doesn't check.
8486 if (fp->col < 0)
8487 fp->col = 0;
8488 else
8489 {
8490 len = (int)STRLEN(ml_get(fp->lnum));
8491 if (fp->col > len)
8492 fp->col = len;
8493 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008494 getvvcol(curwin, fp, NULL, NULL, &vcol);
8495 ++vcol;
8496 }
8497
8498 rettv->vval.v_number = vcol;
8499}
8500
8501/*
8502 * "visualmode()" function
8503 */
8504 static void
8505f_visualmode(typval_T *argvars, typval_T *rettv)
8506{
8507 char_u str[2];
8508
8509 rettv->v_type = VAR_STRING;
8510 str[0] = curbuf->b_visual_mode_eval;
8511 str[1] = NUL;
8512 rettv->vval.v_string = vim_strsave(str);
8513
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008514 // A non-zero number or non-empty string argument: reset mode.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008515 if (non_zero_arg(&argvars[0]))
8516 curbuf->b_visual_mode_eval = NUL;
8517}
8518
8519/*
8520 * "wildmenumode()" function
8521 */
8522 static void
8523f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8524{
8525#ifdef FEAT_WILDMENU
8526 if (wild_menu_showing)
8527 rettv->vval.v_number = 1;
8528#endif
8529}
8530
8531/*
Bram Moolenaar0c1e3742019-12-27 13:49:24 +01008532 * "windowsversion()" function
8533 */
8534 static void
8535f_windowsversion(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8536{
8537 rettv->v_type = VAR_STRING;
8538 rettv->vval.v_string = vim_strsave((char_u *)windowsVersion);
8539}
8540
8541/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008542 * "wordcount()" function
8543 */
8544 static void
8545f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8546{
8547 if (rettv_dict_alloc(rettv) == FAIL)
8548 return;
8549 cursor_pos_info(rettv->vval.v_dict);
8550}
8551
8552/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008553 * "xor(expr, expr)" function
8554 */
8555 static void
8556f_xor(typval_T *argvars, typval_T *rettv)
8557{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008558 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8559 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008560}
8561
Bram Moolenaar5d18efe2019-12-01 21:11:22 +01008562#endif // FEAT_EVAL