blob: 945c5f227f213e1336f753ba55048deaae54a79b [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 Moolenaard0573012017-10-28 21:11:06 +020023#ifdef MACOS_X
Bram Moolenaar8d71b542019-08-30 15:46:30 +020024# include <time.h> // for time_t
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020025#endif
26
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027#ifdef FEAT_FLOAT
28static void f_abs(typval_T *argvars, typval_T *rettv);
29static void f_acos(typval_T *argvars, typval_T *rettv);
30#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020031static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020032#ifdef FEAT_FLOAT
33static void f_asin(typval_T *argvars, typval_T *rettv);
34static void f_atan(typval_T *argvars, typval_T *rettv);
35static void f_atan2(typval_T *argvars, typval_T *rettv);
36#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010037#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020038static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010039static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010040# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010041static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_byte2line(typval_T *argvars, typval_T *rettv);
45static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
46static void f_byteidx(typval_T *argvars, typval_T *rettv);
47static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
48static void f_call(typval_T *argvars, typval_T *rettv);
49#ifdef FEAT_FLOAT
50static void f_ceil(typval_T *argvars, typval_T *rettv);
51#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_changenr(typval_T *argvars, typval_T *rettv);
53static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_confirm(typval_T *argvars, typval_T *rettv);
56static void f_copy(typval_T *argvars, typval_T *rettv);
57#ifdef FEAT_FLOAT
58static void f_cos(typval_T *argvars, typval_T *rettv);
59static void f_cosh(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010062#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020063static void f_debugbreak(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020065static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020068static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_escape(typval_T *argvars, typval_T *rettv);
70static void f_eval(typval_T *argvars, typval_T *rettv);
71static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_exists(typval_T *argvars, typval_T *rettv);
74#ifdef FEAT_FLOAT
75static void f_exp(typval_T *argvars, typval_T *rettv);
76#endif
77static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020078static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020079static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080#ifdef FEAT_FLOAT
81static void f_float2nr(typval_T *argvars, typval_T *rettv);
82static void f_floor(typval_T *argvars, typval_T *rettv);
83static void f_fmod(typval_T *argvars, typval_T *rettv);
84#endif
85static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020086static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020087static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020088static void f_function(typval_T *argvars, typval_T *rettv);
89static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
90static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010091static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020094static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020095static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010096static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020097static void f_getpid(typval_T *argvars, typval_T *rettv);
98static void f_getcurpos(typval_T *argvars, typval_T *rettv);
99static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_getreg(typval_T *argvars, typval_T *rettv);
101static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100102static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
105static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200106static void f_hlID(typval_T *argvars, typval_T *rettv);
107static void f_hlexists(typval_T *argvars, typval_T *rettv);
108static void f_hostname(typval_T *argvars, typval_T *rettv);
109static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200110static void f_index(typval_T *argvars, typval_T *rettv);
111static void f_input(typval_T *argvars, typval_T *rettv);
112static void f_inputdialog(typval_T *argvars, typval_T *rettv);
113static void f_inputlist(typval_T *argvars, typval_T *rettv);
114static void f_inputrestore(typval_T *argvars, typval_T *rettv);
115static void f_inputsave(typval_T *argvars, typval_T *rettv);
116static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram 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 Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200172static void f_reg_executing(typval_T *argvars, typval_T *rettv);
173static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200174static void f_reltime(typval_T *argvars, typval_T *rettv);
175#ifdef FEAT_FLOAT
176static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
177#endif
178static void f_reltimestr(typval_T *argvars, typval_T *rettv);
179static void f_remote_expr(typval_T *argvars, typval_T *rettv);
180static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
181static void f_remote_peek(typval_T *argvars, typval_T *rettv);
182static void f_remote_read(typval_T *argvars, typval_T *rettv);
183static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100184static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_rename(typval_T *argvars, typval_T *rettv);
186static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187#ifdef FEAT_FLOAT
188static void f_round(typval_T *argvars, typval_T *rettv);
189#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100190#ifdef FEAT_RUBY
191static void f_rubyeval(typval_T *argvars, typval_T *rettv);
192#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193static void f_screenattr(typval_T *argvars, typval_T *rettv);
194static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100195static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_screencol(typval_T *argvars, typval_T *rettv);
197static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100198static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200199static void f_search(typval_T *argvars, typval_T *rettv);
200static void f_searchdecl(typval_T *argvars, typval_T *rettv);
201static void f_searchpair(typval_T *argvars, typval_T *rettv);
202static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
203static void f_searchpos(typval_T *argvars, typval_T *rettv);
204static void f_server2client(typval_T *argvars, typval_T *rettv);
205static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200206static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200207static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200208static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200210static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100211static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200212#ifdef FEAT_CRYPT
213static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200214#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200215static void f_shellescape(typval_T *argvars, typval_T *rettv);
216static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200217#ifdef FEAT_FLOAT
218static void f_sin(typval_T *argvars, typval_T *rettv);
219static void f_sinh(typval_T *argvars, typval_T *rettv);
220#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_soundfold(typval_T *argvars, typval_T *rettv);
222static void f_spellbadword(typval_T *argvars, typval_T *rettv);
223static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
224static void f_split(typval_T *argvars, typval_T *rettv);
225#ifdef FEAT_FLOAT
226static void f_sqrt(typval_T *argvars, typval_T *rettv);
227static void f_str2float(typval_T *argvars, typval_T *rettv);
228#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200229static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200230static void f_str2nr(typval_T *argvars, typval_T *rettv);
231static void f_strchars(typval_T *argvars, typval_T *rettv);
232#ifdef HAVE_STRFTIME
233static void f_strftime(typval_T *argvars, typval_T *rettv);
234#endif
235static void f_strgetchar(typval_T *argvars, typval_T *rettv);
236static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200237static void f_strlen(typval_T *argvars, typval_T *rettv);
238static void f_strcharpart(typval_T *argvars, typval_T *rettv);
239static void f_strpart(typval_T *argvars, typval_T *rettv);
240static void f_strridx(typval_T *argvars, typval_T *rettv);
241static void f_strtrans(typval_T *argvars, typval_T *rettv);
242static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
243static void f_strwidth(typval_T *argvars, typval_T *rettv);
244static void f_submatch(typval_T *argvars, typval_T *rettv);
245static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200246static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200247static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248static void f_synID(typval_T *argvars, typval_T *rettv);
249static void f_synIDattr(typval_T *argvars, typval_T *rettv);
250static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
251static void f_synstack(typval_T *argvars, typval_T *rettv);
252static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200253static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200254static void f_taglist(typval_T *argvars, typval_T *rettv);
255static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256#ifdef FEAT_FLOAT
257static void f_tan(typval_T *argvars, typval_T *rettv);
258static void f_tanh(typval_T *argvars, typval_T *rettv);
259#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_tolower(typval_T *argvars, typval_T *rettv);
261static void f_toupper(typval_T *argvars, typval_T *rettv);
262static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100263static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264#ifdef FEAT_FLOAT
265static void f_trunc(typval_T *argvars, typval_T *rettv);
266#endif
267static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200268static void f_virtcol(typval_T *argvars, typval_T *rettv);
269static void f_visualmode(typval_T *argvars, typval_T *rettv);
270static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200271static void f_wordcount(typval_T *argvars, typval_T *rettv);
272static void f_xor(typval_T *argvars, typval_T *rettv);
273
274/*
275 * Array with names and number of arguments of all internal functions
276 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
277 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200278typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200279{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200280 char *f_name; // function name
281 char f_min_argc; // minimal number of arguments
282 char f_max_argc; // maximal number of arguments
283 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200284 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200285 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200286} funcentry_T;
287
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200288// values for f_argtype; zero means it cannot be used as a method
289#define FEARG_1 1 // base is the first argument
290#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200291#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200292#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200293#define FEARG_LAST 9 // base is the last argument
294
Bram Moolenaarac92e252019-08-03 21:58:38 +0200295static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200296{
297#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200298 {"abs", 1, 1, FEARG_1, f_abs},
299 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200300#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200301 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200302 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200303 {"append", 2, 2, FEARG_LAST, f_append},
304 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
305 {"argc", 0, 1, 0, f_argc},
306 {"argidx", 0, 0, 0, f_argidx},
307 {"arglistid", 0, 2, 0, f_arglistid},
308 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200309#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200310 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200311#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200312 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200313 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200314 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200315 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200316 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
317 {"assert_false", 1, 2, FEARG_1, f_assert_false},
318 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
319 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200320 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200321 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200322 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200323 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200324#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200325 {"atan", 1, 1, FEARG_1, f_atan},
326 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200327#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100328#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200329 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200330 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100331# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200332 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100333# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100334#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200335 {"browse", 4, 4, 0, f_browse},
336 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200337 {"bufadd", 1, 1, FEARG_1, f_bufadd},
338 {"bufexists", 1, 1, FEARG_1, f_bufexists},
339 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200340 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
341 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200342 {"buflisted", 1, 1, FEARG_1, f_buflisted},
343 {"bufload", 1, 1, FEARG_1, f_bufload},
344 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200345 {"bufname", 0, 1, FEARG_1, f_bufname},
346 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200347 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
348 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200349 {"byte2line", 1, 1, FEARG_1, f_byte2line},
350 {"byteidx", 2, 2, FEARG_1, f_byteidx},
351 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
352 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200354 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200355#endif
356#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200357 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
358 {"ch_close", 1, 1, FEARG_1, f_ch_close},
359 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
360 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
361 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
362 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
363 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
364 {"ch_info", 1, 1, FEARG_1, f_ch_info},
365 {"ch_log", 1, 2, FEARG_1, f_ch_log},
366 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
367 {"ch_open", 1, 2, FEARG_1, f_ch_open},
368 {"ch_read", 1, 2, FEARG_1, f_ch_read},
369 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
370 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
371 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
372 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
373 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
374 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200375#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200376 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200377 {"char2nr", 1, 2, FEARG_1, f_char2nr},
378 {"chdir", 1, 1, FEARG_1, f_chdir},
379 {"cindent", 1, 1, FEARG_1, f_cindent},
380 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
381 {"col", 1, 1, FEARG_1, f_col},
382 {"complete", 2, 2, FEARG_2, f_complete},
383 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200384 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200385 {"complete_info", 0, 1, FEARG_1, f_complete_info},
386 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200387 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200388#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200389 {"cos", 1, 1, FEARG_1, f_cos},
390 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200392 {"count", 2, 4, FEARG_1, f_count},
393 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200394 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100395#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200396 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200397#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200398 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
399 {"delete", 1, 2, FEARG_1, f_delete},
400 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200401 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200402 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
403 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200404 {"empty", 1, 1, FEARG_1, f_empty},
405 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200406 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200407 {"eval", 1, 1, FEARG_1, f_eval},
408 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200409 {"executable", 1, 1, FEARG_1, f_executable},
410 {"execute", 1, 2, FEARG_1, f_execute},
411 {"exepath", 1, 1, FEARG_1, f_exepath},
412 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200413#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200414 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200415#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200416 {"expand", 1, 3, FEARG_1, f_expand},
417 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200418 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200419 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
420 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
421 {"filereadable", 1, 1, FEARG_1, f_filereadable},
422 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200423 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200424 {"finddir", 1, 3, FEARG_1, f_finddir},
425 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200426#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200427 {"float2nr", 1, 1, FEARG_1, f_float2nr},
428 {"floor", 1, 1, FEARG_1, f_floor},
429 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200430#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200431 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
432 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
433 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
434 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
435 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200436 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200437 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200438 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200439 {"funcref", 1, 3, FEARG_1, f_funcref},
440 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200441 {"garbagecollect", 0, 1, 0, f_garbagecollect},
442 {"get", 2, 3, FEARG_1, f_get},
443 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200444 {"getbufline", 2, 3, FEARG_1, f_getbufline},
445 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
446 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200447 {"getchar", 0, 1, 0, f_getchar},
448 {"getcharmod", 0, 0, 0, f_getcharmod},
449 {"getcharsearch", 0, 0, 0, f_getcharsearch},
450 {"getcmdline", 0, 0, 0, f_getcmdline},
451 {"getcmdpos", 0, 0, 0, f_getcmdpos},
452 {"getcmdtype", 0, 0, 0, f_getcmdtype},
453 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200454 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200455 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200456 {"getcwd", 0, 2, FEARG_1, f_getcwd},
457 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200458 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200459 {"getfperm", 1, 1, FEARG_1, f_getfperm},
460 {"getfsize", 1, 1, FEARG_1, f_getfsize},
461 {"getftime", 1, 1, FEARG_1, f_getftime},
462 {"getftype", 1, 1, FEARG_1, f_getftype},
Bram Moolenaara3a12462019-09-07 15:08:38 +0200463 {"getimstatus", 0, 0, 0, f_getimstatus},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200464 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
465 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200466 {"getloclist", 1, 2, 0, f_getloclist},
467 {"getmatches", 0, 1, 0, f_getmatches},
Bram Moolenaardb3a2052019-11-16 18:22:41 +0100468 {"getmousepos", 0, 0, 0, f_getmousepos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200469 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200470 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200471 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200472 {"getreg", 0, 3, FEARG_1, f_getreg},
473 {"getregtype", 0, 1, FEARG_1, f_getregtype},
474 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
475 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
476 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200477 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
478 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
479 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200480 {"getwinposx", 0, 0, 0, f_getwinposx},
481 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200482 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
483 {"glob", 1, 4, FEARG_1, f_glob},
484 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
485 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200486 {"has", 1, 1, 0, f_has},
487 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200488 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
489 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
490 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
491 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
492 {"histadd", 2, 2, FEARG_2, f_histadd},
493 {"histdel", 1, 2, FEARG_1, f_histdel},
494 {"histget", 1, 2, FEARG_1, f_histget},
495 {"histnr", 1, 1, FEARG_1, f_histnr},
496 {"hlID", 1, 1, FEARG_1, f_hlID},
497 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200498 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200499 {"iconv", 3, 3, FEARG_1, f_iconv},
500 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200501 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200502 {"input", 1, 3, FEARG_1, f_input},
503 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
504 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200505 {"inputrestore", 0, 0, 0, f_inputrestore},
506 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200507 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200508 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200509 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200510 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200511#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200512 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200513#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200514 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200515#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200516 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200517#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200518 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200519#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200520 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
521 {"job_info", 0, 1, FEARG_1, f_job_info},
522 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
523 {"job_start", 1, 2, FEARG_1, f_job_start},
524 {"job_status", 1, 1, FEARG_1, f_job_status},
525 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200527 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200528 {"js_decode", 1, 1, FEARG_1, f_js_decode},
529 {"js_encode", 1, 1, FEARG_1, f_js_encode},
530 {"json_decode", 1, 1, FEARG_1, f_json_decode},
531 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200532 {"keys", 1, 1, FEARG_1, f_keys},
533 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
534 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200535 {"libcall", 3, 3, FEARG_3, f_libcall},
536 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200537 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200538 {"line2byte", 1, 1, FEARG_1, f_line2byte},
539 {"lispindent", 1, 1, FEARG_1, f_lispindent},
540 {"list2str", 1, 2, FEARG_1, f_list2str},
541 {"listener_add", 1, 2, FEARG_2, f_listener_add},
542 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
543 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200544 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200545#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200546 {"log", 1, 1, FEARG_1, f_log},
547 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200548#endif
549#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200550 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200551#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200552 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200553 {"maparg", 1, 4, FEARG_1, f_maparg},
554 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
555 {"match", 2, 4, FEARG_1, f_match},
556 {"matchadd", 2, 5, FEARG_1, f_matchadd},
557 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
558 {"matcharg", 1, 1, FEARG_1, f_matcharg},
559 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
560 {"matchend", 2, 4, FEARG_1, f_matchend},
561 {"matchlist", 2, 4, FEARG_1, f_matchlist},
562 {"matchstr", 2, 4, FEARG_1, f_matchstr},
563 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200564 {"max", 1, 1, FEARG_1, f_max},
565 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200566 {"mkdir", 1, 3, FEARG_1, f_mkdir},
567 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200568#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200569 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200570#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200571 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
572 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200573 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200574 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200575#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200576 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200577#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200578#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200579 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
580 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200581 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200582 {"popup_close", 1, 2, FEARG_1, f_popup_close},
583 {"popup_create", 2, 2, FEARG_1, f_popup_create},
584 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200585 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
586 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200587 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
588 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200589 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
590 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
591 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200592 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200593 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
594 {"popup_move", 2, 2, FEARG_1, f_popup_move},
595 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
596 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
597 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
598 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200600#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200601 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200602#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200603 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200604 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200605#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200606 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
607 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
608 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200609#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100610#ifdef FEAT_TEXT_PROP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200611 {"prop_add", 3, 3, FEARG_1, f_prop_add},
612 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
613 {"prop_list", 1, 2, FEARG_1, f_prop_list},
614 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
615 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
616 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
617 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
618 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
619 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100620#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200621 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200622 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200623#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200624 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625#endif
626#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200627 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200628#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100629#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200630 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100631#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200632 {"range", 1, 3, FEARG_1, f_range},
633 {"readdir", 1, 2, FEARG_1, f_readdir},
634 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200635 {"reg_executing", 0, 0, 0, f_reg_executing},
636 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200637 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200638#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200639 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200641 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
642 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
643 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
644 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
645 {"remote_read", 1, 2, FEARG_1, f_remote_read},
646 {"remote_send", 2, 3, FEARG_1, f_remote_send},
647 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200648 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200649 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200650 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200651 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200652 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200653#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200654 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100656#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200657 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100658#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200659 {"screenattr", 2, 2, FEARG_1, f_screenattr},
660 {"screenchar", 2, 2, FEARG_1, f_screenchar},
661 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200662 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200663 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200664 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200665 {"screenstring", 2, 2, FEARG_1, f_screenstring},
666 {"search", 1, 4, FEARG_1, f_search},
667 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200668 {"searchpair", 3, 7, 0, f_searchpair},
669 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200670 {"searchpos", 1, 4, FEARG_1, f_searchpos},
671 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200672 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200673 {"setbufline", 3, 3, FEARG_3, f_setbufline},
674 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
675 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
676 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
677 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200678 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200679 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200680 {"setloclist", 2, 4, FEARG_2, f_setloclist},
681 {"setmatches", 1, 2, FEARG_1, f_setmatches},
682 {"setpos", 2, 2, FEARG_2, f_setpos},
683 {"setqflist", 1, 3, FEARG_1, f_setqflist},
684 {"setreg", 2, 3, FEARG_2, f_setreg},
685 {"settabvar", 3, 3, FEARG_3, f_settabvar},
686 {"settabwinvar", 4, 4, FEARG_4, f_settabwinvar},
687 {"settagstack", 2, 3, FEARG_2, f_settagstack},
688 {"setwinvar", 3, 3, FEARG_3, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200689#ifdef FEAT_CRYPT
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200690 {"sha256", 1, 1, FEARG_1, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200691#endif
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200692 {"shellescape", 1, 2, FEARG_1, f_shellescape},
693 {"shiftwidth", 0, 1, FEARG_1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100694#ifdef FEAT_SIGNS
Bram Moolenaar93476fd2019-09-06 22:00:54 +0200695 {"sign_define", 1, 2, FEARG_1, f_sign_define},
696 {"sign_getdefined", 0, 1, FEARG_1, f_sign_getdefined},
697 {"sign_getplaced", 0, 2, FEARG_1, f_sign_getplaced},
698 {"sign_jump", 3, 3, FEARG_1, f_sign_jump},
699 {"sign_place", 4, 5, FEARG_1, f_sign_place},
700 {"sign_placelist", 1, 1, FEARG_1, f_sign_placelist},
701 {"sign_undefine", 0, 1, FEARG_1, f_sign_undefine},
702 {"sign_unplace", 1, 2, FEARG_1, f_sign_unplace},
703 {"sign_unplacelist", 1, 2, FEARG_1, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100704#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200705 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200706#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200707 {"sin", 1, 1, FEARG_1, f_sin},
708 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200709#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200710 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200711#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200712 {"sound_clear", 0, 0, 0, f_sound_clear},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200713 {"sound_playevent", 1, 2, FEARG_1, f_sound_playevent},
714 {"sound_playfile", 1, 2, FEARG_1, f_sound_playfile},
715 {"sound_stop", 1, 1, FEARG_1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200716#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200717 {"soundfold", 1, 1, FEARG_1, f_soundfold},
718 {"spellbadword", 0, 1, FEARG_1, f_spellbadword},
719 {"spellsuggest", 1, 3, FEARG_1, f_spellsuggest},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200720 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200721#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200722 {"sqrt", 1, 1, FEARG_1, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200723#endif
724 {"state", 0, 1, FEARG_1, f_state},
725#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200726 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200728 {"str2list", 1, 2, FEARG_1, f_str2list},
Bram Moolenaar60a8de22019-09-15 14:33:22 +0200729 {"str2nr", 1, 3, FEARG_1, f_str2nr},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200730 {"strcharpart", 2, 3, FEARG_1, f_strcharpart},
731 {"strchars", 1, 2, FEARG_1, f_strchars},
732 {"strdisplaywidth", 1, 2, FEARG_1, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200733#ifdef HAVE_STRFTIME
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200734 {"strftime", 1, 2, FEARG_1, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200735#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200736 {"strgetchar", 2, 2, FEARG_1, f_strgetchar},
737 {"stridx", 2, 3, FEARG_1, f_stridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200738 {"string", 1, 1, FEARG_1, f_string},
739 {"strlen", 1, 1, FEARG_1, f_strlen},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200740 {"strpart", 2, 3, FEARG_1, f_strpart},
741 {"strridx", 2, 3, FEARG_1, f_strridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200742 {"strtrans", 1, 1, FEARG_1, f_strtrans},
743 {"strwidth", 1, 1, FEARG_1, f_strwidth},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200744 {"submatch", 1, 2, FEARG_1, f_submatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200745 {"substitute", 4, 4, FEARG_1, f_substitute},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200746 {"swapinfo", 1, 1, FEARG_1, f_swapinfo},
747 {"swapname", 1, 1, FEARG_1, f_swapname},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200748 {"synID", 3, 3, 0, f_synID},
749 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
750 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
751 {"synconcealed", 2, 2, 0, f_synconcealed},
752 {"synstack", 2, 2, 0, f_synstack},
753 {"system", 1, 2, FEARG_1, f_system},
754 {"systemlist", 1, 2, FEARG_1, f_systemlist},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200755 {"tabpagebuflist", 0, 1, FEARG_1, f_tabpagebuflist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200756 {"tabpagenr", 0, 1, 0, f_tabpagenr},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200757 {"tabpagewinnr", 1, 2, FEARG_1, f_tabpagewinnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200758 {"tagfiles", 0, 0, 0, f_tagfiles},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200759 {"taglist", 1, 2, FEARG_1, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200760#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200761 {"tan", 1, 1, FEARG_1, f_tan},
762 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200763#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200764 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200765#ifdef FEAT_TERMINAL
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200766 {"term_dumpdiff", 2, 3, FEARG_1, f_term_dumpdiff},
767 {"term_dumpload", 1, 2, FEARG_1, f_term_dumpload},
768 {"term_dumpwrite", 2, 3, FEARG_2, f_term_dumpwrite},
769 {"term_getaltscreen", 1, 1, FEARG_1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200770# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200771 {"term_getansicolors", 1, 1, FEARG_1, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200772# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200773 {"term_getattr", 2, 2, FEARG_1, f_term_getattr},
774 {"term_getcursor", 1, 1, FEARG_1, f_term_getcursor},
775 {"term_getjob", 1, 1, FEARG_1, f_term_getjob},
776 {"term_getline", 2, 2, FEARG_1, f_term_getline},
777 {"term_getscrolled", 1, 1, FEARG_1, f_term_getscrolled},
778 {"term_getsize", 1, 1, FEARG_1, f_term_getsize},
779 {"term_getstatus", 1, 1, FEARG_1, f_term_getstatus},
780 {"term_gettitle", 1, 1, FEARG_1, f_term_gettitle},
781 {"term_gettty", 1, 2, FEARG_1, f_term_gettty},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200782 {"term_list", 0, 0, 0, f_term_list},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200783 {"term_scrape", 2, 2, FEARG_1, f_term_scrape},
784 {"term_sendkeys", 2, 2, FEARG_1, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200785# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200786 {"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200787# endif
Bram Moolenaard2842ea2019-09-26 23:08:54 +0200788 {"term_setapi", 2, 2, FEARG_1, f_term_setapi},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200789 {"term_setkill", 2, 2, FEARG_1, f_term_setkill},
790 {"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
791 {"term_setsize", 3, 3, FEARG_1, f_term_setsize},
792 {"term_start", 1, 2, FEARG_1, f_term_start},
793 {"term_wait", 1, 2, FEARG_1, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200794#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200795 {"test_alloc_fail", 3, 3, FEARG_1, f_test_alloc_fail},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200796 {"test_autochdir", 0, 0, 0, f_test_autochdir},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200797 {"test_feedinput", 1, 1, FEARG_1, f_test_feedinput},
798 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
799 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
800 {"test_getvalue", 1, 1, FEARG_1, f_test_getvalue},
801 {"test_ignore_error", 1, 1, FEARG_1, f_test_ignore_error},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200802 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200803#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200804 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200805#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200806 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200808 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200809#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200810 {"test_null_list", 0, 0, 0, f_test_null_list},
811 {"test_null_partial", 0, 0, 0, f_test_null_partial},
812 {"test_null_string", 0, 0, 0, f_test_null_string},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200813 {"test_option_not_set", 1, 1, FEARG_1, f_test_option_not_set},
814 {"test_override", 2, 2, FEARG_2, f_test_override},
815 {"test_refcount", 1, 1, FEARG_1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200816#ifdef FEAT_GUI
Bram Moolenaarce90e362019-09-08 18:58:44 +0200817 {"test_scrollbar", 3, 3, FEARG_2, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200818#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200819 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200820 {"test_settime", 1, 1, FEARG_1, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821#ifdef FEAT_TIMERS
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200822 {"timer_info", 0, 1, FEARG_1, f_timer_info},
823 {"timer_pause", 2, 2, FEARG_1, f_timer_pause},
824 {"timer_start", 2, 3, FEARG_1, f_timer_start},
825 {"timer_stop", 1, 1, FEARG_1, f_timer_stop},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200826 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827#endif
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200828 {"tolower", 1, 1, FEARG_1, f_tolower},
829 {"toupper", 1, 1, FEARG_1, f_toupper},
830 {"tr", 3, 3, FEARG_1, f_tr},
831 {"trim", 1, 2, FEARG_1, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200832#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200833 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200834#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200835 {"type", 1, 1, FEARG_1, f_type},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200836 {"undofile", 1, 1, FEARG_1, f_undofile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200837 {"undotree", 0, 0, 0, f_undotree},
838 {"uniq", 1, 3, FEARG_1, f_uniq},
839 {"values", 1, 1, FEARG_1, f_values},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200840 {"virtcol", 1, 1, FEARG_1, f_virtcol},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200841 {"visualmode", 0, 1, 0, f_visualmode},
842 {"wildmenumode", 0, 0, 0, f_wildmenumode},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200843 {"win_execute", 2, 3, FEARG_2, f_win_execute},
844 {"win_findbuf", 1, 1, FEARG_1, f_win_findbuf},
845 {"win_getid", 0, 2, FEARG_1, f_win_getid},
846 {"win_gotoid", 1, 1, FEARG_1, f_win_gotoid},
847 {"win_id2tabwin", 1, 1, FEARG_1, f_win_id2tabwin},
848 {"win_id2win", 1, 1, FEARG_1, f_win_id2win},
849 {"win_screenpos", 1, 1, FEARG_1, f_win_screenpos},
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200850 {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200851 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200852 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200853 {"winheight", 1, 1, FEARG_1, f_winheight},
854 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200855 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200856 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200857 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200858 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200859 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200860 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200861 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200862 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200863 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200864};
865
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200866/*
867 * Function given to ExpandGeneric() to obtain the list of internal
868 * or user defined function names.
869 */
870 char_u *
871get_function_name(expand_T *xp, int idx)
872{
873 static int intidx = -1;
874 char_u *name;
875
876 if (idx == 0)
877 intidx = -1;
878 if (intidx < 0)
879 {
880 name = get_user_func_name(xp, idx);
881 if (name != NULL)
882 return name;
883 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200884 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200885 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200886 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200887 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200888 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200889 STRCAT(IObuff, ")");
890 return IObuff;
891 }
892
893 return NULL;
894}
895
896/*
897 * Function given to ExpandGeneric() to obtain the list of internal or
898 * user defined variable or function names.
899 */
900 char_u *
901get_expr_name(expand_T *xp, int idx)
902{
903 static int intidx = -1;
904 char_u *name;
905
906 if (idx == 0)
907 intidx = -1;
908 if (intidx < 0)
909 {
910 name = get_function_name(xp, idx);
911 if (name != NULL)
912 return name;
913 }
914 return get_user_var_name(xp, ++intidx);
915}
916
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200918 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200919 * Return index, or -1 if not found
920 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200921 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200922find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923{
924 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200925 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926 int cmp;
927 int x;
928
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200929 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200930
931 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200932 while (first <= last)
933 {
934 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200935 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200936 if (cmp < 0)
937 last = x - 1;
938 else if (cmp > 0)
939 first = x + 1;
940 else
941 return x;
942 }
943 return -1;
944}
945
946 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200947has_internal_func(char_u *name)
948{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200949 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200950}
951
952 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200953call_internal_func(
954 char_u *name,
955 int argcount,
956 typval_T *argvars,
957 typval_T *rettv)
958{
959 int i;
960
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200961 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200962 if (i < 0)
963 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200964 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200965 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200966 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200967 return ERROR_TOOMANY;
968 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200969 global_functions[i].f_func(argvars, rettv);
970 return ERROR_NONE;
971}
972
973/*
974 * Invoke a method for base->method().
975 */
976 int
977call_internal_method(
978 char_u *name,
979 int argcount,
980 typval_T *argvars,
981 typval_T *rettv,
982 typval_T *basetv)
983{
984 int i;
985 int fi;
986 typval_T argv[MAX_FUNC_ARGS + 1];
987
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200988 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +0200989 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200990 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +0200991 if (global_functions[fi].f_argtype == 0)
992 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200993 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200994 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200995 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200996 return ERROR_TOOMANY;
997
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200998 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200999 {
1000 // base value goes last
1001 for (i = 0; i < argcount; ++i)
1002 argv[i] = argvars[i];
1003 argv[argcount] = *basetv;
1004 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001005 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001006 {
1007 // base value goes second
1008 argv[0] = argvars[0];
1009 argv[1] = *basetv;
1010 for (i = 1; i < argcount; ++i)
1011 argv[i + 1] = argvars[i];
1012 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001013 else if (global_functions[fi].f_argtype == FEARG_3)
1014 {
1015 // base value goes third
1016 argv[0] = argvars[0];
1017 argv[1] = argvars[1];
1018 argv[2] = *basetv;
1019 for (i = 2; i < argcount; ++i)
1020 argv[i + 1] = argvars[i];
1021 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001022 else if (global_functions[fi].f_argtype == FEARG_4)
1023 {
1024 // base value goes fourth
1025 argv[0] = argvars[0];
1026 argv[1] = argvars[1];
1027 argv[2] = argvars[2];
1028 argv[3] = *basetv;
1029 for (i = 3; i < argcount; ++i)
1030 argv[i + 1] = argvars[i];
1031 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001032 else
1033 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001034 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001035 argv[0] = *basetv;
1036 for (i = 0; i < argcount; ++i)
1037 argv[i + 1] = argvars[i];
1038 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001039 argv[argcount + 1].v_type = VAR_UNKNOWN;
1040
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001041 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001042 return ERROR_NONE;
1043}
1044
1045/*
1046 * Return TRUE for a non-zero Number and a non-empty String.
1047 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001048 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001049non_zero_arg(typval_T *argvars)
1050{
1051 return ((argvars[0].v_type == VAR_NUMBER
1052 && argvars[0].vval.v_number != 0)
1053 || (argvars[0].v_type == VAR_SPECIAL
1054 && argvars[0].vval.v_number == VVAL_TRUE)
1055 || (argvars[0].v_type == VAR_STRING
1056 && argvars[0].vval.v_string != NULL
1057 && *argvars[0].vval.v_string != NUL));
1058}
1059
1060/*
1061 * Get the lnum from the first argument.
1062 * Also accepts ".", "$", etc., but that only works for the current buffer.
1063 * Returns -1 on error.
1064 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001065 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001066tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001067{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001068 linenr_T lnum;
1069
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001070 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001071 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001072 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001073 int fnum;
1074 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1075
1076 if (fp != NULL)
1077 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001078 }
1079 return lnum;
1080}
1081
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001082/*
1083 * Get the lnum from the first argument.
1084 * Also accepts "$", then "buf" is used.
1085 * Returns 0 on error.
1086 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001087 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001088tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1089{
1090 if (argvars[0].v_type == VAR_STRING
1091 && argvars[0].vval.v_string != NULL
1092 && argvars[0].vval.v_string[0] == '$'
1093 && buf != NULL)
1094 return buf->b_ml.ml_line_count;
1095 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1096}
1097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001098#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001099/*
1100 * Get the float value of "argvars[0]" into "f".
1101 * Returns FAIL when the argument is not a Number or Float.
1102 */
1103 static int
1104get_float_arg(typval_T *argvars, float_T *f)
1105{
1106 if (argvars[0].v_type == VAR_FLOAT)
1107 {
1108 *f = argvars[0].vval.v_float;
1109 return OK;
1110 }
1111 if (argvars[0].v_type == VAR_NUMBER)
1112 {
1113 *f = (float_T)argvars[0].vval.v_number;
1114 return OK;
1115 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001116 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001117 return FAIL;
1118}
1119
1120/*
1121 * "abs(expr)" function
1122 */
1123 static void
1124f_abs(typval_T *argvars, typval_T *rettv)
1125{
1126 if (argvars[0].v_type == VAR_FLOAT)
1127 {
1128 rettv->v_type = VAR_FLOAT;
1129 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1130 }
1131 else
1132 {
1133 varnumber_T n;
1134 int error = FALSE;
1135
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001136 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001137 if (error)
1138 rettv->vval.v_number = -1;
1139 else if (n > 0)
1140 rettv->vval.v_number = n;
1141 else
1142 rettv->vval.v_number = -n;
1143 }
1144}
1145
1146/*
1147 * "acos()" function
1148 */
1149 static void
1150f_acos(typval_T *argvars, typval_T *rettv)
1151{
1152 float_T f = 0.0;
1153
1154 rettv->v_type = VAR_FLOAT;
1155 if (get_float_arg(argvars, &f) == OK)
1156 rettv->vval.v_float = acos(f);
1157 else
1158 rettv->vval.v_float = 0.0;
1159}
1160#endif
1161
1162/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001163 * "and(expr, expr)" function
1164 */
1165 static void
1166f_and(typval_T *argvars, typval_T *rettv)
1167{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001168 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1169 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001170}
1171
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001172#ifdef FEAT_FLOAT
1173/*
1174 * "asin()" function
1175 */
1176 static void
1177f_asin(typval_T *argvars, typval_T *rettv)
1178{
1179 float_T f = 0.0;
1180
1181 rettv->v_type = VAR_FLOAT;
1182 if (get_float_arg(argvars, &f) == OK)
1183 rettv->vval.v_float = asin(f);
1184 else
1185 rettv->vval.v_float = 0.0;
1186}
1187
1188/*
1189 * "atan()" function
1190 */
1191 static void
1192f_atan(typval_T *argvars, typval_T *rettv)
1193{
1194 float_T f = 0.0;
1195
1196 rettv->v_type = VAR_FLOAT;
1197 if (get_float_arg(argvars, &f) == OK)
1198 rettv->vval.v_float = atan(f);
1199 else
1200 rettv->vval.v_float = 0.0;
1201}
1202
1203/*
1204 * "atan2()" function
1205 */
1206 static void
1207f_atan2(typval_T *argvars, typval_T *rettv)
1208{
1209 float_T fx = 0.0, fy = 0.0;
1210
1211 rettv->v_type = VAR_FLOAT;
1212 if (get_float_arg(argvars, &fx) == OK
1213 && get_float_arg(&argvars[1], &fy) == OK)
1214 rettv->vval.v_float = atan2(fx, fy);
1215 else
1216 rettv->vval.v_float = 0.0;
1217}
1218#endif
1219
1220/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001221 * "balloon_show()" function
1222 */
1223#ifdef FEAT_BEVAL
1224 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001225f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1226{
1227 rettv->v_type = VAR_STRING;
1228 if (balloonEval != NULL)
1229 {
1230 if (balloonEval->msg == NULL)
1231 rettv->vval.v_string = NULL;
1232 else
1233 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1234 }
1235}
1236
1237 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001238f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1239{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001240 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001241 {
1242 if (argvars[0].v_type == VAR_LIST
1243# ifdef FEAT_GUI
1244 && !gui.in_use
1245# endif
1246 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001247 {
1248 list_T *l = argvars[0].vval.v_list;
1249
1250 // empty list removes the balloon
1251 post_balloon(balloonEval, NULL,
1252 l == NULL || l->lv_len == 0 ? NULL : l);
1253 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001254 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001255 {
1256 char_u *mesg = tv_get_string_chk(&argvars[0]);
1257
1258 if (mesg != NULL)
1259 // empty string removes the balloon
1260 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1261 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001262 }
1263}
1264
Bram Moolenaar669a8282017-11-19 20:13:05 +01001265# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001266 static void
1267f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1268{
1269 if (rettv_list_alloc(rettv) == OK)
1270 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001271 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001272
1273 if (msg != NULL)
1274 {
1275 pumitem_T *array;
1276 int size = split_message(msg, &array);
1277 int i;
1278
1279 /* Skip the first and last item, they are always empty. */
1280 for (i = 1; i < size - 1; ++i)
1281 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001282 while (size > 0)
1283 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001284 vim_free(array);
1285 }
1286 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001287}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001288# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001289#endif
1290
1291/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001292 * Get buffer by number or pattern.
1293 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001294 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001295tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001296{
1297 char_u *name = tv->vval.v_string;
1298 buf_T *buf;
1299
1300 if (tv->v_type == VAR_NUMBER)
1301 return buflist_findnr((int)tv->vval.v_number);
1302 if (tv->v_type != VAR_STRING)
1303 return NULL;
1304 if (name == NULL || *name == NUL)
1305 return curbuf;
1306 if (name[0] == '$' && name[1] == NUL)
1307 return lastbuf;
1308
1309 buf = buflist_find_by_name(name, curtab_only);
1310
1311 /* If not found, try expanding the name, like done for bufexists(). */
1312 if (buf == NULL)
1313 buf = find_buffer(tv);
1314
1315 return buf;
1316}
1317
1318/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001319 * Get the buffer from "arg" and give an error and return NULL if it is not
1320 * valid.
1321 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001322 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001323get_buf_arg(typval_T *arg)
1324{
1325 buf_T *buf;
1326
1327 ++emsg_off;
1328 buf = tv_get_buf(arg, FALSE);
1329 --emsg_off;
1330 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001331 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001332 return buf;
1333}
1334
1335/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001336 * "byte2line(byte)" function
1337 */
1338 static void
1339f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1340{
1341#ifndef FEAT_BYTEOFF
1342 rettv->vval.v_number = -1;
1343#else
1344 long boff = 0;
1345
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001346 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347 if (boff < 0)
1348 rettv->vval.v_number = -1;
1349 else
1350 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1351 (linenr_T)0, &boff);
1352#endif
1353}
1354
1355 static void
1356byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1357{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001359 char_u *str;
1360 varnumber_T idx;
1361
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001362 str = tv_get_string_chk(&argvars[0]);
1363 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364 rettv->vval.v_number = -1;
1365 if (str == NULL || idx < 0)
1366 return;
1367
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001368 t = str;
1369 for ( ; idx > 0; idx--)
1370 {
1371 if (*t == NUL) /* EOL reached */
1372 return;
1373 if (enc_utf8 && comp)
1374 t += utf_ptr2len(t);
1375 else
1376 t += (*mb_ptr2len)(t);
1377 }
1378 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001379}
1380
1381/*
1382 * "byteidx()" function
1383 */
1384 static void
1385f_byteidx(typval_T *argvars, typval_T *rettv)
1386{
1387 byteidx(argvars, rettv, FALSE);
1388}
1389
1390/*
1391 * "byteidxcomp()" function
1392 */
1393 static void
1394f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1395{
1396 byteidx(argvars, rettv, TRUE);
1397}
1398
1399/*
1400 * "call(func, arglist [, dict])" function
1401 */
1402 static void
1403f_call(typval_T *argvars, typval_T *rettv)
1404{
1405 char_u *func;
1406 partial_T *partial = NULL;
1407 dict_T *selfdict = NULL;
1408
1409 if (argvars[1].v_type != VAR_LIST)
1410 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001411 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001412 return;
1413 }
1414 if (argvars[1].vval.v_list == NULL)
1415 return;
1416
1417 if (argvars[0].v_type == VAR_FUNC)
1418 func = argvars[0].vval.v_string;
1419 else if (argvars[0].v_type == VAR_PARTIAL)
1420 {
1421 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001422 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001423 }
1424 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001425 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001426 if (*func == NUL)
1427 return; /* type error or empty name */
1428
1429 if (argvars[2].v_type != VAR_UNKNOWN)
1430 {
1431 if (argvars[2].v_type != VAR_DICT)
1432 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001433 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434 return;
1435 }
1436 selfdict = argvars[2].vval.v_dict;
1437 }
1438
1439 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1440}
1441
1442#ifdef FEAT_FLOAT
1443/*
1444 * "ceil({float})" function
1445 */
1446 static void
1447f_ceil(typval_T *argvars, typval_T *rettv)
1448{
1449 float_T f = 0.0;
1450
1451 rettv->v_type = VAR_FLOAT;
1452 if (get_float_arg(argvars, &f) == OK)
1453 rettv->vval.v_float = ceil(f);
1454 else
1455 rettv->vval.v_float = 0.0;
1456}
1457#endif
1458
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001459/*
1460 * "changenr()" function
1461 */
1462 static void
1463f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1464{
1465 rettv->vval.v_number = curbuf->b_u_seq_cur;
1466}
1467
1468/*
1469 * "char2nr(string)" function
1470 */
1471 static void
1472f_char2nr(typval_T *argvars, typval_T *rettv)
1473{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001474 if (has_mbyte)
1475 {
1476 int utf8 = 0;
1477
1478 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001479 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480
1481 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001482 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001484 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001485 }
1486 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001487 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488}
1489
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001490 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001491get_optional_window(typval_T *argvars, int idx)
1492{
1493 win_T *win = curwin;
1494
1495 if (argvars[idx].v_type != VAR_UNKNOWN)
1496 {
1497 win = find_win_by_nr_or_id(&argvars[idx]);
1498 if (win == NULL)
1499 {
1500 emsg(_(e_invalwindow));
1501 return NULL;
1502 }
1503 }
1504 return win;
1505}
1506
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001507/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508 * "col(string)" function
1509 */
1510 static void
1511f_col(typval_T *argvars, typval_T *rettv)
1512{
1513 colnr_T col = 0;
1514 pos_T *fp;
1515 int fnum = curbuf->b_fnum;
1516
1517 fp = var2fpos(&argvars[0], FALSE, &fnum);
1518 if (fp != NULL && fnum == curbuf->b_fnum)
1519 {
1520 if (fp->col == MAXCOL)
1521 {
1522 /* '> can be MAXCOL, get the length of the line then */
1523 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1524 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1525 else
1526 col = MAXCOL;
1527 }
1528 else
1529 {
1530 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001531 /* col(".") when the cursor is on the NUL at the end of the line
1532 * because of "coladd" can be seen as an extra column. */
1533 if (virtual_active() && fp == &curwin->w_cursor)
1534 {
1535 char_u *p = ml_get_cursor();
1536
1537 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1538 curwin->w_virtcol - curwin->w_cursor.coladd))
1539 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001540 int l;
1541
1542 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1543 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001544 }
1545 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001546 }
1547 }
1548 rettv->vval.v_number = col;
1549}
1550
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001551/*
1552 * "confirm(message, buttons[, default [, type]])" function
1553 */
1554 static void
1555f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1556{
1557#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1558 char_u *message;
1559 char_u *buttons = NULL;
1560 char_u buf[NUMBUFLEN];
1561 char_u buf2[NUMBUFLEN];
1562 int def = 1;
1563 int type = VIM_GENERIC;
1564 char_u *typestr;
1565 int error = FALSE;
1566
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001567 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001568 if (message == NULL)
1569 error = TRUE;
1570 if (argvars[1].v_type != VAR_UNKNOWN)
1571 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001572 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001573 if (buttons == NULL)
1574 error = TRUE;
1575 if (argvars[2].v_type != VAR_UNKNOWN)
1576 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001577 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001578 if (argvars[3].v_type != VAR_UNKNOWN)
1579 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001580 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001581 if (typestr == NULL)
1582 error = TRUE;
1583 else
1584 {
1585 switch (TOUPPER_ASC(*typestr))
1586 {
1587 case 'E': type = VIM_ERROR; break;
1588 case 'Q': type = VIM_QUESTION; break;
1589 case 'I': type = VIM_INFO; break;
1590 case 'W': type = VIM_WARNING; break;
1591 case 'G': type = VIM_GENERIC; break;
1592 }
1593 }
1594 }
1595 }
1596 }
1597
1598 if (buttons == NULL || *buttons == NUL)
1599 buttons = (char_u *)_("&Ok");
1600
1601 if (!error)
1602 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1603 def, NULL, FALSE);
1604#endif
1605}
1606
1607/*
1608 * "copy()" function
1609 */
1610 static void
1611f_copy(typval_T *argvars, typval_T *rettv)
1612{
1613 item_copy(&argvars[0], rettv, FALSE, 0);
1614}
1615
1616#ifdef FEAT_FLOAT
1617/*
1618 * "cos()" function
1619 */
1620 static void
1621f_cos(typval_T *argvars, typval_T *rettv)
1622{
1623 float_T f = 0.0;
1624
1625 rettv->v_type = VAR_FLOAT;
1626 if (get_float_arg(argvars, &f) == OK)
1627 rettv->vval.v_float = cos(f);
1628 else
1629 rettv->vval.v_float = 0.0;
1630}
1631
1632/*
1633 * "cosh()" function
1634 */
1635 static void
1636f_cosh(typval_T *argvars, typval_T *rettv)
1637{
1638 float_T f = 0.0;
1639
1640 rettv->v_type = VAR_FLOAT;
1641 if (get_float_arg(argvars, &f) == OK)
1642 rettv->vval.v_float = cosh(f);
1643 else
1644 rettv->vval.v_float = 0.0;
1645}
1646#endif
1647
1648/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649 * "cursor(lnum, col)" function, or
1650 * "cursor(list)"
1651 *
1652 * Moves the cursor to the specified line and column.
1653 * Returns 0 when the position could be set, -1 otherwise.
1654 */
1655 static void
1656f_cursor(typval_T *argvars, typval_T *rettv)
1657{
1658 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001659 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001660 int set_curswant = TRUE;
1661
1662 rettv->vval.v_number = -1;
1663 if (argvars[1].v_type == VAR_UNKNOWN)
1664 {
1665 pos_T pos;
1666 colnr_T curswant = -1;
1667
1668 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1669 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001670 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001671 return;
1672 }
1673 line = pos.lnum;
1674 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001676 if (curswant >= 0)
1677 {
1678 curwin->w_curswant = curswant - 1;
1679 set_curswant = FALSE;
1680 }
1681 }
1682 else
1683 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001684 line = tv_get_lnum(argvars);
1685 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001687 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001689 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001690 return; /* type error; errmsg already given */
1691 if (line > 0)
1692 curwin->w_cursor.lnum = line;
1693 if (col > 0)
1694 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001695 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001696
1697 /* Make sure the cursor is in a valid position. */
1698 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001699 /* Correct cursor for multi-byte character. */
1700 if (has_mbyte)
1701 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001702
1703 curwin->w_set_curswant = set_curswant;
1704 rettv->vval.v_number = 0;
1705}
1706
Bram Moolenaar4f974752019-02-17 17:44:42 +01001707#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001708/*
1709 * "debugbreak()" function
1710 */
1711 static void
1712f_debugbreak(typval_T *argvars, typval_T *rettv)
1713{
1714 int pid;
1715
1716 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001717 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001718 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001719 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001720 else
1721 {
1722 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1723
1724 if (hProcess != NULL)
1725 {
1726 DebugBreakProcess(hProcess);
1727 CloseHandle(hProcess);
1728 rettv->vval.v_number = OK;
1729 }
1730 }
1731}
1732#endif
1733
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001734/*
1735 * "deepcopy()" function
1736 */
1737 static void
1738f_deepcopy(typval_T *argvars, typval_T *rettv)
1739{
1740 int noref = 0;
1741 int copyID;
1742
1743 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001744 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001745 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001746 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001747 else
1748 {
1749 copyID = get_copyID();
1750 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1751 }
1752}
1753
1754/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001755 * "did_filetype()" function
1756 */
1757 static void
1758f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1759{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001760 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001761}
1762
1763/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001764 * "empty({expr})" function
1765 */
1766 static void
1767f_empty(typval_T *argvars, typval_T *rettv)
1768{
1769 int n = FALSE;
1770
1771 switch (argvars[0].v_type)
1772 {
1773 case VAR_STRING:
1774 case VAR_FUNC:
1775 n = argvars[0].vval.v_string == NULL
1776 || *argvars[0].vval.v_string == NUL;
1777 break;
1778 case VAR_PARTIAL:
1779 n = FALSE;
1780 break;
1781 case VAR_NUMBER:
1782 n = argvars[0].vval.v_number == 0;
1783 break;
1784 case VAR_FLOAT:
1785#ifdef FEAT_FLOAT
1786 n = argvars[0].vval.v_float == 0.0;
1787 break;
1788#endif
1789 case VAR_LIST:
1790 n = argvars[0].vval.v_list == NULL
1791 || argvars[0].vval.v_list->lv_first == NULL;
1792 break;
1793 case VAR_DICT:
1794 n = argvars[0].vval.v_dict == NULL
1795 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1796 break;
1797 case VAR_SPECIAL:
1798 n = argvars[0].vval.v_number != VVAL_TRUE;
1799 break;
1800
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001801 case VAR_BLOB:
1802 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001803 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1804 break;
1805
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001806 case VAR_JOB:
1807#ifdef FEAT_JOB_CHANNEL
1808 n = argvars[0].vval.v_job == NULL
1809 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1810 break;
1811#endif
1812 case VAR_CHANNEL:
1813#ifdef FEAT_JOB_CHANNEL
1814 n = argvars[0].vval.v_channel == NULL
1815 || !channel_is_open(argvars[0].vval.v_channel);
1816 break;
1817#endif
1818 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001819 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001820 n = TRUE;
1821 break;
1822 }
1823
1824 rettv->vval.v_number = n;
1825}
1826
1827/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001828 * "environ()" function
1829 */
1830 static void
1831f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1832{
1833#if !defined(AMIGA)
1834 int i = 0;
1835 char_u *entry, *value;
1836# ifdef MSWIN
1837 extern wchar_t **_wenviron;
1838# else
1839 extern char **environ;
1840# endif
1841
1842 if (rettv_dict_alloc(rettv) != OK)
1843 return;
1844
1845# ifdef MSWIN
1846 if (*_wenviron == NULL)
1847 return;
1848# else
1849 if (*environ == NULL)
1850 return;
1851# endif
1852
1853 for (i = 0; ; ++i)
1854 {
1855# ifdef MSWIN
1856 short_u *p;
1857
1858 if ((p = (short_u *)_wenviron[i]) == NULL)
1859 return;
1860 entry = utf16_to_enc(p, NULL);
1861# else
1862 if ((entry = (char_u *)environ[i]) == NULL)
1863 return;
1864 entry = vim_strsave(entry);
1865# endif
1866 if (entry == NULL) // out of memory
1867 return;
1868 if ((value = vim_strchr(entry, '=')) == NULL)
1869 {
1870 vim_free(entry);
1871 continue;
1872 }
1873 *value++ = NUL;
1874 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1875 vim_free(entry);
1876 }
1877#endif
1878}
1879
1880/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001881 * "escape({string}, {chars})" function
1882 */
1883 static void
1884f_escape(typval_T *argvars, typval_T *rettv)
1885{
1886 char_u buf[NUMBUFLEN];
1887
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001888 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1889 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001890 rettv->v_type = VAR_STRING;
1891}
1892
1893/*
1894 * "eval()" function
1895 */
1896 static void
1897f_eval(typval_T *argvars, typval_T *rettv)
1898{
1899 char_u *s, *p;
1900
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001901 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001902 if (s != NULL)
1903 s = skipwhite(s);
1904
1905 p = s;
1906 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1907 {
1908 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001909 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001910 need_clr_eos = FALSE;
1911 rettv->v_type = VAR_NUMBER;
1912 rettv->vval.v_number = 0;
1913 }
1914 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001915 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001916}
1917
1918/*
1919 * "eventhandler()" function
1920 */
1921 static void
1922f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1923{
1924 rettv->vval.v_number = vgetc_busy;
1925}
1926
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001927static garray_T redir_execute_ga;
1928
1929/*
1930 * Append "value[value_len]" to the execute() output.
1931 */
1932 void
1933execute_redir_str(char_u *value, int value_len)
1934{
1935 int len;
1936
1937 if (value_len == -1)
1938 len = (int)STRLEN(value); /* Append the entire string */
1939 else
1940 len = value_len; /* Append only "value_len" characters */
1941 if (ga_grow(&redir_execute_ga, len) == OK)
1942 {
1943 mch_memmove((char *)redir_execute_ga.ga_data
1944 + redir_execute_ga.ga_len, value, len);
1945 redir_execute_ga.ga_len += len;
1946 }
1947}
1948
1949/*
1950 * Get next line from a list.
1951 * Called by do_cmdline() to get the next line.
1952 * Returns allocated string, or NULL for end of function.
1953 */
1954
1955 static char_u *
1956get_list_line(
1957 int c UNUSED,
1958 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001959 int indent UNUSED,
1960 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001961{
1962 listitem_T **p = (listitem_T **)cookie;
1963 listitem_T *item = *p;
1964 char_u buf[NUMBUFLEN];
1965 char_u *s;
1966
1967 if (item == NULL)
1968 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001969 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001970 *p = item->li_next;
1971 return s == NULL ? NULL : vim_strsave(s);
1972}
1973
1974/*
1975 * "execute()" function
1976 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001977 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001978execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001979{
1980 char_u *cmd = NULL;
1981 list_T *list = NULL;
1982 int save_msg_silent = msg_silent;
1983 int save_emsg_silent = emsg_silent;
1984 int save_emsg_noredir = emsg_noredir;
1985 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01001986 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01001988 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01001989 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001990
1991 rettv->vval.v_string = NULL;
1992 rettv->v_type = VAR_STRING;
1993
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001994 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001996 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001997 if (list == NULL || list->lv_first == NULL)
1998 /* empty list, no commands, empty output */
1999 return;
2000 ++list->lv_refcount;
2001 }
2002 else
2003 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002004 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002005 if (cmd == NULL)
2006 return;
2007 }
2008
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002009 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 {
2011 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002012 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013
2014 if (s == NULL)
2015 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002016 if (*s == NUL)
2017 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002018 if (STRNCMP(s, "silent", 6) == 0)
2019 ++msg_silent;
2020 if (STRCMP(s, "silent!") == 0)
2021 {
2022 emsg_silent = TRUE;
2023 emsg_noredir = TRUE;
2024 }
2025 }
2026 else
2027 ++msg_silent;
2028
2029 if (redir_execute)
2030 save_ga = redir_execute_ga;
2031 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2032 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002033 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002034 if (!echo_output)
2035 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002036
2037 if (cmd != NULL)
2038 do_cmdline_cmd(cmd);
2039 else
2040 {
2041 listitem_T *item = list->lv_first;
2042
2043 do_cmdline(NULL, get_list_line, (void *)&item,
2044 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2045 --list->lv_refcount;
2046 }
2047
Bram Moolenaard297f352017-01-29 20:31:21 +01002048 /* Need to append a NUL to the result. */
2049 if (ga_grow(&redir_execute_ga, 1) == OK)
2050 {
2051 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2052 rettv->vval.v_string = redir_execute_ga.ga_data;
2053 }
2054 else
2055 {
2056 ga_clear(&redir_execute_ga);
2057 rettv->vval.v_string = NULL;
2058 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002059 msg_silent = save_msg_silent;
2060 emsg_silent = save_emsg_silent;
2061 emsg_noredir = save_emsg_noredir;
2062
2063 redir_execute = save_redir_execute;
2064 if (redir_execute)
2065 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002066 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002067
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002068 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002069 if (echo_output)
2070 // When not working silently: put it in column zero. A following
2071 // "echon" will overwrite the message, unavoidably.
2072 msg_col = 0;
2073 else
2074 // When working silently: Put it back where it was, since nothing
2075 // should have been written.
2076 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002077}
2078
2079/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002080 * "execute()" function
2081 */
2082 static void
2083f_execute(typval_T *argvars, typval_T *rettv)
2084{
2085 execute_common(argvars, rettv, 0);
2086}
2087
2088/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002089 * "exists()" function
2090 */
2091 static void
2092f_exists(typval_T *argvars, typval_T *rettv)
2093{
2094 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002096
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002097 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 if (*p == '$') /* environment variable */
2099 {
2100 /* first try "normal" environment variables (fast) */
2101 if (mch_getenv(p + 1) != NULL)
2102 n = TRUE;
2103 else
2104 {
2105 /* try expanding things like $VIM and ${HOME} */
2106 p = expand_env_save(p);
2107 if (p != NULL && *p != '$')
2108 n = TRUE;
2109 vim_free(p);
2110 }
2111 }
2112 else if (*p == '&' || *p == '+') /* option */
2113 {
2114 n = (get_option_tv(&p, NULL, TRUE) == OK);
2115 if (*skipwhite(p) != NUL)
2116 n = FALSE; /* trailing garbage */
2117 }
2118 else if (*p == '*') /* internal or user defined function */
2119 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002120 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002121 }
2122 else if (*p == ':')
2123 {
2124 n = cmd_exists(p + 1);
2125 }
2126 else if (*p == '#')
2127 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002128 if (p[1] == '#')
2129 n = autocmd_supported(p + 2);
2130 else
2131 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002132 }
2133 else /* internal variable */
2134 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002135 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002136 }
2137
2138 rettv->vval.v_number = n;
2139}
2140
2141#ifdef FEAT_FLOAT
2142/*
2143 * "exp()" function
2144 */
2145 static void
2146f_exp(typval_T *argvars, typval_T *rettv)
2147{
2148 float_T f = 0.0;
2149
2150 rettv->v_type = VAR_FLOAT;
2151 if (get_float_arg(argvars, &f) == OK)
2152 rettv->vval.v_float = exp(f);
2153 else
2154 rettv->vval.v_float = 0.0;
2155}
2156#endif
2157
2158/*
2159 * "expand()" function
2160 */
2161 static void
2162f_expand(typval_T *argvars, typval_T *rettv)
2163{
2164 char_u *s;
2165 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002166 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002167 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2168 expand_T xpc;
2169 int error = FALSE;
2170 char_u *result;
2171
2172 rettv->v_type = VAR_STRING;
2173 if (argvars[1].v_type != VAR_UNKNOWN
2174 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002175 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002177 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002179 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180 if (*s == '%' || *s == '#' || *s == '<')
2181 {
2182 ++emsg_off;
2183 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2184 --emsg_off;
2185 if (rettv->v_type == VAR_LIST)
2186 {
2187 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2188 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002189 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002190 }
2191 else
2192 rettv->vval.v_string = result;
2193 }
2194 else
2195 {
2196 /* When the optional second argument is non-zero, don't remove matches
2197 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2198 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002199 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002200 options |= WILD_KEEP_ALL;
2201 if (!error)
2202 {
2203 ExpandInit(&xpc);
2204 xpc.xp_context = EXPAND_FILES;
2205 if (p_wic)
2206 options += WILD_ICASE;
2207 if (rettv->v_type == VAR_STRING)
2208 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2209 options, WILD_ALL);
2210 else if (rettv_list_alloc(rettv) != FAIL)
2211 {
2212 int i;
2213
2214 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2215 for (i = 0; i < xpc.xp_numfiles; i++)
2216 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2217 ExpandCleanup(&xpc);
2218 }
2219 }
2220 else
2221 rettv->vval.v_string = NULL;
2222 }
2223}
2224
2225/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002226 * "expandcmd()" function
2227 * Expand all the special characters in a command string.
2228 */
2229 static void
2230f_expandcmd(typval_T *argvars, typval_T *rettv)
2231{
2232 exarg_T eap;
2233 char_u *cmdstr;
2234 char *errormsg = NULL;
2235
2236 rettv->v_type = VAR_STRING;
2237 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2238
2239 memset(&eap, 0, sizeof(eap));
2240 eap.cmd = cmdstr;
2241 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002242 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002243 eap.usefilter = FALSE;
2244 eap.nextcmd = NULL;
2245 eap.cmdidx = CMD_USER;
2246
2247 expand_filename(&eap, &cmdstr, &errormsg);
2248 if (errormsg != NULL && *errormsg != NUL)
2249 emsg(errormsg);
2250
2251 rettv->vval.v_string = cmdstr;
2252}
2253
2254/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002255 * "feedkeys()" function
2256 */
2257 static void
2258f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2259{
2260 int remap = TRUE;
2261 int insert = FALSE;
2262 char_u *keys, *flags;
2263 char_u nbuf[NUMBUFLEN];
2264 int typed = FALSE;
2265 int execute = FALSE;
2266 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002267 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002268 char_u *keys_esc;
2269
2270 /* This is not allowed in the sandbox. If the commands would still be
2271 * executed in the sandbox it would be OK, but it probably happens later,
2272 * when "sandbox" is no longer set. */
2273 if (check_secure())
2274 return;
2275
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002276 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002277
2278 if (argvars[1].v_type != VAR_UNKNOWN)
2279 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002280 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002281 for ( ; *flags != NUL; ++flags)
2282 {
2283 switch (*flags)
2284 {
2285 case 'n': remap = FALSE; break;
2286 case 'm': remap = TRUE; break;
2287 case 't': typed = TRUE; break;
2288 case 'i': insert = TRUE; break;
2289 case 'x': execute = TRUE; break;
2290 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002291 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002292 }
2293 }
2294 }
2295
2296 if (*keys != NUL || execute)
2297 {
2298 /* Need to escape K_SPECIAL and CSI before putting the string in the
2299 * typeahead buffer. */
2300 keys_esc = vim_strsave_escape_csi(keys);
2301 if (keys_esc != NULL)
2302 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002303 if (lowlevel)
2304 {
2305#ifdef USE_INPUT_BUF
2306 add_to_input_buf(keys, (int)STRLEN(keys));
2307#else
2308 emsg(_("E980: lowlevel input not supported"));
2309#endif
2310 }
2311 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002312 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002313 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002314 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002315 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002316#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002317 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002318#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002319 )
2320 typebuf_was_filled = TRUE;
2321 }
2322 vim_free(keys_esc);
2323
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002324 if (execute)
2325 {
2326 int save_msg_scroll = msg_scroll;
2327
2328 /* Avoid a 1 second delay when the keys start Insert mode. */
2329 msg_scroll = FALSE;
2330
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002331 if (!dangerous)
2332 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002333 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002334 if (!dangerous)
2335 --ex_normal_busy;
2336
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002337 msg_scroll |= save_msg_scroll;
2338 }
2339 }
2340 }
2341}
2342
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002343#ifdef FEAT_FLOAT
2344/*
2345 * "float2nr({float})" function
2346 */
2347 static void
2348f_float2nr(typval_T *argvars, typval_T *rettv)
2349{
2350 float_T f = 0.0;
2351
2352 if (get_float_arg(argvars, &f) == OK)
2353 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002354 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002355 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002356 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002357 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002358 else
2359 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002360 }
2361}
2362
2363/*
2364 * "floor({float})" function
2365 */
2366 static void
2367f_floor(typval_T *argvars, typval_T *rettv)
2368{
2369 float_T f = 0.0;
2370
2371 rettv->v_type = VAR_FLOAT;
2372 if (get_float_arg(argvars, &f) == OK)
2373 rettv->vval.v_float = floor(f);
2374 else
2375 rettv->vval.v_float = 0.0;
2376}
2377
2378/*
2379 * "fmod()" function
2380 */
2381 static void
2382f_fmod(typval_T *argvars, typval_T *rettv)
2383{
2384 float_T fx = 0.0, fy = 0.0;
2385
2386 rettv->v_type = VAR_FLOAT;
2387 if (get_float_arg(argvars, &fx) == OK
2388 && get_float_arg(&argvars[1], &fy) == OK)
2389 rettv->vval.v_float = fmod(fx, fy);
2390 else
2391 rettv->vval.v_float = 0.0;
2392}
2393#endif
2394
2395/*
2396 * "fnameescape({string})" function
2397 */
2398 static void
2399f_fnameescape(typval_T *argvars, typval_T *rettv)
2400{
2401 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002402 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002403 rettv->v_type = VAR_STRING;
2404}
2405
2406/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002407 * "foreground()" function
2408 */
2409 static void
2410f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2411{
2412#ifdef FEAT_GUI
2413 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002414 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002415 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002416 return;
2417 }
2418#endif
2419#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002420 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002421#endif
2422}
2423
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002424 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002425common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002426{
2427 char_u *s;
2428 char_u *name;
2429 int use_string = FALSE;
2430 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002431 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002432
2433 if (argvars[0].v_type == VAR_FUNC)
2434 {
2435 /* function(MyFunc, [arg], dict) */
2436 s = argvars[0].vval.v_string;
2437 }
2438 else if (argvars[0].v_type == VAR_PARTIAL
2439 && argvars[0].vval.v_partial != NULL)
2440 {
2441 /* function(dict.MyFunc, [arg]) */
2442 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002443 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002444 }
2445 else
2446 {
2447 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002448 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002449 use_string = TRUE;
2450 }
2451
Bram Moolenaar843b8842016-08-21 14:36:15 +02002452 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002453 {
2454 name = s;
2455 trans_name = trans_function_name(&name, FALSE,
2456 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2457 if (*name != NUL)
2458 s = NULL;
2459 }
2460
Bram Moolenaar843b8842016-08-21 14:36:15 +02002461 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2462 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002463 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002464 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002465 else if (trans_name != NULL && (is_funcref
2466 ? find_func(trans_name) == NULL
2467 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002468 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002469 else
2470 {
2471 int dict_idx = 0;
2472 int arg_idx = 0;
2473 list_T *list = NULL;
2474
2475 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2476 {
2477 char sid_buf[25];
2478 int off = *s == 's' ? 2 : 5;
2479
2480 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2481 * also be called from another script. Using trans_function_name()
2482 * would also work, but some plugins depend on the name being
2483 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002484 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002485 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002486 if (name != NULL)
2487 {
2488 STRCPY(name, sid_buf);
2489 STRCAT(name, s + off);
2490 }
2491 }
2492 else
2493 name = vim_strsave(s);
2494
2495 if (argvars[1].v_type != VAR_UNKNOWN)
2496 {
2497 if (argvars[2].v_type != VAR_UNKNOWN)
2498 {
2499 /* function(name, [args], dict) */
2500 arg_idx = 1;
2501 dict_idx = 2;
2502 }
2503 else if (argvars[1].v_type == VAR_DICT)
2504 /* function(name, dict) */
2505 dict_idx = 1;
2506 else
2507 /* function(name, [args]) */
2508 arg_idx = 1;
2509 if (dict_idx > 0)
2510 {
2511 if (argvars[dict_idx].v_type != VAR_DICT)
2512 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002513 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002514 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002515 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002516 }
2517 if (argvars[dict_idx].vval.v_dict == NULL)
2518 dict_idx = 0;
2519 }
2520 if (arg_idx > 0)
2521 {
2522 if (argvars[arg_idx].v_type != VAR_LIST)
2523 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002524 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002525 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002526 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002527 }
2528 list = argvars[arg_idx].vval.v_list;
2529 if (list == NULL || list->lv_len == 0)
2530 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002531 else if (list->lv_len > MAX_FUNC_ARGS)
2532 {
2533 emsg_funcname((char *)e_toomanyarg, name);
2534 vim_free(name);
2535 goto theend;
2536 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 }
2538 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002539 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002540 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002541 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002542
2543 /* result is a VAR_PARTIAL */
2544 if (pt == NULL)
2545 vim_free(name);
2546 else
2547 {
2548 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2549 {
2550 listitem_T *li;
2551 int i = 0;
2552 int arg_len = 0;
2553 int lv_len = 0;
2554
2555 if (arg_pt != NULL)
2556 arg_len = arg_pt->pt_argc;
2557 if (list != NULL)
2558 lv_len = list->lv_len;
2559 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002560 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002561 if (pt->pt_argv == NULL)
2562 {
2563 vim_free(pt);
2564 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002565 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002566 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002567 for (i = 0; i < arg_len; i++)
2568 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2569 if (lv_len > 0)
2570 for (li = list->lv_first; li != NULL;
2571 li = li->li_next)
2572 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002573 }
2574
2575 /* For "function(dict.func, [], dict)" and "func" is a partial
2576 * use "dict". That is backwards compatible. */
2577 if (dict_idx > 0)
2578 {
2579 /* The dict is bound explicitly, pt_auto is FALSE. */
2580 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2581 ++pt->pt_dict->dv_refcount;
2582 }
2583 else if (arg_pt != NULL)
2584 {
2585 /* If the dict was bound automatically the result is also
2586 * bound automatically. */
2587 pt->pt_dict = arg_pt->pt_dict;
2588 pt->pt_auto = arg_pt->pt_auto;
2589 if (pt->pt_dict != NULL)
2590 ++pt->pt_dict->dv_refcount;
2591 }
2592
2593 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002594 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2595 {
2596 pt->pt_func = arg_pt->pt_func;
2597 func_ptr_ref(pt->pt_func);
2598 vim_free(name);
2599 }
2600 else if (is_funcref)
2601 {
2602 pt->pt_func = find_func(trans_name);
2603 func_ptr_ref(pt->pt_func);
2604 vim_free(name);
2605 }
2606 else
2607 {
2608 pt->pt_name = name;
2609 func_ref(name);
2610 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002611 }
2612 rettv->v_type = VAR_PARTIAL;
2613 rettv->vval.v_partial = pt;
2614 }
2615 else
2616 {
2617 /* result is a VAR_FUNC */
2618 rettv->v_type = VAR_FUNC;
2619 rettv->vval.v_string = name;
2620 func_ref(name);
2621 }
2622 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002623theend:
2624 vim_free(trans_name);
2625}
2626
2627/*
2628 * "funcref()" function
2629 */
2630 static void
2631f_funcref(typval_T *argvars, typval_T *rettv)
2632{
2633 common_function(argvars, rettv, TRUE);
2634}
2635
2636/*
2637 * "function()" function
2638 */
2639 static void
2640f_function(typval_T *argvars, typval_T *rettv)
2641{
2642 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002643}
2644
2645/*
2646 * "garbagecollect()" function
2647 */
2648 static void
2649f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2650{
2651 /* This is postponed until we are back at the toplevel, because we may be
2652 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2653 want_garbage_collect = TRUE;
2654
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002655 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002656 garbage_collect_at_exit = TRUE;
2657}
2658
2659/*
2660 * "get()" function
2661 */
2662 static void
2663f_get(typval_T *argvars, typval_T *rettv)
2664{
2665 listitem_T *li;
2666 list_T *l;
2667 dictitem_T *di;
2668 dict_T *d;
2669 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002670 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002671
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002672 if (argvars[0].v_type == VAR_BLOB)
2673 {
2674 int error = FALSE;
2675 int idx = tv_get_number_chk(&argvars[1], &error);
2676
2677 if (!error)
2678 {
2679 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002680 if (idx < 0)
2681 idx = blob_len(argvars[0].vval.v_blob) + idx;
2682 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2683 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002684 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002685 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002686 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002687 tv = rettv;
2688 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002689 }
2690 }
2691 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002692 {
2693 if ((l = argvars[0].vval.v_list) != NULL)
2694 {
2695 int error = FALSE;
2696
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002697 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002698 if (!error && li != NULL)
2699 tv = &li->li_tv;
2700 }
2701 }
2702 else if (argvars[0].v_type == VAR_DICT)
2703 {
2704 if ((d = argvars[0].vval.v_dict) != NULL)
2705 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002706 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002707 if (di != NULL)
2708 tv = &di->di_tv;
2709 }
2710 }
2711 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2712 {
2713 partial_T *pt;
2714 partial_T fref_pt;
2715
2716 if (argvars[0].v_type == VAR_PARTIAL)
2717 pt = argvars[0].vval.v_partial;
2718 else
2719 {
2720 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2721 fref_pt.pt_name = argvars[0].vval.v_string;
2722 pt = &fref_pt;
2723 }
2724
2725 if (pt != NULL)
2726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002727 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002728 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002729
2730 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2731 {
2732 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002733 n = partial_name(pt);
2734 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002735 rettv->vval.v_string = NULL;
2736 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002737 {
2738 rettv->vval.v_string = vim_strsave(n);
2739 if (rettv->v_type == VAR_FUNC)
2740 func_ref(rettv->vval.v_string);
2741 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002742 }
2743 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002744 {
2745 what_is_dict = TRUE;
2746 if (pt->pt_dict != NULL)
2747 rettv_dict_set(rettv, pt->pt_dict);
2748 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002749 else if (STRCMP(what, "args") == 0)
2750 {
2751 rettv->v_type = VAR_LIST;
2752 if (rettv_list_alloc(rettv) == OK)
2753 {
2754 int i;
2755
2756 for (i = 0; i < pt->pt_argc; ++i)
2757 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2758 }
2759 }
2760 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002761 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002762
2763 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2764 // third argument
2765 if (!what_is_dict)
2766 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002767 }
2768 }
2769 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002770 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002771
2772 if (tv == NULL)
2773 {
2774 if (argvars[2].v_type != VAR_UNKNOWN)
2775 copy_tv(&argvars[2], rettv);
2776 }
2777 else
2778 copy_tv(tv, rettv);
2779}
2780
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002781/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002782 * "getchangelist()" function
2783 */
2784 static void
2785f_getchangelist(typval_T *argvars, typval_T *rettv)
2786{
2787#ifdef FEAT_JUMPLIST
2788 buf_T *buf;
2789 int i;
2790 list_T *l;
2791 dict_T *d;
2792#endif
2793
2794 if (rettv_list_alloc(rettv) != OK)
2795 return;
2796
2797#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002798 if (argvars[0].v_type == VAR_UNKNOWN)
2799 buf = curbuf;
2800 else
2801 {
2802 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2803 ++emsg_off;
2804 buf = tv_get_buf(&argvars[0], FALSE);
2805 --emsg_off;
2806 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002807 if (buf == NULL)
2808 return;
2809
2810 l = list_alloc();
2811 if (l == NULL)
2812 return;
2813
2814 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2815 return;
2816 /*
2817 * The current window change list index tracks only the position in the
2818 * current buffer change list. For other buffers, use the change list
2819 * length as the current index.
2820 */
2821 list_append_number(rettv->vval.v_list,
2822 (varnumber_T)((buf == curwin->w_buffer)
2823 ? curwin->w_changelistidx : buf->b_changelistlen));
2824
2825 for (i = 0; i < buf->b_changelistlen; ++i)
2826 {
2827 if (buf->b_changelist[i].lnum == 0)
2828 continue;
2829 if ((d = dict_alloc()) == NULL)
2830 return;
2831 if (list_append_dict(l, d) == FAIL)
2832 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002833 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2834 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002835 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002836 }
2837#endif
2838}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002839
2840/*
2841 * "getcharsearch()" function
2842 */
2843 static void
2844f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2845{
2846 if (rettv_dict_alloc(rettv) != FAIL)
2847 {
2848 dict_T *dict = rettv->vval.v_dict;
2849
Bram Moolenaare0be1672018-07-08 16:50:37 +02002850 dict_add_string(dict, "char", last_csearch());
2851 dict_add_number(dict, "forward", last_csearch_forward());
2852 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002853 }
2854}
2855
2856/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002857 * "getcmdwintype()" function
2858 */
2859 static void
2860f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2861{
2862 rettv->v_type = VAR_STRING;
2863 rettv->vval.v_string = NULL;
2864#ifdef FEAT_CMDWIN
2865 rettv->vval.v_string = alloc(2);
2866 if (rettv->vval.v_string != NULL)
2867 {
2868 rettv->vval.v_string[0] = cmdwin_type;
2869 rettv->vval.v_string[1] = NUL;
2870 }
2871#endif
2872}
2873
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002874/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002875 * "getenv()" function
2876 */
2877 static void
2878f_getenv(typval_T *argvars, typval_T *rettv)
2879{
2880 int mustfree = FALSE;
2881 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2882
2883 if (p == NULL)
2884 {
2885 rettv->v_type = VAR_SPECIAL;
2886 rettv->vval.v_number = VVAL_NULL;
2887 return;
2888 }
2889 if (!mustfree)
2890 p = vim_strsave(p);
2891 rettv->vval.v_string = p;
2892 rettv->v_type = VAR_STRING;
2893}
2894
2895/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002896 * "getfontname()" function
2897 */
2898 static void
2899f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2900{
2901 rettv->v_type = VAR_STRING;
2902 rettv->vval.v_string = NULL;
2903#ifdef FEAT_GUI
2904 if (gui.in_use)
2905 {
2906 GuiFont font;
2907 char_u *name = NULL;
2908
2909 if (argvars[0].v_type == VAR_UNKNOWN)
2910 {
2911 /* Get the "Normal" font. Either the name saved by
2912 * hl_set_font_name() or from the font ID. */
2913 font = gui.norm_font;
2914 name = hl_get_font_name();
2915 }
2916 else
2917 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002918 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002919 if (STRCMP(name, "*") == 0) /* don't use font dialog */
2920 return;
2921 font = gui_mch_get_font(name, FALSE);
2922 if (font == NOFONT)
2923 return; /* Invalid font name, return empty string. */
2924 }
2925 rettv->vval.v_string = gui_mch_get_fontname(font, name);
2926 if (argvars[0].v_type != VAR_UNKNOWN)
2927 gui_mch_free_font(font);
2928 }
2929#endif
2930}
2931
2932/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01002933 * "getjumplist()" function
2934 */
2935 static void
2936f_getjumplist(typval_T *argvars, typval_T *rettv)
2937{
2938#ifdef FEAT_JUMPLIST
2939 win_T *wp;
2940 int i;
2941 list_T *l;
2942 dict_T *d;
2943#endif
2944
2945 if (rettv_list_alloc(rettv) != OK)
2946 return;
2947
2948#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02002949 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002950 if (wp == NULL)
2951 return;
2952
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01002953 cleanup_jumplist(wp, TRUE);
2954
Bram Moolenaar4f505882018-02-10 21:06:32 +01002955 l = list_alloc();
2956 if (l == NULL)
2957 return;
2958
2959 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2960 return;
2961 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
2962
2963 for (i = 0; i < wp->w_jumplistlen; ++i)
2964 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002965 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
2966 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01002967 if ((d = dict_alloc()) == NULL)
2968 return;
2969 if (list_append_dict(l, d) == FAIL)
2970 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002971 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
2972 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002973 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002974 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002975 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02002976 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002977 }
2978#endif
2979}
2980
2981/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002982 * "getpid()" function
2983 */
2984 static void
2985f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
2986{
2987 rettv->vval.v_number = mch_get_pid();
2988}
2989
2990 static void
2991getpos_both(
2992 typval_T *argvars,
2993 typval_T *rettv,
2994 int getcurpos)
2995{
2996 pos_T *fp;
2997 list_T *l;
2998 int fnum = -1;
2999
3000 if (rettv_list_alloc(rettv) == OK)
3001 {
3002 l = rettv->vval.v_list;
3003 if (getcurpos)
3004 fp = &curwin->w_cursor;
3005 else
3006 fp = var2fpos(&argvars[0], TRUE, &fnum);
3007 if (fnum != -1)
3008 list_append_number(l, (varnumber_T)fnum);
3009 else
3010 list_append_number(l, (varnumber_T)0);
3011 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3012 : (varnumber_T)0);
3013 list_append_number(l, (fp != NULL)
3014 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3015 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003016 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003017 (varnumber_T)0);
3018 if (getcurpos)
3019 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003020 int save_set_curswant = curwin->w_set_curswant;
3021 colnr_T save_curswant = curwin->w_curswant;
3022 colnr_T save_virtcol = curwin->w_virtcol;
3023
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003024 update_curswant();
3025 list_append_number(l, curwin->w_curswant == MAXCOL ?
3026 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003027
3028 // Do not change "curswant", as it is unexpected that a get
3029 // function has a side effect.
3030 if (save_set_curswant)
3031 {
3032 curwin->w_set_curswant = save_set_curswant;
3033 curwin->w_curswant = save_curswant;
3034 curwin->w_virtcol = save_virtcol;
3035 curwin->w_valid &= ~VALID_VIRTCOL;
3036 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003037 }
3038 }
3039 else
3040 rettv->vval.v_number = FALSE;
3041}
3042
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003043/*
3044 * "getcurpos()" function
3045 */
3046 static void
3047f_getcurpos(typval_T *argvars, typval_T *rettv)
3048{
3049 getpos_both(argvars, rettv, TRUE);
3050}
3051
3052/*
3053 * "getpos(string)" function
3054 */
3055 static void
3056f_getpos(typval_T *argvars, typval_T *rettv)
3057{
3058 getpos_both(argvars, rettv, FALSE);
3059}
3060
3061/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062 * "getreg()" function
3063 */
3064 static void
3065f_getreg(typval_T *argvars, typval_T *rettv)
3066{
3067 char_u *strregname;
3068 int regname;
3069 int arg2 = FALSE;
3070 int return_list = FALSE;
3071 int error = FALSE;
3072
3073 if (argvars[0].v_type != VAR_UNKNOWN)
3074 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003075 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003076 error = strregname == NULL;
3077 if (argvars[1].v_type != VAR_UNKNOWN)
3078 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003079 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003080 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003081 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003082 }
3083 }
3084 else
3085 strregname = get_vim_var_str(VV_REG);
3086
3087 if (error)
3088 return;
3089
3090 regname = (strregname == NULL ? '"' : *strregname);
3091 if (regname == 0)
3092 regname = '"';
3093
3094 if (return_list)
3095 {
3096 rettv->v_type = VAR_LIST;
3097 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3098 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3099 if (rettv->vval.v_list == NULL)
3100 (void)rettv_list_alloc(rettv);
3101 else
3102 ++rettv->vval.v_list->lv_refcount;
3103 }
3104 else
3105 {
3106 rettv->v_type = VAR_STRING;
3107 rettv->vval.v_string = get_reg_contents(regname,
3108 arg2 ? GREG_EXPR_SRC : 0);
3109 }
3110}
3111
3112/*
3113 * "getregtype()" function
3114 */
3115 static void
3116f_getregtype(typval_T *argvars, typval_T *rettv)
3117{
3118 char_u *strregname;
3119 int regname;
3120 char_u buf[NUMBUFLEN + 2];
3121 long reglen = 0;
3122
3123 if (argvars[0].v_type != VAR_UNKNOWN)
3124 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003125 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003126 if (strregname == NULL) /* type error; errmsg already given */
3127 {
3128 rettv->v_type = VAR_STRING;
3129 rettv->vval.v_string = NULL;
3130 return;
3131 }
3132 }
3133 else
3134 /* Default to v:register */
3135 strregname = get_vim_var_str(VV_REG);
3136
3137 regname = (strregname == NULL ? '"' : *strregname);
3138 if (regname == 0)
3139 regname = '"';
3140
3141 buf[0] = NUL;
3142 buf[1] = NUL;
3143 switch (get_reg_type(regname, &reglen))
3144 {
3145 case MLINE: buf[0] = 'V'; break;
3146 case MCHAR: buf[0] = 'v'; break;
3147 case MBLOCK:
3148 buf[0] = Ctrl_V;
3149 sprintf((char *)buf + 1, "%ld", reglen + 1);
3150 break;
3151 }
3152 rettv->v_type = VAR_STRING;
3153 rettv->vval.v_string = vim_strsave(buf);
3154}
3155
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003156/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003157 * "gettagstack()" function
3158 */
3159 static void
3160f_gettagstack(typval_T *argvars, typval_T *rettv)
3161{
3162 win_T *wp = curwin; // default is current window
3163
3164 if (rettv_dict_alloc(rettv) != OK)
3165 return;
3166
3167 if (argvars[0].v_type != VAR_UNKNOWN)
3168 {
3169 wp = find_win_by_nr_or_id(&argvars[0]);
3170 if (wp == NULL)
3171 return;
3172 }
3173
3174 get_tagstack(wp, rettv->vval.v_dict);
3175}
3176
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003177/* for VIM_VERSION_ defines */
3178#include "version.h"
3179
3180/*
3181 * "has()" function
3182 */
3183 static void
3184f_has(typval_T *argvars, typval_T *rettv)
3185{
3186 int i;
3187 char_u *name;
3188 int n = FALSE;
3189 static char *(has_list[]) =
3190 {
3191#ifdef AMIGA
3192 "amiga",
3193# ifdef FEAT_ARP
3194 "arp",
3195# endif
3196#endif
3197#ifdef __BEOS__
3198 "beos",
3199#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003200#if defined(BSD) && !defined(MACOS_X)
3201 "bsd",
3202#endif
3203#ifdef hpux
3204 "hpux",
3205#endif
3206#ifdef __linux__
3207 "linux",
3208#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003209#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003210 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3211 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003212# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003213 "macunix", /* Mac OS X, with the darwin feature */
3214 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003215# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003216#endif
3217#ifdef __QNX__
3218 "qnx",
3219#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003220#ifdef SUN_SYSTEM
3221 "sun",
3222#else
3223 "moon",
3224#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003225#ifdef UNIX
3226 "unix",
3227#endif
3228#ifdef VMS
3229 "vms",
3230#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003231#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003232 "win32",
3233#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003234#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003235 "win32unix",
3236#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003237#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 "win64",
3239#endif
3240#ifdef EBCDIC
3241 "ebcdic",
3242#endif
3243#ifndef CASE_INSENSITIVE_FILENAME
3244 "fname_case",
3245#endif
3246#ifdef HAVE_ACL
3247 "acl",
3248#endif
3249#ifdef FEAT_ARABIC
3250 "arabic",
3251#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003252 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003253#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003254 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003255#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003256#ifdef FEAT_AUTOSERVERNAME
3257 "autoservername",
3258#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003259#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003260 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003261# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003262 "balloon_multiline",
3263# endif
3264#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003265#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003266 "balloon_eval_term",
3267#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003268#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3269 "builtin_terms",
3270# ifdef ALL_BUILTIN_TCAPS
3271 "all_builtin_terms",
3272# endif
3273#endif
3274#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003275 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003276 || defined(FEAT_GUI_MOTIF))
3277 "browsefilter",
3278#endif
3279#ifdef FEAT_BYTEOFF
3280 "byte_offset",
3281#endif
3282#ifdef FEAT_JOB_CHANNEL
3283 "channel",
3284#endif
3285#ifdef FEAT_CINDENT
3286 "cindent",
3287#endif
3288#ifdef FEAT_CLIENTSERVER
3289 "clientserver",
3290#endif
3291#ifdef FEAT_CLIPBOARD
3292 "clipboard",
3293#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003294 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003295 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003296 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297#ifdef FEAT_CONCEAL
3298 "conceal",
3299#endif
3300#ifdef FEAT_CRYPT
3301 "cryptv",
3302 "crypt-blowfish",
3303 "crypt-blowfish2",
3304#endif
3305#ifdef FEAT_CSCOPE
3306 "cscope",
3307#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003309#ifdef CURSOR_SHAPE
3310 "cursorshape",
3311#endif
3312#ifdef DEBUG
3313 "debug",
3314#endif
3315#ifdef FEAT_CON_DIALOG
3316 "dialog_con",
3317#endif
3318#ifdef FEAT_GUI_DIALOG
3319 "dialog_gui",
3320#endif
3321#ifdef FEAT_DIFF
3322 "diff",
3323#endif
3324#ifdef FEAT_DIGRAPHS
3325 "digraphs",
3326#endif
3327#ifdef FEAT_DIRECTX
3328 "directx",
3329#endif
3330#ifdef FEAT_DND
3331 "dnd",
3332#endif
3333#ifdef FEAT_EMACS_TAGS
3334 "emacs_tags",
3335#endif
3336 "eval", /* always present, of course! */
3337 "ex_extra", /* graduated feature */
3338#ifdef FEAT_SEARCH_EXTRA
3339 "extra_search",
3340#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003341#ifdef FEAT_SEARCHPATH
3342 "file_in_path",
3343#endif
3344#ifdef FEAT_FILTERPIPE
3345 "filterpipe",
3346#endif
3347#ifdef FEAT_FIND_ID
3348 "find_in_path",
3349#endif
3350#ifdef FEAT_FLOAT
3351 "float",
3352#endif
3353#ifdef FEAT_FOLDING
3354 "folding",
3355#endif
3356#ifdef FEAT_FOOTER
3357 "footer",
3358#endif
3359#if !defined(USE_SYSTEM) && defined(UNIX)
3360 "fork",
3361#endif
3362#ifdef FEAT_GETTEXT
3363 "gettext",
3364#endif
3365#ifdef FEAT_GUI
3366 "gui",
3367#endif
3368#ifdef FEAT_GUI_ATHENA
3369# ifdef FEAT_GUI_NEXTAW
3370 "gui_neXtaw",
3371# else
3372 "gui_athena",
3373# endif
3374#endif
3375#ifdef FEAT_GUI_GTK
3376 "gui_gtk",
3377# ifdef USE_GTK3
3378 "gui_gtk3",
3379# else
3380 "gui_gtk2",
3381# endif
3382#endif
3383#ifdef FEAT_GUI_GNOME
3384 "gui_gnome",
3385#endif
3386#ifdef FEAT_GUI_MAC
3387 "gui_mac",
3388#endif
3389#ifdef FEAT_GUI_MOTIF
3390 "gui_motif",
3391#endif
3392#ifdef FEAT_GUI_PHOTON
3393 "gui_photon",
3394#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003395#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003396 "gui_win32",
3397#endif
3398#ifdef FEAT_HANGULIN
3399 "hangul_input",
3400#endif
3401#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3402 "iconv",
3403#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003404 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003405#ifdef FEAT_JOB_CHANNEL
3406 "job",
3407#endif
3408#ifdef FEAT_JUMPLIST
3409 "jumplist",
3410#endif
3411#ifdef FEAT_KEYMAP
3412 "keymap",
3413#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003414 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003415#ifdef FEAT_LANGMAP
3416 "langmap",
3417#endif
3418#ifdef FEAT_LIBCALL
3419 "libcall",
3420#endif
3421#ifdef FEAT_LINEBREAK
3422 "linebreak",
3423#endif
3424#ifdef FEAT_LISP
3425 "lispindent",
3426#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003427 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003429#ifdef FEAT_LUA
3430# ifndef DYNAMIC_LUA
3431 "lua",
3432# endif
3433#endif
3434#ifdef FEAT_MENU
3435 "menu",
3436#endif
3437#ifdef FEAT_SESSION
3438 "mksession",
3439#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003440 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003441 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003442#ifdef FEAT_MOUSESHAPE
3443 "mouseshape",
3444#endif
3445#if defined(UNIX) || defined(VMS)
3446# ifdef FEAT_MOUSE_DEC
3447 "mouse_dec",
3448# endif
3449# ifdef FEAT_MOUSE_GPM
3450 "mouse_gpm",
3451# endif
3452# ifdef FEAT_MOUSE_JSB
3453 "mouse_jsbterm",
3454# endif
3455# ifdef FEAT_MOUSE_NET
3456 "mouse_netterm",
3457# endif
3458# ifdef FEAT_MOUSE_PTERM
3459 "mouse_pterm",
3460# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003461# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003462 "mouse_sgr",
3463# endif
3464# ifdef FEAT_SYSMOUSE
3465 "mouse_sysmouse",
3466# endif
3467# ifdef FEAT_MOUSE_URXVT
3468 "mouse_urxvt",
3469# endif
3470# ifdef FEAT_MOUSE_XTERM
3471 "mouse_xterm",
3472# endif
3473#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003474 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003475#ifdef FEAT_MBYTE_IME
3476 "multi_byte_ime",
3477#endif
3478#ifdef FEAT_MULTI_LANG
3479 "multi_lang",
3480#endif
3481#ifdef FEAT_MZSCHEME
3482#ifndef DYNAMIC_MZSCHEME
3483 "mzscheme",
3484#endif
3485#endif
3486#ifdef FEAT_NUM64
3487 "num64",
3488#endif
3489#ifdef FEAT_OLE
3490 "ole",
3491#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003492#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003493 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003494#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003495#ifdef FEAT_PATH_EXTRA
3496 "path_extra",
3497#endif
3498#ifdef FEAT_PERL
3499#ifndef DYNAMIC_PERL
3500 "perl",
3501#endif
3502#endif
3503#ifdef FEAT_PERSISTENT_UNDO
3504 "persistent_undo",
3505#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003506#if defined(FEAT_PYTHON)
3507 "python_compiled",
3508# if defined(DYNAMIC_PYTHON)
3509 "python_dynamic",
3510# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003511 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003512 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003513# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003514#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003515#if defined(FEAT_PYTHON3)
3516 "python3_compiled",
3517# if defined(DYNAMIC_PYTHON3)
3518 "python3_dynamic",
3519# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003521 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003522# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003523#endif
3524#ifdef FEAT_POSTSCRIPT
3525 "postscript",
3526#endif
3527#ifdef FEAT_PRINTER
3528 "printer",
3529#endif
3530#ifdef FEAT_PROFILE
3531 "profile",
3532#endif
3533#ifdef FEAT_RELTIME
3534 "reltime",
3535#endif
3536#ifdef FEAT_QUICKFIX
3537 "quickfix",
3538#endif
3539#ifdef FEAT_RIGHTLEFT
3540 "rightleft",
3541#endif
3542#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3543 "ruby",
3544#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003545 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546#ifdef FEAT_CMDL_INFO
3547 "showcmd",
3548 "cmdline_info",
3549#endif
3550#ifdef FEAT_SIGNS
3551 "signs",
3552#endif
3553#ifdef FEAT_SMARTINDENT
3554 "smartindent",
3555#endif
3556#ifdef STARTUPTIME
3557 "startuptime",
3558#endif
3559#ifdef FEAT_STL_OPT
3560 "statusline",
3561#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003562#ifdef FEAT_NETBEANS_INTG
3563 "netbeans_intg",
3564#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003565#ifdef FEAT_SOUND
3566 "sound",
3567#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568#ifdef FEAT_SPELL
3569 "spell",
3570#endif
3571#ifdef FEAT_SYN_HL
3572 "syntax",
3573#endif
3574#if defined(USE_SYSTEM) || !defined(UNIX)
3575 "system",
3576#endif
3577#ifdef FEAT_TAG_BINS
3578 "tag_binary",
3579#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003580#ifdef FEAT_TCL
3581# ifndef DYNAMIC_TCL
3582 "tcl",
3583# endif
3584#endif
3585#ifdef FEAT_TERMGUICOLORS
3586 "termguicolors",
3587#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003588#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003589 "terminal",
3590#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003591#ifdef TERMINFO
3592 "terminfo",
3593#endif
3594#ifdef FEAT_TERMRESPONSE
3595 "termresponse",
3596#endif
3597#ifdef FEAT_TEXTOBJ
3598 "textobjects",
3599#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003600#ifdef FEAT_TEXT_PROP
3601 "textprop",
3602#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603#ifdef HAVE_TGETENT
3604 "tgetent",
3605#endif
3606#ifdef FEAT_TIMERS
3607 "timers",
3608#endif
3609#ifdef FEAT_TITLE
3610 "title",
3611#endif
3612#ifdef FEAT_TOOLBAR
3613 "toolbar",
3614#endif
3615#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3616 "unnamedplus",
3617#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003618 "user-commands", /* was accidentally included in 5.4 */
3619 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003620#ifdef FEAT_VARTABS
3621 "vartabs",
3622#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003623 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003624#ifdef FEAT_VIMINFO
3625 "viminfo",
3626#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003627 "vimscript-1",
3628 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003629 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003630 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003631 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003632 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003633 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003634 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003635#ifdef FEAT_VTP
3636 "vtp",
3637#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003638#ifdef FEAT_WILDIGN
3639 "wildignore",
3640#endif
3641#ifdef FEAT_WILDMENU
3642 "wildmenu",
3643#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003645#ifdef FEAT_WAK
3646 "winaltkeys",
3647#endif
3648#ifdef FEAT_WRITEBACKUP
3649 "writebackup",
3650#endif
3651#ifdef FEAT_XIM
3652 "xim",
3653#endif
3654#ifdef FEAT_XFONTSET
3655 "xfontset",
3656#endif
3657#ifdef FEAT_XPM_W32
3658 "xpm",
3659 "xpm_w32", /* for backward compatibility */
3660#else
3661# if defined(HAVE_XPM)
3662 "xpm",
3663# endif
3664#endif
3665#ifdef USE_XSMP
3666 "xsmp",
3667#endif
3668#ifdef USE_XSMP_INTERACT
3669 "xsmp_interact",
3670#endif
3671#ifdef FEAT_XCLIPBOARD
3672 "xterm_clipboard",
3673#endif
3674#ifdef FEAT_XTERM_SAVE
3675 "xterm_save",
3676#endif
3677#if defined(UNIX) && defined(FEAT_X11)
3678 "X11",
3679#endif
3680 NULL
3681 };
3682
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003683 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003684 for (i = 0; has_list[i] != NULL; ++i)
3685 if (STRICMP(name, has_list[i]) == 0)
3686 {
3687 n = TRUE;
3688 break;
3689 }
3690
3691 if (n == FALSE)
3692 {
3693 if (STRNICMP(name, "patch", 5) == 0)
3694 {
3695 if (name[5] == '-'
3696 && STRLEN(name) >= 11
3697 && vim_isdigit(name[6])
3698 && vim_isdigit(name[8])
3699 && vim_isdigit(name[10]))
3700 {
3701 int major = atoi((char *)name + 6);
3702 int minor = atoi((char *)name + 8);
3703
3704 /* Expect "patch-9.9.01234". */
3705 n = (major < VIM_VERSION_MAJOR
3706 || (major == VIM_VERSION_MAJOR
3707 && (minor < VIM_VERSION_MINOR
3708 || (minor == VIM_VERSION_MINOR
3709 && has_patch(atoi((char *)name + 10))))));
3710 }
3711 else
3712 n = has_patch(atoi((char *)name + 5));
3713 }
3714 else if (STRICMP(name, "vim_starting") == 0)
3715 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003716 else if (STRICMP(name, "ttyin") == 0)
3717 n = mch_input_isatty();
3718 else if (STRICMP(name, "ttyout") == 0)
3719 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720 else if (STRICMP(name, "multi_byte_encoding") == 0)
3721 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003722#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003723 else if (STRICMP(name, "balloon_multiline") == 0)
3724 n = multiline_balloon_available();
3725#endif
3726#ifdef DYNAMIC_TCL
3727 else if (STRICMP(name, "tcl") == 0)
3728 n = tcl_enabled(FALSE);
3729#endif
3730#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3731 else if (STRICMP(name, "iconv") == 0)
3732 n = iconv_enabled(FALSE);
3733#endif
3734#ifdef DYNAMIC_LUA
3735 else if (STRICMP(name, "lua") == 0)
3736 n = lua_enabled(FALSE);
3737#endif
3738#ifdef DYNAMIC_MZSCHEME
3739 else if (STRICMP(name, "mzscheme") == 0)
3740 n = mzscheme_enabled(FALSE);
3741#endif
3742#ifdef DYNAMIC_RUBY
3743 else if (STRICMP(name, "ruby") == 0)
3744 n = ruby_enabled(FALSE);
3745#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003746#ifdef DYNAMIC_PYTHON
3747 else if (STRICMP(name, "python") == 0)
3748 n = python_enabled(FALSE);
3749#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003750#ifdef DYNAMIC_PYTHON3
3751 else if (STRICMP(name, "python3") == 0)
3752 n = python3_enabled(FALSE);
3753#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003754#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3755 else if (STRICMP(name, "pythonx") == 0)
3756 {
3757# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3758 if (p_pyx == 0)
3759 n = python3_enabled(FALSE) || python_enabled(FALSE);
3760 else if (p_pyx == 3)
3761 n = python3_enabled(FALSE);
3762 else if (p_pyx == 2)
3763 n = python_enabled(FALSE);
3764# elif defined(DYNAMIC_PYTHON)
3765 n = python_enabled(FALSE);
3766# elif defined(DYNAMIC_PYTHON3)
3767 n = python3_enabled(FALSE);
3768# endif
3769 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003770#endif
3771#ifdef DYNAMIC_PERL
3772 else if (STRICMP(name, "perl") == 0)
3773 n = perl_enabled(FALSE);
3774#endif
3775#ifdef FEAT_GUI
3776 else if (STRICMP(name, "gui_running") == 0)
3777 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003778# ifdef FEAT_BROWSE
3779 else if (STRICMP(name, "browse") == 0)
3780 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3781# endif
3782#endif
3783#ifdef FEAT_SYN_HL
3784 else if (STRICMP(name, "syntax_items") == 0)
3785 n = syntax_present(curwin);
3786#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003787#ifdef FEAT_VTP
3788 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003789 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003790#endif
3791#ifdef FEAT_NETBEANS_INTG
3792 else if (STRICMP(name, "netbeans_enabled") == 0)
3793 n = netbeans_active();
3794#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003795#ifdef FEAT_MOUSE_GPM
3796 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3797 n = gpm_enabled();
3798#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003799#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003800 else if (STRICMP(name, "terminal") == 0)
3801 n = terminal_enabled();
3802#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003803#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003804 else if (STRICMP(name, "conpty") == 0)
3805 n = use_conpty();
3806#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003807#ifdef FEAT_CLIPBOARD
3808 else if (STRICMP(name, "clipboard_working") == 0)
3809 n = clip_star.available;
3810#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003811 }
3812
3813 rettv->vval.v_number = n;
3814}
3815
3816/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003817 * "haslocaldir()" function
3818 */
3819 static void
3820f_haslocaldir(typval_T *argvars, typval_T *rettv)
3821{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003822 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003823 win_T *wp = NULL;
3824
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003825 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3826
3827 // Check for window-local and tab-local directories
3828 if (wp != NULL && wp->w_localdir != NULL)
3829 rettv->vval.v_number = 1;
3830 else if (tp != NULL && tp->tp_localdir != NULL)
3831 rettv->vval.v_number = 2;
3832 else
3833 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003834}
3835
3836/*
3837 * "hasmapto()" function
3838 */
3839 static void
3840f_hasmapto(typval_T *argvars, typval_T *rettv)
3841{
3842 char_u *name;
3843 char_u *mode;
3844 char_u buf[NUMBUFLEN];
3845 int abbr = FALSE;
3846
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003847 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003848 if (argvars[1].v_type == VAR_UNKNOWN)
3849 mode = (char_u *)"nvo";
3850 else
3851 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003852 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003853 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003854 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003855 }
3856
3857 if (map_to_exists(name, mode, abbr))
3858 rettv->vval.v_number = TRUE;
3859 else
3860 rettv->vval.v_number = FALSE;
3861}
3862
3863/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003864 * "highlightID(name)" function
3865 */
3866 static void
3867f_hlID(typval_T *argvars, typval_T *rettv)
3868{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003869 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003870}
3871
3872/*
3873 * "highlight_exists()" function
3874 */
3875 static void
3876f_hlexists(typval_T *argvars, typval_T *rettv)
3877{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003878 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003879}
3880
3881/*
3882 * "hostname()" function
3883 */
3884 static void
3885f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3886{
3887 char_u hostname[256];
3888
3889 mch_get_host_name(hostname, 256);
3890 rettv->v_type = VAR_STRING;
3891 rettv->vval.v_string = vim_strsave(hostname);
3892}
3893
3894/*
3895 * iconv() function
3896 */
3897 static void
3898f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3899{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003900 char_u buf1[NUMBUFLEN];
3901 char_u buf2[NUMBUFLEN];
3902 char_u *from, *to, *str;
3903 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003904
3905 rettv->v_type = VAR_STRING;
3906 rettv->vval.v_string = NULL;
3907
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003908 str = tv_get_string(&argvars[0]);
3909 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3910 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003911 vimconv.vc_type = CONV_NONE;
3912 convert_setup(&vimconv, from, to);
3913
3914 /* If the encodings are equal, no conversion needed. */
3915 if (vimconv.vc_type == CONV_NONE)
3916 rettv->vval.v_string = vim_strsave(str);
3917 else
3918 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
3919
3920 convert_setup(&vimconv, NULL, NULL);
3921 vim_free(from);
3922 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003923}
3924
3925/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003926 * "index()" function
3927 */
3928 static void
3929f_index(typval_T *argvars, typval_T *rettv)
3930{
3931 list_T *l;
3932 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003933 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934 long idx = 0;
3935 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003936 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003937
3938 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003939 if (argvars[0].v_type == VAR_BLOB)
3940 {
3941 typval_T tv;
3942 int start = 0;
3943
3944 if (argvars[2].v_type != VAR_UNKNOWN)
3945 {
3946 start = tv_get_number_chk(&argvars[2], &error);
3947 if (error)
3948 return;
3949 }
3950 b = argvars[0].vval.v_blob;
3951 if (b == NULL)
3952 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01003953 if (start < 0)
3954 {
3955 start = blob_len(b) + start;
3956 if (start < 0)
3957 start = 0;
3958 }
3959
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003960 for (idx = start; idx < blob_len(b); ++idx)
3961 {
3962 tv.v_type = VAR_NUMBER;
3963 tv.vval.v_number = blob_get(b, idx);
3964 if (tv_equal(&tv, &argvars[1], ic, FALSE))
3965 {
3966 rettv->vval.v_number = idx;
3967 return;
3968 }
3969 }
3970 return;
3971 }
3972 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003973 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003974 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003975 return;
3976 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003977
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003978 l = argvars[0].vval.v_list;
3979 if (l != NULL)
3980 {
3981 item = l->lv_first;
3982 if (argvars[2].v_type != VAR_UNKNOWN)
3983 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984 /* Start at specified item. Use the cached index that list_find()
3985 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003986 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003987 idx = l->lv_idx;
3988 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003989 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003990 if (error)
3991 item = NULL;
3992 }
3993
3994 for ( ; item != NULL; item = item->li_next, ++idx)
3995 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
3996 {
3997 rettv->vval.v_number = idx;
3998 break;
3999 }
4000 }
4001}
4002
4003static int inputsecret_flag = 0;
4004
4005/*
4006 * "input()" function
4007 * Also handles inputsecret() when inputsecret is set.
4008 */
4009 static void
4010f_input(typval_T *argvars, typval_T *rettv)
4011{
4012 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4013}
4014
4015/*
4016 * "inputdialog()" function
4017 */
4018 static void
4019f_inputdialog(typval_T *argvars, typval_T *rettv)
4020{
4021#if defined(FEAT_GUI_TEXTDIALOG)
4022 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4023 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4024 {
4025 char_u *message;
4026 char_u buf[NUMBUFLEN];
4027 char_u *defstr = (char_u *)"";
4028
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004029 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004030 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004031 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004032 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4033 else
4034 IObuff[0] = NUL;
4035 if (message != NULL && defstr != NULL
4036 && do_dialog(VIM_QUESTION, NULL, message,
4037 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4038 rettv->vval.v_string = vim_strsave(IObuff);
4039 else
4040 {
4041 if (message != NULL && defstr != NULL
4042 && argvars[1].v_type != VAR_UNKNOWN
4043 && argvars[2].v_type != VAR_UNKNOWN)
4044 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004045 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004046 else
4047 rettv->vval.v_string = NULL;
4048 }
4049 rettv->v_type = VAR_STRING;
4050 }
4051 else
4052#endif
4053 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4054}
4055
4056/*
4057 * "inputlist()" function
4058 */
4059 static void
4060f_inputlist(typval_T *argvars, typval_T *rettv)
4061{
4062 listitem_T *li;
4063 int selected;
4064 int mouse_used;
4065
4066#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004067 /* While starting up, there is no place to enter text. When running tests
4068 * with --not-a-term we assume feedkeys() will be used. */
4069 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 return;
4071#endif
4072 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4073 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004074 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004075 return;
4076 }
4077
4078 msg_start();
4079 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4080 lines_left = Rows; /* avoid more prompt */
4081 msg_scroll = TRUE;
4082 msg_clr_eos();
4083
4084 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4085 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004086 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004087 msg_putchar('\n');
4088 }
4089
4090 /* Ask for choice. */
4091 selected = prompt_for_number(&mouse_used);
4092 if (mouse_used)
4093 selected -= lines_left;
4094
4095 rettv->vval.v_number = selected;
4096}
4097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004098static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4099
4100/*
4101 * "inputrestore()" function
4102 */
4103 static void
4104f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4105{
4106 if (ga_userinput.ga_len > 0)
4107 {
4108 --ga_userinput.ga_len;
4109 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4110 + ga_userinput.ga_len);
4111 /* default return is zero == OK */
4112 }
4113 else if (p_verbose > 1)
4114 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004115 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004116 rettv->vval.v_number = 1; /* Failed */
4117 }
4118}
4119
4120/*
4121 * "inputsave()" function
4122 */
4123 static void
4124f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4125{
4126 /* Add an entry to the stack of typeahead storage. */
4127 if (ga_grow(&ga_userinput, 1) == OK)
4128 {
4129 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4130 + ga_userinput.ga_len);
4131 ++ga_userinput.ga_len;
4132 /* default return is zero == OK */
4133 }
4134 else
4135 rettv->vval.v_number = 1; /* Failed */
4136}
4137
4138/*
4139 * "inputsecret()" function
4140 */
4141 static void
4142f_inputsecret(typval_T *argvars, typval_T *rettv)
4143{
4144 ++cmdline_star;
4145 ++inputsecret_flag;
4146 f_input(argvars, rettv);
4147 --cmdline_star;
4148 --inputsecret_flag;
4149}
4150
4151/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004152 * "invert(expr)" function
4153 */
4154 static void
4155f_invert(typval_T *argvars, typval_T *rettv)
4156{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004157 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004158}
4159
4160/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004161 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4162 * or it refers to a List or Dictionary that is locked.
4163 */
4164 static int
4165tv_islocked(typval_T *tv)
4166{
4167 return (tv->v_lock & VAR_LOCKED)
4168 || (tv->v_type == VAR_LIST
4169 && tv->vval.v_list != NULL
4170 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4171 || (tv->v_type == VAR_DICT
4172 && tv->vval.v_dict != NULL
4173 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4174}
4175
4176/*
4177 * "islocked()" function
4178 */
4179 static void
4180f_islocked(typval_T *argvars, typval_T *rettv)
4181{
4182 lval_T lv;
4183 char_u *end;
4184 dictitem_T *di;
4185
4186 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004187 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004188 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004189 if (end != NULL && lv.ll_name != NULL)
4190 {
4191 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004192 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004193 else
4194 {
4195 if (lv.ll_tv == NULL)
4196 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004197 di = find_var(lv.ll_name, NULL, TRUE);
4198 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004199 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004200 /* Consider a variable locked when:
4201 * 1. the variable itself is locked
4202 * 2. the value of the variable is locked.
4203 * 3. the List or Dict value is locked.
4204 */
4205 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4206 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004207 }
4208 }
4209 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004210 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004211 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004212 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004213 else if (lv.ll_list != NULL)
4214 /* List item. */
4215 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4216 else
4217 /* Dictionary item. */
4218 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4219 }
4220 }
4221
4222 clear_lval(&lv);
4223}
4224
4225#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4226/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004227 * "isinf()" function
4228 */
4229 static void
4230f_isinf(typval_T *argvars, typval_T *rettv)
4231{
4232 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4233 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4234}
4235
4236/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004237 * "isnan()" function
4238 */
4239 static void
4240f_isnan(typval_T *argvars, typval_T *rettv)
4241{
4242 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4243 && isnan(argvars[0].vval.v_float);
4244}
4245#endif
4246
4247/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004248 * "last_buffer_nr()" function.
4249 */
4250 static void
4251f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4252{
4253 int n = 0;
4254 buf_T *buf;
4255
Bram Moolenaar29323592016-07-24 22:04:11 +02004256 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004257 if (n < buf->b_fnum)
4258 n = buf->b_fnum;
4259
4260 rettv->vval.v_number = n;
4261}
4262
4263/*
4264 * "len()" function
4265 */
4266 static void
4267f_len(typval_T *argvars, typval_T *rettv)
4268{
4269 switch (argvars[0].v_type)
4270 {
4271 case VAR_STRING:
4272 case VAR_NUMBER:
4273 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004274 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004275 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004276 case VAR_BLOB:
4277 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4278 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004279 case VAR_LIST:
4280 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4281 break;
4282 case VAR_DICT:
4283 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4284 break;
4285 case VAR_UNKNOWN:
4286 case VAR_SPECIAL:
4287 case VAR_FLOAT:
4288 case VAR_FUNC:
4289 case VAR_PARTIAL:
4290 case VAR_JOB:
4291 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004292 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004293 break;
4294 }
4295}
4296
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004297 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004298libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004299{
4300#ifdef FEAT_LIBCALL
4301 char_u *string_in;
4302 char_u **string_result;
4303 int nr_result;
4304#endif
4305
4306 rettv->v_type = type;
4307 if (type != VAR_NUMBER)
4308 rettv->vval.v_string = NULL;
4309
4310 if (check_restricted() || check_secure())
4311 return;
4312
4313#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004314 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004315 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4316 {
4317 string_in = NULL;
4318 if (argvars[2].v_type == VAR_STRING)
4319 string_in = argvars[2].vval.v_string;
4320 if (type == VAR_NUMBER)
4321 string_result = NULL;
4322 else
4323 string_result = &rettv->vval.v_string;
4324 if (mch_libcall(argvars[0].vval.v_string,
4325 argvars[1].vval.v_string,
4326 string_in,
4327 argvars[2].vval.v_number,
4328 string_result,
4329 &nr_result) == OK
4330 && type == VAR_NUMBER)
4331 rettv->vval.v_number = nr_result;
4332 }
4333#endif
4334}
4335
4336/*
4337 * "libcall()" function
4338 */
4339 static void
4340f_libcall(typval_T *argvars, typval_T *rettv)
4341{
4342 libcall_common(argvars, rettv, VAR_STRING);
4343}
4344
4345/*
4346 * "libcallnr()" function
4347 */
4348 static void
4349f_libcallnr(typval_T *argvars, typval_T *rettv)
4350{
4351 libcall_common(argvars, rettv, VAR_NUMBER);
4352}
4353
4354/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004355 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004356 */
4357 static void
4358f_line(typval_T *argvars, typval_T *rettv)
4359{
4360 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004361 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004362 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004363 int id;
4364 tabpage_T *tp;
4365 win_T *wp;
4366 win_T *save_curwin;
4367 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004368
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004369 if (argvars[1].v_type != VAR_UNKNOWN)
4370 {
4371 // use window specified in the second argument
4372 id = (int)tv_get_number(&argvars[1]);
4373 wp = win_id2wp_tp(id, &tp);
4374 if (wp != NULL && tp != NULL)
4375 {
4376 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4377 == OK)
4378 {
4379 check_cursor();
4380 fp = var2fpos(&argvars[0], TRUE, &fnum);
4381 }
4382 restore_win_noblock(save_curwin, save_curtab, TRUE);
4383 }
4384 }
4385 else
4386 // use current window
4387 fp = var2fpos(&argvars[0], TRUE, &fnum);
4388
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004389 if (fp != NULL)
4390 lnum = fp->lnum;
4391 rettv->vval.v_number = lnum;
4392}
4393
4394/*
4395 * "line2byte(lnum)" function
4396 */
4397 static void
4398f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4399{
4400#ifndef FEAT_BYTEOFF
4401 rettv->vval.v_number = -1;
4402#else
4403 linenr_T lnum;
4404
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004405 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004406 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4407 rettv->vval.v_number = -1;
4408 else
4409 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4410 if (rettv->vval.v_number >= 0)
4411 ++rettv->vval.v_number;
4412#endif
4413}
4414
4415/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004416 * "localtime()" function
4417 */
4418 static void
4419f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4420{
4421 rettv->vval.v_number = (varnumber_T)time(NULL);
4422}
4423
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004424#ifdef FEAT_FLOAT
4425/*
4426 * "log()" function
4427 */
4428 static void
4429f_log(typval_T *argvars, typval_T *rettv)
4430{
4431 float_T f = 0.0;
4432
4433 rettv->v_type = VAR_FLOAT;
4434 if (get_float_arg(argvars, &f) == OK)
4435 rettv->vval.v_float = log(f);
4436 else
4437 rettv->vval.v_float = 0.0;
4438}
4439
4440/*
4441 * "log10()" function
4442 */
4443 static void
4444f_log10(typval_T *argvars, typval_T *rettv)
4445{
4446 float_T f = 0.0;
4447
4448 rettv->v_type = VAR_FLOAT;
4449 if (get_float_arg(argvars, &f) == OK)
4450 rettv->vval.v_float = log10(f);
4451 else
4452 rettv->vval.v_float = 0.0;
4453}
4454#endif
4455
4456#ifdef FEAT_LUA
4457/*
4458 * "luaeval()" function
4459 */
4460 static void
4461f_luaeval(typval_T *argvars, typval_T *rettv)
4462{
4463 char_u *str;
4464 char_u buf[NUMBUFLEN];
4465
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004466 if (check_restricted() || check_secure())
4467 return;
4468
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004469 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004470 do_luaeval(str, argvars + 1, rettv);
4471}
4472#endif
4473
4474/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004475 * "maparg()" function
4476 */
4477 static void
4478f_maparg(typval_T *argvars, typval_T *rettv)
4479{
4480 get_maparg(argvars, rettv, TRUE);
4481}
4482
4483/*
4484 * "mapcheck()" function
4485 */
4486 static void
4487f_mapcheck(typval_T *argvars, typval_T *rettv)
4488{
4489 get_maparg(argvars, rettv, FALSE);
4490}
4491
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004492typedef enum
4493{
4494 MATCH_END, /* matchend() */
4495 MATCH_MATCH, /* match() */
4496 MATCH_STR, /* matchstr() */
4497 MATCH_LIST, /* matchlist() */
4498 MATCH_POS /* matchstrpos() */
4499} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004500
4501 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004502find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004503{
4504 char_u *str = NULL;
4505 long len = 0;
4506 char_u *expr = NULL;
4507 char_u *pat;
4508 regmatch_T regmatch;
4509 char_u patbuf[NUMBUFLEN];
4510 char_u strbuf[NUMBUFLEN];
4511 char_u *save_cpo;
4512 long start = 0;
4513 long nth = 1;
4514 colnr_T startcol = 0;
4515 int match = 0;
4516 list_T *l = NULL;
4517 listitem_T *li = NULL;
4518 long idx = 0;
4519 char_u *tofree = NULL;
4520
4521 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4522 save_cpo = p_cpo;
4523 p_cpo = (char_u *)"";
4524
4525 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004526 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004527 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004528 /* type MATCH_LIST: return empty list when there are no matches.
4529 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004530 if (rettv_list_alloc(rettv) == FAIL)
4531 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004532 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004533 && (list_append_string(rettv->vval.v_list,
4534 (char_u *)"", 0) == FAIL
4535 || list_append_number(rettv->vval.v_list,
4536 (varnumber_T)-1) == FAIL
4537 || list_append_number(rettv->vval.v_list,
4538 (varnumber_T)-1) == FAIL
4539 || list_append_number(rettv->vval.v_list,
4540 (varnumber_T)-1) == FAIL))
4541 {
4542 list_free(rettv->vval.v_list);
4543 rettv->vval.v_list = NULL;
4544 goto theend;
4545 }
4546 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004547 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004548 {
4549 rettv->v_type = VAR_STRING;
4550 rettv->vval.v_string = NULL;
4551 }
4552
4553 if (argvars[0].v_type == VAR_LIST)
4554 {
4555 if ((l = argvars[0].vval.v_list) == NULL)
4556 goto theend;
4557 li = l->lv_first;
4558 }
4559 else
4560 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004561 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004562 len = (long)STRLEN(str);
4563 }
4564
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004565 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004566 if (pat == NULL)
4567 goto theend;
4568
4569 if (argvars[2].v_type != VAR_UNKNOWN)
4570 {
4571 int error = FALSE;
4572
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004573 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004574 if (error)
4575 goto theend;
4576 if (l != NULL)
4577 {
4578 li = list_find(l, start);
4579 if (li == NULL)
4580 goto theend;
4581 idx = l->lv_idx; /* use the cached index */
4582 }
4583 else
4584 {
4585 if (start < 0)
4586 start = 0;
4587 if (start > len)
4588 goto theend;
4589 /* When "count" argument is there ignore matches before "start",
4590 * otherwise skip part of the string. Differs when pattern is "^"
4591 * or "\<". */
4592 if (argvars[3].v_type != VAR_UNKNOWN)
4593 startcol = start;
4594 else
4595 {
4596 str += start;
4597 len -= start;
4598 }
4599 }
4600
4601 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004602 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004603 if (error)
4604 goto theend;
4605 }
4606
4607 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4608 if (regmatch.regprog != NULL)
4609 {
4610 regmatch.rm_ic = p_ic;
4611
4612 for (;;)
4613 {
4614 if (l != NULL)
4615 {
4616 if (li == NULL)
4617 {
4618 match = FALSE;
4619 break;
4620 }
4621 vim_free(tofree);
4622 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4623 if (str == NULL)
4624 break;
4625 }
4626
4627 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4628
4629 if (match && --nth <= 0)
4630 break;
4631 if (l == NULL && !match)
4632 break;
4633
4634 /* Advance to just after the match. */
4635 if (l != NULL)
4636 {
4637 li = li->li_next;
4638 ++idx;
4639 }
4640 else
4641 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004642 startcol = (colnr_T)(regmatch.startp[0]
4643 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004644 if (startcol > (colnr_T)len
4645 || str + startcol <= regmatch.startp[0])
4646 {
4647 match = FALSE;
4648 break;
4649 }
4650 }
4651 }
4652
4653 if (match)
4654 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004655 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004656 {
4657 listitem_T *li1 = rettv->vval.v_list->lv_first;
4658 listitem_T *li2 = li1->li_next;
4659 listitem_T *li3 = li2->li_next;
4660 listitem_T *li4 = li3->li_next;
4661
4662 vim_free(li1->li_tv.vval.v_string);
4663 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4664 (int)(regmatch.endp[0] - regmatch.startp[0]));
4665 li3->li_tv.vval.v_number =
4666 (varnumber_T)(regmatch.startp[0] - expr);
4667 li4->li_tv.vval.v_number =
4668 (varnumber_T)(regmatch.endp[0] - expr);
4669 if (l != NULL)
4670 li2->li_tv.vval.v_number = (varnumber_T)idx;
4671 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004672 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004673 {
4674 int i;
4675
4676 /* return list with matched string and submatches */
4677 for (i = 0; i < NSUBEXP; ++i)
4678 {
4679 if (regmatch.endp[i] == NULL)
4680 {
4681 if (list_append_string(rettv->vval.v_list,
4682 (char_u *)"", 0) == FAIL)
4683 break;
4684 }
4685 else if (list_append_string(rettv->vval.v_list,
4686 regmatch.startp[i],
4687 (int)(regmatch.endp[i] - regmatch.startp[i]))
4688 == FAIL)
4689 break;
4690 }
4691 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004692 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 {
4694 /* return matched string */
4695 if (l != NULL)
4696 copy_tv(&li->li_tv, rettv);
4697 else
4698 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4699 (int)(regmatch.endp[0] - regmatch.startp[0]));
4700 }
4701 else if (l != NULL)
4702 rettv->vval.v_number = idx;
4703 else
4704 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004705 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004706 rettv->vval.v_number =
4707 (varnumber_T)(regmatch.startp[0] - str);
4708 else
4709 rettv->vval.v_number =
4710 (varnumber_T)(regmatch.endp[0] - str);
4711 rettv->vval.v_number += (varnumber_T)(str - expr);
4712 }
4713 }
4714 vim_regfree(regmatch.regprog);
4715 }
4716
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004717theend:
4718 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719 /* matchstrpos() without a list: drop the second item. */
4720 listitem_remove(rettv->vval.v_list,
4721 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004722 vim_free(tofree);
4723 p_cpo = save_cpo;
4724}
4725
4726/*
4727 * "match()" function
4728 */
4729 static void
4730f_match(typval_T *argvars, typval_T *rettv)
4731{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004732 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733}
4734
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004735/*
4736 * "matchend()" function
4737 */
4738 static void
4739f_matchend(typval_T *argvars, typval_T *rettv)
4740{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004741 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004742}
4743
4744/*
4745 * "matchlist()" function
4746 */
4747 static void
4748f_matchlist(typval_T *argvars, typval_T *rettv)
4749{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004750 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004751}
4752
4753/*
4754 * "matchstr()" function
4755 */
4756 static void
4757f_matchstr(typval_T *argvars, typval_T *rettv)
4758{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004759 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004760}
4761
4762/*
4763 * "matchstrpos()" function
4764 */
4765 static void
4766f_matchstrpos(typval_T *argvars, typval_T *rettv)
4767{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004768 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004769}
4770
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004771 static void
4772max_min(typval_T *argvars, typval_T *rettv, int domax)
4773{
4774 varnumber_T n = 0;
4775 varnumber_T i;
4776 int error = FALSE;
4777
4778 if (argvars[0].v_type == VAR_LIST)
4779 {
4780 list_T *l;
4781 listitem_T *li;
4782
4783 l = argvars[0].vval.v_list;
4784 if (l != NULL)
4785 {
4786 li = l->lv_first;
4787 if (li != NULL)
4788 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004789 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004790 for (;;)
4791 {
4792 li = li->li_next;
4793 if (li == NULL)
4794 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004795 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796 if (domax ? i > n : i < n)
4797 n = i;
4798 }
4799 }
4800 }
4801 }
4802 else if (argvars[0].v_type == VAR_DICT)
4803 {
4804 dict_T *d;
4805 int first = TRUE;
4806 hashitem_T *hi;
4807 int todo;
4808
4809 d = argvars[0].vval.v_dict;
4810 if (d != NULL)
4811 {
4812 todo = (int)d->dv_hashtab.ht_used;
4813 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4814 {
4815 if (!HASHITEM_EMPTY(hi))
4816 {
4817 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004818 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004819 if (first)
4820 {
4821 n = i;
4822 first = FALSE;
4823 }
4824 else if (domax ? i > n : i < n)
4825 n = i;
4826 }
4827 }
4828 }
4829 }
4830 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004831 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004832 rettv->vval.v_number = error ? 0 : n;
4833}
4834
4835/*
4836 * "max()" function
4837 */
4838 static void
4839f_max(typval_T *argvars, typval_T *rettv)
4840{
4841 max_min(argvars, rettv, TRUE);
4842}
4843
4844/*
4845 * "min()" function
4846 */
4847 static void
4848f_min(typval_T *argvars, typval_T *rettv)
4849{
4850 max_min(argvars, rettv, FALSE);
4851}
4852
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853#if defined(FEAT_MZSCHEME) || defined(PROTO)
4854/*
4855 * "mzeval()" function
4856 */
4857 static void
4858f_mzeval(typval_T *argvars, typval_T *rettv)
4859{
4860 char_u *str;
4861 char_u buf[NUMBUFLEN];
4862
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004863 if (check_restricted() || check_secure())
4864 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004865 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004866 do_mzeval(str, rettv);
4867}
4868
4869 void
4870mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4871{
4872 typval_T argvars[3];
4873
4874 argvars[0].v_type = VAR_STRING;
4875 argvars[0].vval.v_string = name;
4876 copy_tv(args, &argvars[1]);
4877 argvars[2].v_type = VAR_UNKNOWN;
4878 f_call(argvars, rettv);
4879 clear_tv(&argvars[1]);
4880}
4881#endif
4882
4883/*
4884 * "nextnonblank()" function
4885 */
4886 static void
4887f_nextnonblank(typval_T *argvars, typval_T *rettv)
4888{
4889 linenr_T lnum;
4890
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004891 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004892 {
4893 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
4894 {
4895 lnum = 0;
4896 break;
4897 }
4898 if (*skipwhite(ml_get(lnum)) != NUL)
4899 break;
4900 }
4901 rettv->vval.v_number = lnum;
4902}
4903
4904/*
4905 * "nr2char()" function
4906 */
4907 static void
4908f_nr2char(typval_T *argvars, typval_T *rettv)
4909{
4910 char_u buf[NUMBUFLEN];
4911
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004912 if (has_mbyte)
4913 {
4914 int utf8 = 0;
4915
4916 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004917 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004918 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01004919 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004920 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004921 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004922 }
4923 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004924 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004925 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004926 buf[1] = NUL;
4927 }
4928 rettv->v_type = VAR_STRING;
4929 rettv->vval.v_string = vim_strsave(buf);
4930}
4931
4932/*
4933 * "or(expr, expr)" function
4934 */
4935 static void
4936f_or(typval_T *argvars, typval_T *rettv)
4937{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004938 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
4939 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004940}
4941
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004942#ifdef FEAT_PERL
4943/*
4944 * "perleval()" function
4945 */
4946 static void
4947f_perleval(typval_T *argvars, typval_T *rettv)
4948{
4949 char_u *str;
4950 char_u buf[NUMBUFLEN];
4951
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004952 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004953 do_perleval(str, rettv);
4954}
4955#endif
4956
4957#ifdef FEAT_FLOAT
4958/*
4959 * "pow()" function
4960 */
4961 static void
4962f_pow(typval_T *argvars, typval_T *rettv)
4963{
4964 float_T fx = 0.0, fy = 0.0;
4965
4966 rettv->v_type = VAR_FLOAT;
4967 if (get_float_arg(argvars, &fx) == OK
4968 && get_float_arg(&argvars[1], &fy) == OK)
4969 rettv->vval.v_float = pow(fx, fy);
4970 else
4971 rettv->vval.v_float = 0.0;
4972}
4973#endif
4974
4975/*
4976 * "prevnonblank()" function
4977 */
4978 static void
4979f_prevnonblank(typval_T *argvars, typval_T *rettv)
4980{
4981 linenr_T lnum;
4982
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004983 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004984 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
4985 lnum = 0;
4986 else
4987 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
4988 --lnum;
4989 rettv->vval.v_number = lnum;
4990}
4991
4992/* This dummy va_list is here because:
4993 * - passing a NULL pointer doesn't work when va_list isn't a pointer
4994 * - locally in the function results in a "used before set" warning
4995 * - using va_start() to initialize it gives "function with fixed args" error */
4996static va_list ap;
4997
4998/*
4999 * "printf()" function
5000 */
5001 static void
5002f_printf(typval_T *argvars, typval_T *rettv)
5003{
5004 char_u buf[NUMBUFLEN];
5005 int len;
5006 char_u *s;
5007 int saved_did_emsg = did_emsg;
5008 char *fmt;
5009
5010 rettv->v_type = VAR_STRING;
5011 rettv->vval.v_string = NULL;
5012
5013 /* Get the required length, allocate the buffer and do it for real. */
5014 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005015 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005016 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005017 if (!did_emsg)
5018 {
5019 s = alloc(len + 1);
5020 if (s != NULL)
5021 {
5022 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005023 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5024 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005025 }
5026 }
5027 did_emsg |= saved_did_emsg;
5028}
5029
5030/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005031 * "pum_getpos()" function
5032 */
5033 static void
5034f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5035{
5036 if (rettv_dict_alloc(rettv) != OK)
5037 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005038 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005039}
5040
5041/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042 * "pumvisible()" function
5043 */
5044 static void
5045f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5046{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005047 if (pum_visible())
5048 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005049}
5050
5051#ifdef FEAT_PYTHON3
5052/*
5053 * "py3eval()" function
5054 */
5055 static void
5056f_py3eval(typval_T *argvars, typval_T *rettv)
5057{
5058 char_u *str;
5059 char_u buf[NUMBUFLEN];
5060
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005061 if (check_restricted() || check_secure())
5062 return;
5063
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005064 if (p_pyx == 0)
5065 p_pyx = 3;
5066
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005067 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005068 do_py3eval(str, rettv);
5069}
5070#endif
5071
5072#ifdef FEAT_PYTHON
5073/*
5074 * "pyeval()" function
5075 */
5076 static void
5077f_pyeval(typval_T *argvars, typval_T *rettv)
5078{
5079 char_u *str;
5080 char_u buf[NUMBUFLEN];
5081
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005082 if (check_restricted() || check_secure())
5083 return;
5084
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005085 if (p_pyx == 0)
5086 p_pyx = 2;
5087
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005088 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005089 do_pyeval(str, rettv);
5090}
5091#endif
5092
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005093#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5094/*
5095 * "pyxeval()" function
5096 */
5097 static void
5098f_pyxeval(typval_T *argvars, typval_T *rettv)
5099{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005100 if (check_restricted() || check_secure())
5101 return;
5102
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005103# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5104 init_pyxversion();
5105 if (p_pyx == 2)
5106 f_pyeval(argvars, rettv);
5107 else
5108 f_py3eval(argvars, rettv);
5109# elif defined(FEAT_PYTHON)
5110 f_pyeval(argvars, rettv);
5111# elif defined(FEAT_PYTHON3)
5112 f_py3eval(argvars, rettv);
5113# endif
5114}
5115#endif
5116
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005117/*
5118 * "range()" function
5119 */
5120 static void
5121f_range(typval_T *argvars, typval_T *rettv)
5122{
5123 varnumber_T start;
5124 varnumber_T end;
5125 varnumber_T stride = 1;
5126 varnumber_T i;
5127 int error = FALSE;
5128
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005129 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005130 if (argvars[1].v_type == VAR_UNKNOWN)
5131 {
5132 end = start - 1;
5133 start = 0;
5134 }
5135 else
5136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005137 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005138 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005139 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005140 }
5141
5142 if (error)
5143 return; /* type error; errmsg already given */
5144 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005145 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005146 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005147 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005148 else
5149 {
5150 if (rettv_list_alloc(rettv) == OK)
5151 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5152 if (list_append_number(rettv->vval.v_list,
5153 (varnumber_T)i) == FAIL)
5154 break;
5155 }
5156}
5157
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005158 static void
5159return_register(int regname, typval_T *rettv)
5160{
5161 char_u buf[2] = {0, 0};
5162
5163 buf[0] = (char_u)regname;
5164 rettv->v_type = VAR_STRING;
5165 rettv->vval.v_string = vim_strsave(buf);
5166}
5167
5168/*
5169 * "reg_executing()" function
5170 */
5171 static void
5172f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5173{
5174 return_register(reg_executing, rettv);
5175}
5176
5177/*
5178 * "reg_recording()" function
5179 */
5180 static void
5181f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5182{
5183 return_register(reg_recording, rettv);
5184}
5185
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005186#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005187/*
5188 * Convert a List to proftime_T.
5189 * Return FAIL when there is something wrong.
5190 */
5191 static int
5192list2proftime(typval_T *arg, proftime_T *tm)
5193{
5194 long n1, n2;
5195 int error = FALSE;
5196
5197 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5198 || arg->vval.v_list->lv_len != 2)
5199 return FAIL;
5200 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5201 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005202# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203 tm->HighPart = n1;
5204 tm->LowPart = n2;
5205# else
5206 tm->tv_sec = n1;
5207 tm->tv_usec = n2;
5208# endif
5209 return error ? FAIL : OK;
5210}
5211#endif /* FEAT_RELTIME */
5212
5213/*
5214 * "reltime()" function
5215 */
5216 static void
5217f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5218{
5219#ifdef FEAT_RELTIME
5220 proftime_T res;
5221 proftime_T start;
5222
5223 if (argvars[0].v_type == VAR_UNKNOWN)
5224 {
5225 /* No arguments: get current time. */
5226 profile_start(&res);
5227 }
5228 else if (argvars[1].v_type == VAR_UNKNOWN)
5229 {
5230 if (list2proftime(&argvars[0], &res) == FAIL)
5231 return;
5232 profile_end(&res);
5233 }
5234 else
5235 {
5236 /* Two arguments: compute the difference. */
5237 if (list2proftime(&argvars[0], &start) == FAIL
5238 || list2proftime(&argvars[1], &res) == FAIL)
5239 return;
5240 profile_sub(&res, &start);
5241 }
5242
5243 if (rettv_list_alloc(rettv) == OK)
5244 {
5245 long n1, n2;
5246
Bram Moolenaar4f974752019-02-17 17:44:42 +01005247# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005248 n1 = res.HighPart;
5249 n2 = res.LowPart;
5250# else
5251 n1 = res.tv_sec;
5252 n2 = res.tv_usec;
5253# endif
5254 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5255 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5256 }
5257#endif
5258}
5259
5260#ifdef FEAT_FLOAT
5261/*
5262 * "reltimefloat()" function
5263 */
5264 static void
5265f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5266{
5267# ifdef FEAT_RELTIME
5268 proftime_T tm;
5269# endif
5270
5271 rettv->v_type = VAR_FLOAT;
5272 rettv->vval.v_float = 0;
5273# ifdef FEAT_RELTIME
5274 if (list2proftime(&argvars[0], &tm) == OK)
5275 rettv->vval.v_float = profile_float(&tm);
5276# endif
5277}
5278#endif
5279
5280/*
5281 * "reltimestr()" function
5282 */
5283 static void
5284f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5285{
5286#ifdef FEAT_RELTIME
5287 proftime_T tm;
5288#endif
5289
5290 rettv->v_type = VAR_STRING;
5291 rettv->vval.v_string = NULL;
5292#ifdef FEAT_RELTIME
5293 if (list2proftime(&argvars[0], &tm) == OK)
5294 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5295#endif
5296}
5297
5298#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005299 static void
5300make_connection(void)
5301{
5302 if (X_DISPLAY == NULL
5303# ifdef FEAT_GUI
5304 && !gui.in_use
5305# endif
5306 )
5307 {
5308 x_force_connect = TRUE;
5309 setup_term_clip();
5310 x_force_connect = FALSE;
5311 }
5312}
5313
5314 static int
5315check_connection(void)
5316{
5317 make_connection();
5318 if (X_DISPLAY == NULL)
5319 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005320 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005321 return FAIL;
5322 }
5323 return OK;
5324}
5325#endif
5326
5327#ifdef FEAT_CLIENTSERVER
5328 static void
5329remote_common(typval_T *argvars, typval_T *rettv, int expr)
5330{
5331 char_u *server_name;
5332 char_u *keys;
5333 char_u *r = NULL;
5334 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005335 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005336# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005337 HWND w;
5338# else
5339 Window w;
5340# endif
5341
5342 if (check_restricted() || check_secure())
5343 return;
5344
5345# ifdef FEAT_X11
5346 if (check_connection() == FAIL)
5347 return;
5348# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005349 if (argvars[2].v_type != VAR_UNKNOWN
5350 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005351 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005352
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005353 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005354 if (server_name == NULL)
5355 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005356 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005357# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005358 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005359# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005360 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5361 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005362# endif
5363 {
5364 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005365 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005366 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005367 vim_free(r);
5368 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005369 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005370 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005371 return;
5372 }
5373
5374 rettv->vval.v_string = r;
5375
5376 if (argvars[2].v_type != VAR_UNKNOWN)
5377 {
5378 dictitem_T v;
5379 char_u str[30];
5380 char_u *idvar;
5381
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005382 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005383 if (idvar != NULL && *idvar != NUL)
5384 {
5385 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5386 v.di_tv.v_type = VAR_STRING;
5387 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005388 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005389 vim_free(v.di_tv.vval.v_string);
5390 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005391 }
5392}
5393#endif
5394
5395/*
5396 * "remote_expr()" function
5397 */
5398 static void
5399f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5400{
5401 rettv->v_type = VAR_STRING;
5402 rettv->vval.v_string = NULL;
5403#ifdef FEAT_CLIENTSERVER
5404 remote_common(argvars, rettv, TRUE);
5405#endif
5406}
5407
5408/*
5409 * "remote_foreground()" function
5410 */
5411 static void
5412f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5413{
5414#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005415# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005416 /* On Win32 it's done in this application. */
5417 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005418 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005419
5420 if (server_name != NULL)
5421 serverForeground(server_name);
5422 }
5423# else
5424 /* Send a foreground() expression to the server. */
5425 argvars[1].v_type = VAR_STRING;
5426 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5427 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005428 rettv->v_type = VAR_STRING;
5429 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005430 remote_common(argvars, rettv, TRUE);
5431 vim_free(argvars[1].vval.v_string);
5432# endif
5433#endif
5434}
5435
5436 static void
5437f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5438{
5439#ifdef FEAT_CLIENTSERVER
5440 dictitem_T v;
5441 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005442# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005443 long_u n = 0;
5444# endif
5445 char_u *serverid;
5446
5447 if (check_restricted() || check_secure())
5448 {
5449 rettv->vval.v_number = -1;
5450 return;
5451 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005452 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005453 if (serverid == NULL)
5454 {
5455 rettv->vval.v_number = -1;
5456 return; /* type error; errmsg already given */
5457 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005458# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005459 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5460 if (n == 0)
5461 rettv->vval.v_number = -1;
5462 else
5463 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005464 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005465 rettv->vval.v_number = (s != NULL);
5466 }
5467# else
5468 if (check_connection() == FAIL)
5469 return;
5470
5471 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5472 serverStrToWin(serverid), &s);
5473# endif
5474
5475 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5476 {
5477 char_u *retvar;
5478
5479 v.di_tv.v_type = VAR_STRING;
5480 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005481 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005482 if (retvar != NULL)
5483 set_var(retvar, &v.di_tv, FALSE);
5484 vim_free(v.di_tv.vval.v_string);
5485 }
5486#else
5487 rettv->vval.v_number = -1;
5488#endif
5489}
5490
5491 static void
5492f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5493{
5494 char_u *r = NULL;
5495
5496#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005497 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005498
5499 if (serverid != NULL && !check_restricted() && !check_secure())
5500 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005501 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005502# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005503 /* The server's HWND is encoded in the 'id' parameter */
5504 long_u n = 0;
5505# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005506
5507 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005508 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005509
Bram Moolenaar4f974752019-02-17 17:44:42 +01005510# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005511 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5512 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005513 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005514 if (r == NULL)
5515# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005516 if (check_connection() == FAIL
5517 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5518 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005519# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005520 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005521 }
5522#endif
5523 rettv->v_type = VAR_STRING;
5524 rettv->vval.v_string = r;
5525}
5526
5527/*
5528 * "remote_send()" function
5529 */
5530 static void
5531f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5532{
5533 rettv->v_type = VAR_STRING;
5534 rettv->vval.v_string = NULL;
5535#ifdef FEAT_CLIENTSERVER
5536 remote_common(argvars, rettv, FALSE);
5537#endif
5538}
5539
5540/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005541 * "remote_startserver()" function
5542 */
5543 static void
5544f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5545{
5546#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005547 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005548
5549 if (server == NULL)
5550 return; /* type error; errmsg already given */
5551 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005552 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005553 else
5554 {
5555# ifdef FEAT_X11
5556 if (check_connection() == OK)
5557 serverRegisterName(X_DISPLAY, server);
5558# else
5559 serverSetName(server);
5560# endif
5561 }
5562#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005563 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005564#endif
5565}
5566
5567/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005568 * "rename({from}, {to})" function
5569 */
5570 static void
5571f_rename(typval_T *argvars, typval_T *rettv)
5572{
5573 char_u buf[NUMBUFLEN];
5574
5575 if (check_restricted() || check_secure())
5576 rettv->vval.v_number = -1;
5577 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005578 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5579 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005580}
5581
5582/*
5583 * "repeat()" function
5584 */
5585 static void
5586f_repeat(typval_T *argvars, typval_T *rettv)
5587{
5588 char_u *p;
5589 int n;
5590 int slen;
5591 int len;
5592 char_u *r;
5593 int i;
5594
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005595 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005596 if (argvars[0].v_type == VAR_LIST)
5597 {
5598 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5599 while (n-- > 0)
5600 if (list_extend(rettv->vval.v_list,
5601 argvars[0].vval.v_list, NULL) == FAIL)
5602 break;
5603 }
5604 else
5605 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005606 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005607 rettv->v_type = VAR_STRING;
5608 rettv->vval.v_string = NULL;
5609
5610 slen = (int)STRLEN(p);
5611 len = slen * n;
5612 if (len <= 0)
5613 return;
5614
5615 r = alloc(len + 1);
5616 if (r != NULL)
5617 {
5618 for (i = 0; i < n; i++)
5619 mch_memmove(r + i * slen, p, (size_t)slen);
5620 r[len] = NUL;
5621 }
5622
5623 rettv->vval.v_string = r;
5624 }
5625}
5626
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005627#define SP_NOMOVE 0x01 /* don't move cursor */
5628#define SP_REPEAT 0x02 /* repeat to find outer pair */
5629#define SP_RETCOUNT 0x04 /* return matchcount */
5630#define SP_SETPCMARK 0x08 /* set previous context mark */
5631#define SP_START 0x10 /* accept match at start position */
5632#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5633#define SP_END 0x40 /* leave cursor at end of match */
5634#define SP_COLUMN 0x80 /* start at cursor column */
5635
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005636/*
5637 * Get flags for a search function.
5638 * Possibly sets "p_ws".
5639 * Returns BACKWARD, FORWARD or zero (for an error).
5640 */
5641 static int
5642get_search_arg(typval_T *varp, int *flagsp)
5643{
5644 int dir = FORWARD;
5645 char_u *flags;
5646 char_u nbuf[NUMBUFLEN];
5647 int mask;
5648
5649 if (varp->v_type != VAR_UNKNOWN)
5650 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005651 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005652 if (flags == NULL)
5653 return 0; /* type error; errmsg already given */
5654 while (*flags != NUL)
5655 {
5656 switch (*flags)
5657 {
5658 case 'b': dir = BACKWARD; break;
5659 case 'w': p_ws = TRUE; break;
5660 case 'W': p_ws = FALSE; break;
5661 default: mask = 0;
5662 if (flagsp != NULL)
5663 switch (*flags)
5664 {
5665 case 'c': mask = SP_START; break;
5666 case 'e': mask = SP_END; break;
5667 case 'm': mask = SP_RETCOUNT; break;
5668 case 'n': mask = SP_NOMOVE; break;
5669 case 'p': mask = SP_SUBPAT; break;
5670 case 'r': mask = SP_REPEAT; break;
5671 case 's': mask = SP_SETPCMARK; break;
5672 case 'z': mask = SP_COLUMN; break;
5673 }
5674 if (mask == 0)
5675 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005676 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005677 dir = 0;
5678 }
5679 else
5680 *flagsp |= mask;
5681 }
5682 if (dir == 0)
5683 break;
5684 ++flags;
5685 }
5686 }
5687 return dir;
5688}
5689
5690/*
5691 * Shared by search() and searchpos() functions.
5692 */
5693 static int
5694search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5695{
5696 int flags;
5697 char_u *pat;
5698 pos_T pos;
5699 pos_T save_cursor;
5700 int save_p_ws = p_ws;
5701 int dir;
5702 int retval = 0; /* default: FAIL */
5703 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005704#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005705 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005706 long time_limit = 0;
5707#endif
5708 int options = SEARCH_KEEP;
5709 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005710 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005711
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005712 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005713 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5714 if (dir == 0)
5715 goto theend;
5716 flags = *flagsp;
5717 if (flags & SP_START)
5718 options |= SEARCH_START;
5719 if (flags & SP_END)
5720 options |= SEARCH_END;
5721 if (flags & SP_COLUMN)
5722 options |= SEARCH_COL;
5723
5724 /* Optional arguments: line number to stop searching and timeout. */
5725 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005727 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005728 if (lnum_stop < 0)
5729 goto theend;
5730#ifdef FEAT_RELTIME
5731 if (argvars[3].v_type != VAR_UNKNOWN)
5732 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005733 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734 if (time_limit < 0)
5735 goto theend;
5736 }
5737#endif
5738 }
5739
5740#ifdef FEAT_RELTIME
5741 /* Set the time limit, if there is one. */
5742 profile_setlimit(time_limit, &tm);
5743#endif
5744
5745 /*
5746 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5747 * Check to make sure only those flags are set.
5748 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5749 * flags cannot be set. Check for that condition also.
5750 */
5751 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5752 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5753 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005754 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005755 goto theend;
5756 }
5757
5758 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005759 vim_memset(&sia, 0, sizeof(sia));
5760 sia.sa_stop_lnum = (linenr_T)lnum_stop;
5761#ifdef FEAT_RELTIME
5762 sia.sa_tm = &tm;
5763#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005764 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005765 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005766 if (subpatnum != FAIL)
5767 {
5768 if (flags & SP_SUBPAT)
5769 retval = subpatnum;
5770 else
5771 retval = pos.lnum;
5772 if (flags & SP_SETPCMARK)
5773 setpcmark();
5774 curwin->w_cursor = pos;
5775 if (match_pos != NULL)
5776 {
5777 /* Store the match cursor position */
5778 match_pos->lnum = pos.lnum;
5779 match_pos->col = pos.col + 1;
5780 }
5781 /* "/$" will put the cursor after the end of the line, may need to
5782 * correct that here */
5783 check_cursor();
5784 }
5785
5786 /* If 'n' flag is used: restore cursor position. */
5787 if (flags & SP_NOMOVE)
5788 curwin->w_cursor = save_cursor;
5789 else
5790 curwin->w_set_curswant = TRUE;
5791theend:
5792 p_ws = save_p_ws;
5793
5794 return retval;
5795}
5796
5797#ifdef FEAT_FLOAT
5798
5799/*
5800 * round() is not in C90, use ceil() or floor() instead.
5801 */
5802 float_T
5803vim_round(float_T f)
5804{
5805 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
5806}
5807
5808/*
5809 * "round({float})" function
5810 */
5811 static void
5812f_round(typval_T *argvars, typval_T *rettv)
5813{
5814 float_T f = 0.0;
5815
5816 rettv->v_type = VAR_FLOAT;
5817 if (get_float_arg(argvars, &f) == OK)
5818 rettv->vval.v_float = vim_round(f);
5819 else
5820 rettv->vval.v_float = 0.0;
5821}
5822#endif
5823
Bram Moolenaare99be0e2019-03-26 22:51:09 +01005824#ifdef FEAT_RUBY
5825/*
5826 * "rubyeval()" function
5827 */
5828 static void
5829f_rubyeval(typval_T *argvars, typval_T *rettv)
5830{
5831 char_u *str;
5832 char_u buf[NUMBUFLEN];
5833
5834 str = tv_get_string_buf(&argvars[0], buf);
5835 do_rubyeval(str, rettv);
5836}
5837#endif
5838
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005839/*
5840 * "screenattr()" function
5841 */
5842 static void
5843f_screenattr(typval_T *argvars, typval_T *rettv)
5844{
5845 int row;
5846 int col;
5847 int c;
5848
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005849 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5850 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005851 if (row < 0 || row >= screen_Rows
5852 || col < 0 || col >= screen_Columns)
5853 c = -1;
5854 else
5855 c = ScreenAttrs[LineOffset[row] + col];
5856 rettv->vval.v_number = c;
5857}
5858
5859/*
5860 * "screenchar()" function
5861 */
5862 static void
5863f_screenchar(typval_T *argvars, typval_T *rettv)
5864{
5865 int row;
5866 int col;
5867 int off;
5868 int c;
5869
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005870 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5871 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005872 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005873 c = -1;
5874 else
5875 {
5876 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005877 if (enc_utf8 && ScreenLinesUC[off] != 0)
5878 c = ScreenLinesUC[off];
5879 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005880 c = ScreenLines[off];
5881 }
5882 rettv->vval.v_number = c;
5883}
5884
5885/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005886 * "screenchars()" function
5887 */
5888 static void
5889f_screenchars(typval_T *argvars, typval_T *rettv)
5890{
5891 int row;
5892 int col;
5893 int off;
5894 int c;
5895 int i;
5896
5897 if (rettv_list_alloc(rettv) == FAIL)
5898 return;
5899 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5900 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5901 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5902 return;
5903
5904 off = LineOffset[row] + col;
5905 if (enc_utf8 && ScreenLinesUC[off] != 0)
5906 c = ScreenLinesUC[off];
5907 else
5908 c = ScreenLines[off];
5909 list_append_number(rettv->vval.v_list, (varnumber_T)c);
5910
5911 if (enc_utf8)
5912
5913 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
5914 list_append_number(rettv->vval.v_list,
5915 (varnumber_T)ScreenLinesC[i][off]);
5916}
5917
5918/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005919 * "screencol()" function
5920 *
5921 * First column is 1 to be consistent with virtcol().
5922 */
5923 static void
5924f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
5925{
5926 rettv->vval.v_number = screen_screencol() + 1;
5927}
5928
5929/*
5930 * "screenrow()" function
5931 */
5932 static void
5933f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
5934{
5935 rettv->vval.v_number = screen_screenrow() + 1;
5936}
5937
5938/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005939 * "screenstring()" function
5940 */
5941 static void
5942f_screenstring(typval_T *argvars, typval_T *rettv)
5943{
5944 int row;
5945 int col;
5946 int off;
5947 int c;
5948 int i;
5949 char_u buf[MB_MAXBYTES + 1];
5950 int buflen = 0;
5951
5952 rettv->vval.v_string = NULL;
5953 rettv->v_type = VAR_STRING;
5954
5955 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5956 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5957 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5958 return;
5959
5960 off = LineOffset[row] + col;
5961 if (enc_utf8 && ScreenLinesUC[off] != 0)
5962 c = ScreenLinesUC[off];
5963 else
5964 c = ScreenLines[off];
5965 buflen += mb_char2bytes(c, buf);
5966
5967 if (enc_utf8)
5968 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
5969 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
5970
5971 buf[buflen] = NUL;
5972 rettv->vval.v_string = vim_strsave(buf);
5973}
5974
5975/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976 * "search()" function
5977 */
5978 static void
5979f_search(typval_T *argvars, typval_T *rettv)
5980{
5981 int flags = 0;
5982
5983 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
5984}
5985
5986/*
5987 * "searchdecl()" function
5988 */
5989 static void
5990f_searchdecl(typval_T *argvars, typval_T *rettv)
5991{
5992 int locally = 1;
5993 int thisblock = 0;
5994 int error = FALSE;
5995 char_u *name;
5996
5997 rettv->vval.v_number = 1; /* default: FAIL */
5998
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005999 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006000 if (argvars[1].v_type != VAR_UNKNOWN)
6001 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006002 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006003 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006004 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006005 }
6006 if (!error && name != NULL)
6007 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6008 locally, thisblock, SEARCH_KEEP) == FAIL;
6009}
6010
6011/*
6012 * Used by searchpair() and searchpairpos()
6013 */
6014 static int
6015searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6016{
6017 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006018 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006019 int save_p_ws = p_ws;
6020 int dir;
6021 int flags = 0;
6022 char_u nbuf1[NUMBUFLEN];
6023 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006024 int retval = 0; /* default: FAIL */
6025 long lnum_stop = 0;
6026 long time_limit = 0;
6027
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006028 /* Get the three pattern arguments: start, middle, end. Will result in an
6029 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006030 spat = tv_get_string_chk(&argvars[0]);
6031 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6032 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006033 if (spat == NULL || mpat == NULL || epat == NULL)
6034 goto theend; /* type error */
6035
6036 /* Handle the optional fourth argument: flags */
6037 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6038 if (dir == 0)
6039 goto theend;
6040
6041 /* Don't accept SP_END or SP_SUBPAT.
6042 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6043 */
6044 if ((flags & (SP_END | SP_SUBPAT)) != 0
6045 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6046 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006047 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006048 goto theend;
6049 }
6050
6051 /* Using 'r' implies 'W', otherwise it doesn't work. */
6052 if (flags & SP_REPEAT)
6053 p_ws = FALSE;
6054
6055 /* Optional fifth argument: skip expression */
6056 if (argvars[3].v_type == VAR_UNKNOWN
6057 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006058 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006059 else
6060 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006061 skip = &argvars[4];
6062 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6063 && skip->v_type != VAR_STRING)
6064 {
6065 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006066 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006067 goto theend;
6068 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006069 if (argvars[5].v_type != VAR_UNKNOWN)
6070 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006071 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006072 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006073 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006074 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006075 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006076 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006077#ifdef FEAT_RELTIME
6078 if (argvars[6].v_type != VAR_UNKNOWN)
6079 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006080 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006082 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006083 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006084 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006085 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006086 }
6087#endif
6088 }
6089 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006090
6091 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6092 match_pos, lnum_stop, time_limit);
6093
6094theend:
6095 p_ws = save_p_ws;
6096
6097 return retval;
6098}
6099
6100/*
6101 * "searchpair()" function
6102 */
6103 static void
6104f_searchpair(typval_T *argvars, typval_T *rettv)
6105{
6106 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6107}
6108
6109/*
6110 * "searchpairpos()" function
6111 */
6112 static void
6113f_searchpairpos(typval_T *argvars, typval_T *rettv)
6114{
6115 pos_T match_pos;
6116 int lnum = 0;
6117 int col = 0;
6118
6119 if (rettv_list_alloc(rettv) == FAIL)
6120 return;
6121
6122 if (searchpair_cmn(argvars, &match_pos) > 0)
6123 {
6124 lnum = match_pos.lnum;
6125 col = match_pos.col;
6126 }
6127
6128 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6129 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6130}
6131
6132/*
6133 * Search for a start/middle/end thing.
6134 * Used by searchpair(), see its documentation for the details.
6135 * Returns 0 or -1 for no match,
6136 */
6137 long
6138do_searchpair(
6139 char_u *spat, /* start pattern */
6140 char_u *mpat, /* middle pattern */
6141 char_u *epat, /* end pattern */
6142 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006143 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006144 int flags, /* SP_SETPCMARK and other SP_ values */
6145 pos_T *match_pos,
6146 linenr_T lnum_stop, /* stop at this line if not zero */
6147 long time_limit UNUSED) /* stop after this many msec */
6148{
6149 char_u *save_cpo;
6150 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6151 long retval = 0;
6152 pos_T pos;
6153 pos_T firstpos;
6154 pos_T foundpos;
6155 pos_T save_cursor;
6156 pos_T save_pos;
6157 int n;
6158 int r;
6159 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006160 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006161 int err;
6162 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006163#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006164 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006165#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006166
6167 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6168 save_cpo = p_cpo;
6169 p_cpo = empty_option;
6170
6171#ifdef FEAT_RELTIME
6172 /* Set the time limit, if there is one. */
6173 profile_setlimit(time_limit, &tm);
6174#endif
6175
6176 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6177 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006178 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6179 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006180 if (pat2 == NULL || pat3 == NULL)
6181 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006182 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006183 if (*mpat == NUL)
6184 STRCPY(pat3, pat2);
6185 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006186 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006187 spat, epat, mpat);
6188 if (flags & SP_START)
6189 options |= SEARCH_START;
6190
Bram Moolenaar48570482017-10-30 21:48:41 +01006191 if (skip != NULL)
6192 {
6193 /* Empty string means to not use the skip expression. */
6194 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6195 use_skip = skip->vval.v_string != NULL
6196 && *skip->vval.v_string != NUL;
6197 }
6198
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006199 save_cursor = curwin->w_cursor;
6200 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006201 CLEAR_POS(&firstpos);
6202 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006203 pat = pat3;
6204 for (;;)
6205 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006206 searchit_arg_T sia;
6207
6208 vim_memset(&sia, 0, sizeof(sia));
6209 sia.sa_stop_lnum = lnum_stop;
6210#ifdef FEAT_RELTIME
6211 sia.sa_tm = &tm;
6212#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006213 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006214 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006215 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006216 /* didn't find it or found the first match again: FAIL */
6217 break;
6218
6219 if (firstpos.lnum == 0)
6220 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006221 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006222 {
6223 /* Found the same position again. Can happen with a pattern that
6224 * has "\zs" at the end and searching backwards. Advance one
6225 * character and try again. */
6226 if (dir == BACKWARD)
6227 decl(&pos);
6228 else
6229 incl(&pos);
6230 }
6231 foundpos = pos;
6232
6233 /* clear the start flag to avoid getting stuck here */
6234 options &= ~SEARCH_START;
6235
6236 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006237 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006238 {
6239 save_pos = curwin->w_cursor;
6240 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006241 err = FALSE;
6242 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006243 curwin->w_cursor = save_pos;
6244 if (err)
6245 {
6246 /* Evaluating {skip} caused an error, break here. */
6247 curwin->w_cursor = save_cursor;
6248 retval = -1;
6249 break;
6250 }
6251 if (r)
6252 continue;
6253 }
6254
6255 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6256 {
6257 /* Found end when searching backwards or start when searching
6258 * forward: nested pair. */
6259 ++nest;
6260 pat = pat2; /* nested, don't search for middle */
6261 }
6262 else
6263 {
6264 /* Found end when searching forward or start when searching
6265 * backward: end of (nested) pair; or found middle in outer pair. */
6266 if (--nest == 1)
6267 pat = pat3; /* outer level, search for middle */
6268 }
6269
6270 if (nest == 0)
6271 {
6272 /* Found the match: return matchcount or line number. */
6273 if (flags & SP_RETCOUNT)
6274 ++retval;
6275 else
6276 retval = pos.lnum;
6277 if (flags & SP_SETPCMARK)
6278 setpcmark();
6279 curwin->w_cursor = pos;
6280 if (!(flags & SP_REPEAT))
6281 break;
6282 nest = 1; /* search for next unmatched */
6283 }
6284 }
6285
6286 if (match_pos != NULL)
6287 {
6288 /* Store the match cursor position */
6289 match_pos->lnum = curwin->w_cursor.lnum;
6290 match_pos->col = curwin->w_cursor.col + 1;
6291 }
6292
6293 /* If 'n' flag is used or search failed: restore cursor position. */
6294 if ((flags & SP_NOMOVE) || retval == 0)
6295 curwin->w_cursor = save_cursor;
6296
6297theend:
6298 vim_free(pat2);
6299 vim_free(pat3);
6300 if (p_cpo == empty_option)
6301 p_cpo = save_cpo;
6302 else
6303 /* Darn, evaluating the {skip} expression changed the value. */
6304 free_string_option(save_cpo);
6305
6306 return retval;
6307}
6308
6309/*
6310 * "searchpos()" function
6311 */
6312 static void
6313f_searchpos(typval_T *argvars, typval_T *rettv)
6314{
6315 pos_T match_pos;
6316 int lnum = 0;
6317 int col = 0;
6318 int n;
6319 int flags = 0;
6320
6321 if (rettv_list_alloc(rettv) == FAIL)
6322 return;
6323
6324 n = search_cmn(argvars, &match_pos, &flags);
6325 if (n > 0)
6326 {
6327 lnum = match_pos.lnum;
6328 col = match_pos.col;
6329 }
6330
6331 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6332 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6333 if (flags & SP_SUBPAT)
6334 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6335}
6336
6337 static void
6338f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6339{
6340#ifdef FEAT_CLIENTSERVER
6341 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006342 char_u *server = tv_get_string_chk(&argvars[0]);
6343 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006344
6345 rettv->vval.v_number = -1;
6346 if (server == NULL || reply == NULL)
6347 return;
6348 if (check_restricted() || check_secure())
6349 return;
6350# ifdef FEAT_X11
6351 if (check_connection() == FAIL)
6352 return;
6353# endif
6354
6355 if (serverSendReply(server, reply) < 0)
6356 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006357 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006358 return;
6359 }
6360 rettv->vval.v_number = 0;
6361#else
6362 rettv->vval.v_number = -1;
6363#endif
6364}
6365
6366 static void
6367f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6368{
6369 char_u *r = NULL;
6370
6371#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006372# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373 r = serverGetVimNames();
6374# else
6375 make_connection();
6376 if (X_DISPLAY != NULL)
6377 r = serverGetVimNames(X_DISPLAY);
6378# endif
6379#endif
6380 rettv->v_type = VAR_STRING;
6381 rettv->vval.v_string = r;
6382}
6383
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006384 static void
6385f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6386{
6387 dict_T *d;
6388 dictitem_T *di;
6389 char_u *csearch;
6390
6391 if (argvars[0].v_type != VAR_DICT)
6392 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006393 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394 return;
6395 }
6396
6397 if ((d = argvars[0].vval.v_dict) != NULL)
6398 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006399 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006400 if (csearch != NULL)
6401 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006402 if (enc_utf8)
6403 {
6404 int pcc[MAX_MCO];
6405 int c = utfc_ptr2char(csearch, pcc);
6406
6407 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6408 }
6409 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006410 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006411 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412 }
6413
6414 di = dict_find(d, (char_u *)"forward", -1);
6415 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006416 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006417 ? FORWARD : BACKWARD);
6418
6419 di = dict_find(d, (char_u *)"until", -1);
6420 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006421 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422 }
6423}
6424
6425/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006426 * "setenv()" function
6427 */
6428 static void
6429f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6430{
6431 char_u namebuf[NUMBUFLEN];
6432 char_u valbuf[NUMBUFLEN];
6433 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6434
6435 if (argvars[1].v_type == VAR_SPECIAL
6436 && argvars[1].vval.v_number == VVAL_NULL)
6437 vim_unsetenv(name);
6438 else
6439 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6440}
6441
6442/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006443 * "setfperm({fname}, {mode})" function
6444 */
6445 static void
6446f_setfperm(typval_T *argvars, typval_T *rettv)
6447{
6448 char_u *fname;
6449 char_u modebuf[NUMBUFLEN];
6450 char_u *mode_str;
6451 int i;
6452 int mask;
6453 int mode = 0;
6454
6455 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006456 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006457 if (fname == NULL)
6458 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006459 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006460 if (mode_str == NULL)
6461 return;
6462 if (STRLEN(mode_str) != 9)
6463 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006464 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465 return;
6466 }
6467
6468 mask = 1;
6469 for (i = 8; i >= 0; --i)
6470 {
6471 if (mode_str[i] != '-')
6472 mode |= mask;
6473 mask = mask << 1;
6474 }
6475 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6476}
6477
6478/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006479 * "setpos()" function
6480 */
6481 static void
6482f_setpos(typval_T *argvars, typval_T *rettv)
6483{
6484 pos_T pos;
6485 int fnum;
6486 char_u *name;
6487 colnr_T curswant = -1;
6488
6489 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006490 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006491 if (name != NULL)
6492 {
6493 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6494 {
6495 if (--pos.col < 0)
6496 pos.col = 0;
6497 if (name[0] == '.' && name[1] == NUL)
6498 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006499 /* set cursor; "fnum" is ignored */
6500 curwin->w_cursor = pos;
6501 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006503 curwin->w_curswant = curswant - 1;
6504 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006506 check_cursor();
6507 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508 }
6509 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6510 {
6511 /* set mark */
6512 if (setmark_pos(name[1], &pos, fnum) == OK)
6513 rettv->vval.v_number = 0;
6514 }
6515 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006516 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006517 }
6518 }
6519}
6520
6521/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006522 * "setreg()" function
6523 */
6524 static void
6525f_setreg(typval_T *argvars, typval_T *rettv)
6526{
6527 int regname;
6528 char_u *strregname;
6529 char_u *stropt;
6530 char_u *strval;
6531 int append;
6532 char_u yank_type;
6533 long block_len;
6534
6535 block_len = -1;
6536 yank_type = MAUTO;
6537 append = FALSE;
6538
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006539 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006540 rettv->vval.v_number = 1; /* FAIL is default */
6541
6542 if (strregname == NULL)
6543 return; /* type error; errmsg already given */
6544 regname = *strregname;
6545 if (regname == 0 || regname == '@')
6546 regname = '"';
6547
6548 if (argvars[2].v_type != VAR_UNKNOWN)
6549 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006550 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006551 if (stropt == NULL)
6552 return; /* type error */
6553 for (; *stropt != NUL; ++stropt)
6554 switch (*stropt)
6555 {
6556 case 'a': case 'A': /* append */
6557 append = TRUE;
6558 break;
6559 case 'v': case 'c': /* character-wise selection */
6560 yank_type = MCHAR;
6561 break;
6562 case 'V': case 'l': /* line-wise selection */
6563 yank_type = MLINE;
6564 break;
6565 case 'b': case Ctrl_V: /* block-wise selection */
6566 yank_type = MBLOCK;
6567 if (VIM_ISDIGIT(stropt[1]))
6568 {
6569 ++stropt;
6570 block_len = getdigits(&stropt) - 1;
6571 --stropt;
6572 }
6573 break;
6574 }
6575 }
6576
6577 if (argvars[1].v_type == VAR_LIST)
6578 {
6579 char_u **lstval;
6580 char_u **allocval;
6581 char_u buf[NUMBUFLEN];
6582 char_u **curval;
6583 char_u **curallocval;
6584 list_T *ll = argvars[1].vval.v_list;
6585 listitem_T *li;
6586 int len;
6587
6588 /* If the list is NULL handle like an empty list. */
6589 len = ll == NULL ? 0 : ll->lv_len;
6590
6591 /* First half: use for pointers to result lines; second half: use for
6592 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006593 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006594 if (lstval == NULL)
6595 return;
6596 curval = lstval;
6597 allocval = lstval + len + 2;
6598 curallocval = allocval;
6599
6600 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6601 li = li->li_next)
6602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006603 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006604 if (strval == NULL)
6605 goto free_lstval;
6606 if (strval == buf)
6607 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006608 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006609 * overwrite the string. */
6610 strval = vim_strsave(buf);
6611 if (strval == NULL)
6612 goto free_lstval;
6613 *curallocval++ = strval;
6614 }
6615 *curval++ = strval;
6616 }
6617 *curval++ = NULL;
6618
6619 write_reg_contents_lst(regname, lstval, -1,
6620 append, yank_type, block_len);
6621free_lstval:
6622 while (curallocval > allocval)
6623 vim_free(*--curallocval);
6624 vim_free(lstval);
6625 }
6626 else
6627 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006628 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006629 if (strval == NULL)
6630 return;
6631 write_reg_contents_ex(regname, strval, -1,
6632 append, yank_type, block_len);
6633 }
6634 rettv->vval.v_number = 0;
6635}
6636
6637/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006638 * "settagstack()" function
6639 */
6640 static void
6641f_settagstack(typval_T *argvars, typval_T *rettv)
6642{
6643 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6644 win_T *wp;
6645 dict_T *d;
6646 int action = 'r';
6647
6648 rettv->vval.v_number = -1;
6649
6650 // first argument: window number or id
6651 wp = find_win_by_nr_or_id(&argvars[0]);
6652 if (wp == NULL)
6653 return;
6654
6655 // second argument: dict with items to set in the tag stack
6656 if (argvars[1].v_type != VAR_DICT)
6657 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006658 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006659 return;
6660 }
6661 d = argvars[1].vval.v_dict;
6662 if (d == NULL)
6663 return;
6664
6665 // third argument: action - 'a' for append and 'r' for replace.
6666 // default is to replace the stack.
6667 if (argvars[2].v_type == VAR_UNKNOWN)
6668 action = 'r';
6669 else if (argvars[2].v_type == VAR_STRING)
6670 {
6671 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006672 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006673 if (actstr == NULL)
6674 return;
6675 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6676 action = *actstr;
6677 else
6678 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006679 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006680 return;
6681 }
6682 }
6683 else
6684 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006685 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006686 return;
6687 }
6688
6689 if (set_tagstack(wp, d, action) == OK)
6690 rettv->vval.v_number = 0;
6691}
6692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006693#ifdef FEAT_CRYPT
6694/*
6695 * "sha256({string})" function
6696 */
6697 static void
6698f_sha256(typval_T *argvars, typval_T *rettv)
6699{
6700 char_u *p;
6701
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006702 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006703 rettv->vval.v_string = vim_strsave(
6704 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6705 rettv->v_type = VAR_STRING;
6706}
6707#endif /* FEAT_CRYPT */
6708
6709/*
6710 * "shellescape({string})" function
6711 */
6712 static void
6713f_shellescape(typval_T *argvars, typval_T *rettv)
6714{
Bram Moolenaar20615522017-06-05 18:46:26 +02006715 int do_special = non_zero_arg(&argvars[1]);
6716
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006717 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006718 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006719 rettv->v_type = VAR_STRING;
6720}
6721
6722/*
6723 * shiftwidth() function
6724 */
6725 static void
6726f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6727{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006728 rettv->vval.v_number = 0;
6729
6730 if (argvars[0].v_type != VAR_UNKNOWN)
6731 {
6732 long col;
6733
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006734 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006735 if (col < 0)
6736 return; // type error; errmsg already given
6737#ifdef FEAT_VARTABS
6738 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6739 return;
6740#endif
6741 }
6742
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006743 rettv->vval.v_number = get_sw_value(curbuf);
6744}
6745
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006746#ifdef FEAT_FLOAT
6747/*
6748 * "sin()" function
6749 */
6750 static void
6751f_sin(typval_T *argvars, typval_T *rettv)
6752{
6753 float_T f = 0.0;
6754
6755 rettv->v_type = VAR_FLOAT;
6756 if (get_float_arg(argvars, &f) == OK)
6757 rettv->vval.v_float = sin(f);
6758 else
6759 rettv->vval.v_float = 0.0;
6760}
6761
6762/*
6763 * "sinh()" function
6764 */
6765 static void
6766f_sinh(typval_T *argvars, typval_T *rettv)
6767{
6768 float_T f = 0.0;
6769
6770 rettv->v_type = VAR_FLOAT;
6771 if (get_float_arg(argvars, &f) == OK)
6772 rettv->vval.v_float = sinh(f);
6773 else
6774 rettv->vval.v_float = 0.0;
6775}
6776#endif
6777
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006778/*
6779 * "soundfold({word})" function
6780 */
6781 static void
6782f_soundfold(typval_T *argvars, typval_T *rettv)
6783{
6784 char_u *s;
6785
6786 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006787 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006788#ifdef FEAT_SPELL
6789 rettv->vval.v_string = eval_soundfold(s);
6790#else
6791 rettv->vval.v_string = vim_strsave(s);
6792#endif
6793}
6794
6795/*
6796 * "spellbadword()" function
6797 */
6798 static void
6799f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6800{
6801 char_u *word = (char_u *)"";
6802 hlf_T attr = HLF_COUNT;
6803 int len = 0;
6804
6805 if (rettv_list_alloc(rettv) == FAIL)
6806 return;
6807
6808#ifdef FEAT_SPELL
6809 if (argvars[0].v_type == VAR_UNKNOWN)
6810 {
6811 /* Find the start and length of the badly spelled word. */
6812 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
6813 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006814 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006815 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006816 curwin->w_set_curswant = TRUE;
6817 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006818 }
6819 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
6820 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006821 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006822 int capcol = -1;
6823
6824 if (str != NULL)
6825 {
6826 /* Check the argument for spelling. */
6827 while (*str != NUL)
6828 {
6829 len = spell_check(curwin, str, &attr, &capcol, FALSE);
6830 if (attr != HLF_COUNT)
6831 {
6832 word = str;
6833 break;
6834 }
6835 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02006836 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02006837 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006838 }
6839 }
6840 }
6841#endif
6842
6843 list_append_string(rettv->vval.v_list, word, len);
6844 list_append_string(rettv->vval.v_list, (char_u *)(
6845 attr == HLF_SPB ? "bad" :
6846 attr == HLF_SPR ? "rare" :
6847 attr == HLF_SPL ? "local" :
6848 attr == HLF_SPC ? "caps" :
6849 ""), -1);
6850}
6851
6852/*
6853 * "spellsuggest()" function
6854 */
6855 static void
6856f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
6857{
6858#ifdef FEAT_SPELL
6859 char_u *str;
6860 int typeerr = FALSE;
6861 int maxcount;
6862 garray_T ga;
6863 int i;
6864 listitem_T *li;
6865 int need_capital = FALSE;
6866#endif
6867
6868 if (rettv_list_alloc(rettv) == FAIL)
6869 return;
6870
6871#ifdef FEAT_SPELL
6872 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
6873 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006874 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006875 if (argvars[1].v_type != VAR_UNKNOWN)
6876 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006877 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006878 if (maxcount <= 0)
6879 return;
6880 if (argvars[2].v_type != VAR_UNKNOWN)
6881 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006882 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883 if (typeerr)
6884 return;
6885 }
6886 }
6887 else
6888 maxcount = 25;
6889
6890 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
6891
6892 for (i = 0; i < ga.ga_len; ++i)
6893 {
6894 str = ((char_u **)ga.ga_data)[i];
6895
6896 li = listitem_alloc();
6897 if (li == NULL)
6898 vim_free(str);
6899 else
6900 {
6901 li->li_tv.v_type = VAR_STRING;
6902 li->li_tv.v_lock = 0;
6903 li->li_tv.vval.v_string = str;
6904 list_append(rettv->vval.v_list, li);
6905 }
6906 }
6907 ga_clear(&ga);
6908 }
6909#endif
6910}
6911
6912 static void
6913f_split(typval_T *argvars, typval_T *rettv)
6914{
6915 char_u *str;
6916 char_u *end;
6917 char_u *pat = NULL;
6918 regmatch_T regmatch;
6919 char_u patbuf[NUMBUFLEN];
6920 char_u *save_cpo;
6921 int match;
6922 colnr_T col = 0;
6923 int keepempty = FALSE;
6924 int typeerr = FALSE;
6925
6926 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6927 save_cpo = p_cpo;
6928 p_cpo = (char_u *)"";
6929
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006930 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006931 if (argvars[1].v_type != VAR_UNKNOWN)
6932 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006933 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006934 if (pat == NULL)
6935 typeerr = TRUE;
6936 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006937 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006938 }
6939 if (pat == NULL || *pat == NUL)
6940 pat = (char_u *)"[\\x01- ]\\+";
6941
6942 if (rettv_list_alloc(rettv) == FAIL)
6943 return;
6944 if (typeerr)
6945 return;
6946
6947 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6948 if (regmatch.regprog != NULL)
6949 {
6950 regmatch.rm_ic = FALSE;
6951 while (*str != NUL || keepempty)
6952 {
6953 if (*str == NUL)
6954 match = FALSE; /* empty item at the end */
6955 else
6956 match = vim_regexec_nl(&regmatch, str, col);
6957 if (match)
6958 end = regmatch.startp[0];
6959 else
6960 end = str + STRLEN(str);
6961 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
6962 && *str != NUL && match && end < regmatch.endp[0]))
6963 {
6964 if (list_append_string(rettv->vval.v_list, str,
6965 (int)(end - str)) == FAIL)
6966 break;
6967 }
6968 if (!match)
6969 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01006970 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006971 if (regmatch.endp[0] > str)
6972 col = 0;
6973 else
Bram Moolenaar13505972019-01-24 15:04:48 +01006974 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006976 str = regmatch.endp[0];
6977 }
6978
6979 vim_regfree(regmatch.regprog);
6980 }
6981
6982 p_cpo = save_cpo;
6983}
6984
6985#ifdef FEAT_FLOAT
6986/*
6987 * "sqrt()" function
6988 */
6989 static void
6990f_sqrt(typval_T *argvars, typval_T *rettv)
6991{
6992 float_T f = 0.0;
6993
6994 rettv->v_type = VAR_FLOAT;
6995 if (get_float_arg(argvars, &f) == OK)
6996 rettv->vval.v_float = sqrt(f);
6997 else
6998 rettv->vval.v_float = 0.0;
6999}
7000
7001/*
7002 * "str2float()" function
7003 */
7004 static void
7005f_str2float(typval_T *argvars, typval_T *rettv)
7006{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007007 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007008 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007009
Bram Moolenaar08243d22017-01-10 16:12:29 +01007010 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007011 p = skipwhite(p + 1);
7012 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007013 if (isneg)
7014 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007015 rettv->v_type = VAR_FLOAT;
7016}
7017#endif
7018
7019/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007020 * "str2list()" function
7021 */
7022 static void
7023f_str2list(typval_T *argvars, typval_T *rettv)
7024{
7025 char_u *p;
7026 int utf8 = FALSE;
7027
7028 if (rettv_list_alloc(rettv) == FAIL)
7029 return;
7030
7031 if (argvars[1].v_type != VAR_UNKNOWN)
7032 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7033
7034 p = tv_get_string(&argvars[0]);
7035
7036 if (has_mbyte || utf8)
7037 {
7038 int (*ptr2len)(char_u *);
7039 int (*ptr2char)(char_u *);
7040
7041 if (utf8 || enc_utf8)
7042 {
7043 ptr2len = utf_ptr2len;
7044 ptr2char = utf_ptr2char;
7045 }
7046 else
7047 {
7048 ptr2len = mb_ptr2len;
7049 ptr2char = mb_ptr2char;
7050 }
7051
7052 for ( ; *p != NUL; p += (*ptr2len)(p))
7053 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7054 }
7055 else
7056 for ( ; *p != NUL; ++p)
7057 list_append_number(rettv->vval.v_list, *p);
7058}
7059
7060/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007061 * "str2nr()" function
7062 */
7063 static void
7064f_str2nr(typval_T *argvars, typval_T *rettv)
7065{
7066 int base = 10;
7067 char_u *p;
7068 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007069 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007070 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071
7072 if (argvars[1].v_type != VAR_UNKNOWN)
7073 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007074 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075 if (base != 2 && base != 8 && base != 10 && base != 16)
7076 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007077 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078 return;
7079 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007080 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7081 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007082 }
7083
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007084 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007085 isneg = (*p == '-');
7086 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007087 p = skipwhite(p + 1);
7088 switch (base)
7089 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007090 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7091 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7092 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007093 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007094 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7095 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007096 if (isneg)
7097 rettv->vval.v_number = -n;
7098 else
7099 rettv->vval.v_number = n;
7100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007101}
7102
7103#ifdef HAVE_STRFTIME
7104/*
7105 * "strftime({format}[, {time}])" function
7106 */
7107 static void
7108f_strftime(typval_T *argvars, typval_T *rettv)
7109{
7110 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007111 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007112 struct tm *curtime;
7113 time_t seconds;
7114 char_u *p;
7115
7116 rettv->v_type = VAR_STRING;
7117
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007118 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007119 if (argvars[1].v_type == VAR_UNKNOWN)
7120 seconds = time(NULL);
7121 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007122 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007123 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007124 /* MSVC returns NULL for an invalid value of seconds. */
7125 if (curtime == NULL)
7126 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7127 else
7128 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007129 vimconv_T conv;
7130 char_u *enc;
7131
7132 conv.vc_type = CONV_NONE;
7133 enc = enc_locale();
7134 convert_setup(&conv, p_enc, enc);
7135 if (conv.vc_type != CONV_NONE)
7136 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007137 if (p != NULL)
7138 (void)strftime((char *)result_buf, sizeof(result_buf),
7139 (char *)p, curtime);
7140 else
7141 result_buf[0] = NUL;
7142
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007143 if (conv.vc_type != CONV_NONE)
7144 vim_free(p);
7145 convert_setup(&conv, enc, p_enc);
7146 if (conv.vc_type != CONV_NONE)
7147 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7148 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007149 rettv->vval.v_string = vim_strsave(result_buf);
7150
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007151 /* Release conversion descriptors */
7152 convert_setup(&conv, NULL, NULL);
7153 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007154 }
7155}
7156#endif
7157
7158/*
7159 * "strgetchar()" function
7160 */
7161 static void
7162f_strgetchar(typval_T *argvars, typval_T *rettv)
7163{
7164 char_u *str;
7165 int len;
7166 int error = FALSE;
7167 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007168 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007169
7170 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007171 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007172 if (str == NULL)
7173 return;
7174 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007175 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007176 if (error)
7177 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007178
Bram Moolenaar13505972019-01-24 15:04:48 +01007179 while (charidx >= 0 && byteidx < len)
7180 {
7181 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007182 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007183 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7184 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007185 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007186 --charidx;
7187 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007189}
7190
7191/*
7192 * "stridx()" function
7193 */
7194 static void
7195f_stridx(typval_T *argvars, typval_T *rettv)
7196{
7197 char_u buf[NUMBUFLEN];
7198 char_u *needle;
7199 char_u *haystack;
7200 char_u *save_haystack;
7201 char_u *pos;
7202 int start_idx;
7203
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007204 needle = tv_get_string_chk(&argvars[1]);
7205 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007206 rettv->vval.v_number = -1;
7207 if (needle == NULL || haystack == NULL)
7208 return; /* type error; errmsg already given */
7209
7210 if (argvars[2].v_type != VAR_UNKNOWN)
7211 {
7212 int error = FALSE;
7213
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007214 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007215 if (error || start_idx >= (int)STRLEN(haystack))
7216 return;
7217 if (start_idx >= 0)
7218 haystack += start_idx;
7219 }
7220
7221 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7222 if (pos != NULL)
7223 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7224}
7225
7226/*
7227 * "string()" function
7228 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007229 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230f_string(typval_T *argvars, typval_T *rettv)
7231{
7232 char_u *tofree;
7233 char_u numbuf[NUMBUFLEN];
7234
7235 rettv->v_type = VAR_STRING;
7236 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7237 get_copyID());
7238 /* Make a copy if we have a value but it's not in allocated memory. */
7239 if (rettv->vval.v_string != NULL && tofree == NULL)
7240 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7241}
7242
7243/*
7244 * "strlen()" function
7245 */
7246 static void
7247f_strlen(typval_T *argvars, typval_T *rettv)
7248{
7249 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007250 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007251}
7252
7253/*
7254 * "strchars()" function
7255 */
7256 static void
7257f_strchars(typval_T *argvars, typval_T *rettv)
7258{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007259 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007260 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007261 varnumber_T len = 0;
7262 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007263
7264 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007265 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007266 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007267 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007268 else
7269 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007270 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7271 while (*s != NUL)
7272 {
7273 func_mb_ptr2char_adv(&s);
7274 ++len;
7275 }
7276 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007277 }
7278}
7279
7280/*
7281 * "strdisplaywidth()" function
7282 */
7283 static void
7284f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7285{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007286 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007287 int col = 0;
7288
7289 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007290 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007291
7292 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7293}
7294
7295/*
7296 * "strwidth()" function
7297 */
7298 static void
7299f_strwidth(typval_T *argvars, typval_T *rettv)
7300{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007301 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007302
Bram Moolenaar13505972019-01-24 15:04:48 +01007303 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007304}
7305
7306/*
7307 * "strcharpart()" function
7308 */
7309 static void
7310f_strcharpart(typval_T *argvars, typval_T *rettv)
7311{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007312 char_u *p;
7313 int nchar;
7314 int nbyte = 0;
7315 int charlen;
7316 int len = 0;
7317 int slen;
7318 int error = FALSE;
7319
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007320 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007321 slen = (int)STRLEN(p);
7322
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007323 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007324 if (!error)
7325 {
7326 if (nchar > 0)
7327 while (nchar > 0 && nbyte < slen)
7328 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007329 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007330 --nchar;
7331 }
7332 else
7333 nbyte = nchar;
7334 if (argvars[2].v_type != VAR_UNKNOWN)
7335 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007336 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007337 while (charlen > 0 && nbyte + len < slen)
7338 {
7339 int off = nbyte + len;
7340
7341 if (off < 0)
7342 len += 1;
7343 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007344 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 --charlen;
7346 }
7347 }
7348 else
7349 len = slen - nbyte; /* default: all bytes that are available. */
7350 }
7351
7352 /*
7353 * Only return the overlap between the specified part and the actual
7354 * string.
7355 */
7356 if (nbyte < 0)
7357 {
7358 len += nbyte;
7359 nbyte = 0;
7360 }
7361 else if (nbyte > slen)
7362 nbyte = slen;
7363 if (len < 0)
7364 len = 0;
7365 else if (nbyte + len > slen)
7366 len = slen - nbyte;
7367
7368 rettv->v_type = VAR_STRING;
7369 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007370}
7371
7372/*
7373 * "strpart()" function
7374 */
7375 static void
7376f_strpart(typval_T *argvars, typval_T *rettv)
7377{
7378 char_u *p;
7379 int n;
7380 int len;
7381 int slen;
7382 int error = FALSE;
7383
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007384 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007385 slen = (int)STRLEN(p);
7386
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007387 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388 if (error)
7389 len = 0;
7390 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007391 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007392 else
7393 len = slen - n; /* default len: all bytes that are available. */
7394
7395 /*
7396 * Only return the overlap between the specified part and the actual
7397 * string.
7398 */
7399 if (n < 0)
7400 {
7401 len += n;
7402 n = 0;
7403 }
7404 else if (n > slen)
7405 n = slen;
7406 if (len < 0)
7407 len = 0;
7408 else if (n + len > slen)
7409 len = slen - n;
7410
7411 rettv->v_type = VAR_STRING;
7412 rettv->vval.v_string = vim_strnsave(p + n, len);
7413}
7414
7415/*
7416 * "strridx()" function
7417 */
7418 static void
7419f_strridx(typval_T *argvars, typval_T *rettv)
7420{
7421 char_u buf[NUMBUFLEN];
7422 char_u *needle;
7423 char_u *haystack;
7424 char_u *rest;
7425 char_u *lastmatch = NULL;
7426 int haystack_len, end_idx;
7427
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007428 needle = tv_get_string_chk(&argvars[1]);
7429 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007430
7431 rettv->vval.v_number = -1;
7432 if (needle == NULL || haystack == NULL)
7433 return; /* type error; errmsg already given */
7434
7435 haystack_len = (int)STRLEN(haystack);
7436 if (argvars[2].v_type != VAR_UNKNOWN)
7437 {
7438 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007439 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 if (end_idx < 0)
7441 return; /* can never find a match */
7442 }
7443 else
7444 end_idx = haystack_len;
7445
7446 if (*needle == NUL)
7447 {
7448 /* Empty string matches past the end. */
7449 lastmatch = haystack + end_idx;
7450 }
7451 else
7452 {
7453 for (rest = haystack; *rest != '\0'; ++rest)
7454 {
7455 rest = (char_u *)strstr((char *)rest, (char *)needle);
7456 if (rest == NULL || rest > haystack + end_idx)
7457 break;
7458 lastmatch = rest;
7459 }
7460 }
7461
7462 if (lastmatch == NULL)
7463 rettv->vval.v_number = -1;
7464 else
7465 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7466}
7467
7468/*
7469 * "strtrans()" function
7470 */
7471 static void
7472f_strtrans(typval_T *argvars, typval_T *rettv)
7473{
7474 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007475 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007476}
7477
7478/*
7479 * "submatch()" function
7480 */
7481 static void
7482f_submatch(typval_T *argvars, typval_T *rettv)
7483{
7484 int error = FALSE;
7485 int no;
7486 int retList = 0;
7487
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007488 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007489 if (error)
7490 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007491 if (no < 0 || no >= NSUBEXP)
7492 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007493 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007494 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007495 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007496 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007497 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007498 if (error)
7499 return;
7500
7501 if (retList == 0)
7502 {
7503 rettv->v_type = VAR_STRING;
7504 rettv->vval.v_string = reg_submatch(no);
7505 }
7506 else
7507 {
7508 rettv->v_type = VAR_LIST;
7509 rettv->vval.v_list = reg_submatch_list(no);
7510 }
7511}
7512
7513/*
7514 * "substitute()" function
7515 */
7516 static void
7517f_substitute(typval_T *argvars, typval_T *rettv)
7518{
7519 char_u patbuf[NUMBUFLEN];
7520 char_u subbuf[NUMBUFLEN];
7521 char_u flagsbuf[NUMBUFLEN];
7522
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007523 char_u *str = tv_get_string_chk(&argvars[0]);
7524 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007525 char_u *sub = NULL;
7526 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007527 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007528
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007529 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7530 expr = &argvars[2];
7531 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007532 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007533
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007534 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007535 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7536 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537 rettv->vval.v_string = NULL;
7538 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007539 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540}
7541
7542/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007543 * "swapinfo(swap_filename)" function
7544 */
7545 static void
7546f_swapinfo(typval_T *argvars, typval_T *rettv)
7547{
7548 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007549 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007550}
7551
7552/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007553 * "swapname(expr)" function
7554 */
7555 static void
7556f_swapname(typval_T *argvars, typval_T *rettv)
7557{
7558 buf_T *buf;
7559
7560 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007561 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007562 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7563 || buf->b_ml.ml_mfp->mf_fname == NULL)
7564 rettv->vval.v_string = NULL;
7565 else
7566 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7567}
7568
7569/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007570 * "synID(lnum, col, trans)" function
7571 */
7572 static void
7573f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7574{
7575 int id = 0;
7576#ifdef FEAT_SYN_HL
7577 linenr_T lnum;
7578 colnr_T col;
7579 int trans;
7580 int transerr = FALSE;
7581
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007582 lnum = tv_get_lnum(argvars); /* -1 on type error */
7583 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7584 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007585
7586 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7587 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7588 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7589#endif
7590
7591 rettv->vval.v_number = id;
7592}
7593
7594/*
7595 * "synIDattr(id, what [, mode])" function
7596 */
7597 static void
7598f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7599{
7600 char_u *p = NULL;
7601#ifdef FEAT_SYN_HL
7602 int id;
7603 char_u *what;
7604 char_u *mode;
7605 char_u modebuf[NUMBUFLEN];
7606 int modec;
7607
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007608 id = (int)tv_get_number(&argvars[0]);
7609 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007610 if (argvars[2].v_type != VAR_UNKNOWN)
7611 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007612 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007613 modec = TOLOWER_ASC(mode[0]);
7614 if (modec != 't' && modec != 'c' && modec != 'g')
7615 modec = 0; /* replace invalid with current */
7616 }
7617 else
7618 {
7619#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7620 if (USE_24BIT)
7621 modec = 'g';
7622 else
7623#endif
7624 if (t_colors > 1)
7625 modec = 'c';
7626 else
7627 modec = 't';
7628 }
7629
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007630 switch (TOLOWER_ASC(what[0]))
7631 {
7632 case 'b':
7633 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7634 p = highlight_color(id, what, modec);
7635 else /* bold */
7636 p = highlight_has_attr(id, HL_BOLD, modec);
7637 break;
7638
7639 case 'f': /* fg[#] or font */
7640 p = highlight_color(id, what, modec);
7641 break;
7642
7643 case 'i':
7644 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7645 p = highlight_has_attr(id, HL_INVERSE, modec);
7646 else /* italic */
7647 p = highlight_has_attr(id, HL_ITALIC, modec);
7648 break;
7649
7650 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007651 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007652 break;
7653
7654 case 'r': /* reverse */
7655 p = highlight_has_attr(id, HL_INVERSE, modec);
7656 break;
7657
7658 case 's':
7659 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7660 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007661 /* strikeout */
7662 else if (TOLOWER_ASC(what[1]) == 't' &&
7663 TOLOWER_ASC(what[2]) == 'r')
7664 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007665 else /* standout */
7666 p = highlight_has_attr(id, HL_STANDOUT, modec);
7667 break;
7668
7669 case 'u':
7670 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7671 /* underline */
7672 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7673 else
7674 /* undercurl */
7675 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7676 break;
7677 }
7678
7679 if (p != NULL)
7680 p = vim_strsave(p);
7681#endif
7682 rettv->v_type = VAR_STRING;
7683 rettv->vval.v_string = p;
7684}
7685
7686/*
7687 * "synIDtrans(id)" function
7688 */
7689 static void
7690f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7691{
7692 int id;
7693
7694#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007695 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007696
7697 if (id > 0)
7698 id = syn_get_final_id(id);
7699 else
7700#endif
7701 id = 0;
7702
7703 rettv->vval.v_number = id;
7704}
7705
7706/*
7707 * "synconcealed(lnum, col)" function
7708 */
7709 static void
7710f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7711{
7712#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7713 linenr_T lnum;
7714 colnr_T col;
7715 int syntax_flags = 0;
7716 int cchar;
7717 int matchid = 0;
7718 char_u str[NUMBUFLEN];
7719#endif
7720
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007721 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722
7723#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007724 lnum = tv_get_lnum(argvars); /* -1 on type error */
7725 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726
7727 vim_memset(str, NUL, sizeof(str));
7728
7729 if (rettv_list_alloc(rettv) != FAIL)
7730 {
7731 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7732 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7733 && curwin->w_p_cole > 0)
7734 {
7735 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7736 syntax_flags = get_syntax_info(&matchid);
7737
7738 /* get the conceal character */
7739 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7740 {
7741 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007742 if (cchar == NUL && curwin->w_p_cole == 1)
7743 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 if (cchar != NUL)
7745 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007746 if (has_mbyte)
7747 (*mb_char2bytes)(cchar, str);
7748 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007749 str[0] = cchar;
7750 }
7751 }
7752 }
7753
7754 list_append_number(rettv->vval.v_list,
7755 (syntax_flags & HL_CONCEAL) != 0);
7756 /* -1 to auto-determine strlen */
7757 list_append_string(rettv->vval.v_list, str, -1);
7758 list_append_number(rettv->vval.v_list, matchid);
7759 }
7760#endif
7761}
7762
7763/*
7764 * "synstack(lnum, col)" function
7765 */
7766 static void
7767f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7768{
7769#ifdef FEAT_SYN_HL
7770 linenr_T lnum;
7771 colnr_T col;
7772 int i;
7773 int id;
7774#endif
7775
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007776 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777
7778#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007779 lnum = tv_get_lnum(argvars); /* -1 on type error */
7780 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007781
7782 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7783 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7784 && rettv_list_alloc(rettv) != FAIL)
7785 {
7786 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
7787 for (i = 0; ; ++i)
7788 {
7789 id = syn_get_stack_item(i);
7790 if (id < 0)
7791 break;
7792 if (list_append_number(rettv->vval.v_list, id) == FAIL)
7793 break;
7794 }
7795 }
7796#endif
7797}
7798
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007799/*
7800 * "tabpagebuflist()" function
7801 */
7802 static void
7803f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7804{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805 tabpage_T *tp;
7806 win_T *wp = NULL;
7807
7808 if (argvars[0].v_type == VAR_UNKNOWN)
7809 wp = firstwin;
7810 else
7811 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007812 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007813 if (tp != NULL)
7814 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
7815 }
7816 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
7817 {
7818 for (; wp != NULL; wp = wp->w_next)
7819 if (list_append_number(rettv->vval.v_list,
7820 wp->w_buffer->b_fnum) == FAIL)
7821 break;
7822 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007823}
7824
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007825/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 * "tagfiles()" function
7827 */
7828 static void
7829f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
7830{
7831 char_u *fname;
7832 tagname_T tn;
7833 int first;
7834
7835 if (rettv_list_alloc(rettv) == FAIL)
7836 return;
7837 fname = alloc(MAXPATHL);
7838 if (fname == NULL)
7839 return;
7840
7841 for (first = TRUE; ; first = FALSE)
7842 if (get_tagfname(&tn, first, fname) == FAIL
7843 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
7844 break;
7845 tagname_free(&tn);
7846 vim_free(fname);
7847}
7848
7849/*
7850 * "taglist()" function
7851 */
7852 static void
7853f_taglist(typval_T *argvars, typval_T *rettv)
7854{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007855 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007856 char_u *tag_pattern;
7857
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007858 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859
7860 rettv->vval.v_number = FALSE;
7861 if (*tag_pattern == NUL)
7862 return;
7863
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007864 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007865 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007867 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868}
7869
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007870#ifdef FEAT_FLOAT
7871/*
7872 * "tan()" function
7873 */
7874 static void
7875f_tan(typval_T *argvars, typval_T *rettv)
7876{
7877 float_T f = 0.0;
7878
7879 rettv->v_type = VAR_FLOAT;
7880 if (get_float_arg(argvars, &f) == OK)
7881 rettv->vval.v_float = tan(f);
7882 else
7883 rettv->vval.v_float = 0.0;
7884}
7885
7886/*
7887 * "tanh()" function
7888 */
7889 static void
7890f_tanh(typval_T *argvars, typval_T *rettv)
7891{
7892 float_T f = 0.0;
7893
7894 rettv->v_type = VAR_FLOAT;
7895 if (get_float_arg(argvars, &f) == OK)
7896 rettv->vval.v_float = tanh(f);
7897 else
7898 rettv->vval.v_float = 0.0;
7899}
7900#endif
7901
7902/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007903 * "tolower(string)" function
7904 */
7905 static void
7906f_tolower(typval_T *argvars, typval_T *rettv)
7907{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007908 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007909 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910}
7911
7912/*
7913 * "toupper(string)" function
7914 */
7915 static void
7916f_toupper(typval_T *argvars, typval_T *rettv)
7917{
7918 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007919 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007920}
7921
7922/*
7923 * "tr(string, fromstr, tostr)" function
7924 */
7925 static void
7926f_tr(typval_T *argvars, typval_T *rettv)
7927{
7928 char_u *in_str;
7929 char_u *fromstr;
7930 char_u *tostr;
7931 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007932 int inlen;
7933 int fromlen;
7934 int tolen;
7935 int idx;
7936 char_u *cpstr;
7937 int cplen;
7938 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007939 char_u buf[NUMBUFLEN];
7940 char_u buf2[NUMBUFLEN];
7941 garray_T ga;
7942
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007943 in_str = tv_get_string(&argvars[0]);
7944 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
7945 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007946
7947 /* Default return value: empty string. */
7948 rettv->v_type = VAR_STRING;
7949 rettv->vval.v_string = NULL;
7950 if (fromstr == NULL || tostr == NULL)
7951 return; /* type error; errmsg already given */
7952 ga_init2(&ga, (int)sizeof(char), 80);
7953
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007954 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007955 /* not multi-byte: fromstr and tostr must be the same length */
7956 if (STRLEN(fromstr) != STRLEN(tostr))
7957 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007958error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007959 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960 ga_clear(&ga);
7961 return;
7962 }
7963
7964 /* fromstr and tostr have to contain the same number of chars */
7965 while (*in_str != NUL)
7966 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007967 if (has_mbyte)
7968 {
7969 inlen = (*mb_ptr2len)(in_str);
7970 cpstr = in_str;
7971 cplen = inlen;
7972 idx = 0;
7973 for (p = fromstr; *p != NUL; p += fromlen)
7974 {
7975 fromlen = (*mb_ptr2len)(p);
7976 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
7977 {
7978 for (p = tostr; *p != NUL; p += tolen)
7979 {
7980 tolen = (*mb_ptr2len)(p);
7981 if (idx-- == 0)
7982 {
7983 cplen = tolen;
7984 cpstr = p;
7985 break;
7986 }
7987 }
7988 if (*p == NUL) /* tostr is shorter than fromstr */
7989 goto error;
7990 break;
7991 }
7992 ++idx;
7993 }
7994
7995 if (first && cpstr == in_str)
7996 {
7997 /* Check that fromstr and tostr have the same number of
7998 * (multi-byte) characters. Done only once when a character
7999 * of in_str doesn't appear in fromstr. */
8000 first = FALSE;
8001 for (p = tostr; *p != NUL; p += tolen)
8002 {
8003 tolen = (*mb_ptr2len)(p);
8004 --idx;
8005 }
8006 if (idx != 0)
8007 goto error;
8008 }
8009
8010 (void)ga_grow(&ga, cplen);
8011 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8012 ga.ga_len += cplen;
8013
8014 in_str += inlen;
8015 }
8016 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008017 {
8018 /* When not using multi-byte chars we can do it faster. */
8019 p = vim_strchr(fromstr, *in_str);
8020 if (p != NULL)
8021 ga_append(&ga, tostr[p - fromstr]);
8022 else
8023 ga_append(&ga, *in_str);
8024 ++in_str;
8025 }
8026 }
8027
8028 /* add a terminating NUL */
8029 (void)ga_grow(&ga, 1);
8030 ga_append(&ga, NUL);
8031
8032 rettv->vval.v_string = ga.ga_data;
8033}
8034
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008035/*
8036 * "trim({expr})" function
8037 */
8038 static void
8039f_trim(typval_T *argvars, typval_T *rettv)
8040{
8041 char_u buf1[NUMBUFLEN];
8042 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008043 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008044 char_u *mask = NULL;
8045 char_u *tail;
8046 char_u *prev;
8047 char_u *p;
8048 int c1;
8049
8050 rettv->v_type = VAR_STRING;
8051 if (head == NULL)
8052 {
8053 rettv->vval.v_string = NULL;
8054 return;
8055 }
8056
8057 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008058 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008059
8060 while (*head != NUL)
8061 {
8062 c1 = PTR2CHAR(head);
8063 if (mask == NULL)
8064 {
8065 if (c1 > ' ' && c1 != 0xa0)
8066 break;
8067 }
8068 else
8069 {
8070 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8071 if (c1 == PTR2CHAR(p))
8072 break;
8073 if (*p == NUL)
8074 break;
8075 }
8076 MB_PTR_ADV(head);
8077 }
8078
8079 for (tail = head + STRLEN(head); tail > head; tail = prev)
8080 {
8081 prev = tail;
8082 MB_PTR_BACK(head, prev);
8083 c1 = PTR2CHAR(prev);
8084 if (mask == NULL)
8085 {
8086 if (c1 > ' ' && c1 != 0xa0)
8087 break;
8088 }
8089 else
8090 {
8091 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8092 if (c1 == PTR2CHAR(p))
8093 break;
8094 if (*p == NUL)
8095 break;
8096 }
8097 }
8098 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8099}
8100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008101#ifdef FEAT_FLOAT
8102/*
8103 * "trunc({float})" function
8104 */
8105 static void
8106f_trunc(typval_T *argvars, typval_T *rettv)
8107{
8108 float_T f = 0.0;
8109
8110 rettv->v_type = VAR_FLOAT;
8111 if (get_float_arg(argvars, &f) == OK)
8112 /* trunc() is not in C90, use floor() or ceil() instead. */
8113 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8114 else
8115 rettv->vval.v_float = 0.0;
8116}
8117#endif
8118
8119/*
8120 * "type(expr)" function
8121 */
8122 static void
8123f_type(typval_T *argvars, typval_T *rettv)
8124{
8125 int n = -1;
8126
8127 switch (argvars[0].v_type)
8128 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008129 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8130 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008131 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008132 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8133 case VAR_LIST: n = VAR_TYPE_LIST; break;
8134 case VAR_DICT: n = VAR_TYPE_DICT; break;
8135 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008136 case VAR_SPECIAL:
8137 if (argvars[0].vval.v_number == VVAL_FALSE
8138 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008139 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008140 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008141 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008142 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008143 case VAR_JOB: n = VAR_TYPE_JOB; break;
8144 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008145 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008146 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008147 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148 n = -1;
8149 break;
8150 }
8151 rettv->vval.v_number = n;
8152}
8153
8154/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008155 * "virtcol(string)" function
8156 */
8157 static void
8158f_virtcol(typval_T *argvars, typval_T *rettv)
8159{
8160 colnr_T vcol = 0;
8161 pos_T *fp;
8162 int fnum = curbuf->b_fnum;
8163
8164 fp = var2fpos(&argvars[0], FALSE, &fnum);
8165 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8166 && fnum == curbuf->b_fnum)
8167 {
8168 getvvcol(curwin, fp, NULL, NULL, &vcol);
8169 ++vcol;
8170 }
8171
8172 rettv->vval.v_number = vcol;
8173}
8174
8175/*
8176 * "visualmode()" function
8177 */
8178 static void
8179f_visualmode(typval_T *argvars, typval_T *rettv)
8180{
8181 char_u str[2];
8182
8183 rettv->v_type = VAR_STRING;
8184 str[0] = curbuf->b_visual_mode_eval;
8185 str[1] = NUL;
8186 rettv->vval.v_string = vim_strsave(str);
8187
8188 /* A non-zero number or non-empty string argument: reset mode. */
8189 if (non_zero_arg(&argvars[0]))
8190 curbuf->b_visual_mode_eval = NUL;
8191}
8192
8193/*
8194 * "wildmenumode()" function
8195 */
8196 static void
8197f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8198{
8199#ifdef FEAT_WILDMENU
8200 if (wild_menu_showing)
8201 rettv->vval.v_number = 1;
8202#endif
8203}
8204
8205/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008206 * "wordcount()" function
8207 */
8208 static void
8209f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8210{
8211 if (rettv_dict_alloc(rettv) == FAIL)
8212 return;
8213 cursor_pos_info(rettv->vval.v_dict);
8214}
8215
8216/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008217 * "xor(expr, expr)" function
8218 */
8219 static void
8220f_xor(typval_T *argvars, typval_T *rettv)
8221{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008222 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8223 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008224}
8225
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226#endif /* FEAT_EVAL */