blob: e5be361406c52d7df2f0a5221ab9e2e124e4466b [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},
468 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200469 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200470 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200471 {"getreg", 0, 3, FEARG_1, f_getreg},
472 {"getregtype", 0, 1, FEARG_1, f_getregtype},
473 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
474 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
475 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200476 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
477 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
478 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200479 {"getwinposx", 0, 0, 0, f_getwinposx},
480 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200481 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
482 {"glob", 1, 4, FEARG_1, f_glob},
483 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
484 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200485 {"has", 1, 1, 0, f_has},
486 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200487 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
488 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
489 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
490 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
491 {"histadd", 2, 2, FEARG_2, f_histadd},
492 {"histdel", 1, 2, FEARG_1, f_histdel},
493 {"histget", 1, 2, FEARG_1, f_histget},
494 {"histnr", 1, 1, FEARG_1, f_histnr},
495 {"hlID", 1, 1, FEARG_1, f_hlID},
496 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200497 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200498 {"iconv", 3, 3, FEARG_1, f_iconv},
499 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200500 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200501 {"input", 1, 3, FEARG_1, f_input},
502 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
503 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"inputrestore", 0, 0, 0, f_inputrestore},
505 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200506 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200507 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200508 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200509 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200510#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200511 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200512#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200513 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200514#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200515 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200517 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200518#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200519 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
520 {"job_info", 0, 1, FEARG_1, f_job_info},
521 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
522 {"job_start", 1, 2, FEARG_1, f_job_start},
523 {"job_status", 1, 1, FEARG_1, f_job_status},
524 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200526 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200527 {"js_decode", 1, 1, FEARG_1, f_js_decode},
528 {"js_encode", 1, 1, FEARG_1, f_js_encode},
529 {"json_decode", 1, 1, FEARG_1, f_json_decode},
530 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200531 {"keys", 1, 1, FEARG_1, f_keys},
532 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
533 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200534 {"libcall", 3, 3, FEARG_3, f_libcall},
535 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200536 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200537 {"line2byte", 1, 1, FEARG_1, f_line2byte},
538 {"lispindent", 1, 1, FEARG_1, f_lispindent},
539 {"list2str", 1, 2, FEARG_1, f_list2str},
540 {"listener_add", 1, 2, FEARG_2, f_listener_add},
541 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
542 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200543 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200544#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200545 {"log", 1, 1, FEARG_1, f_log},
546 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200547#endif
548#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200549 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200551 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200552 {"maparg", 1, 4, FEARG_1, f_maparg},
553 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
554 {"match", 2, 4, FEARG_1, f_match},
555 {"matchadd", 2, 5, FEARG_1, f_matchadd},
556 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
557 {"matcharg", 1, 1, FEARG_1, f_matcharg},
558 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
559 {"matchend", 2, 4, FEARG_1, f_matchend},
560 {"matchlist", 2, 4, FEARG_1, f_matchlist},
561 {"matchstr", 2, 4, FEARG_1, f_matchstr},
562 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200563 {"max", 1, 1, FEARG_1, f_max},
564 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200565 {"mkdir", 1, 3, FEARG_1, f_mkdir},
566 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200567#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200568 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200569#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200570 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
571 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200572 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200573 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200574#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200575 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200576#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200577#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200578 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
579 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200580 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200581 {"popup_close", 1, 2, FEARG_1, f_popup_close},
582 {"popup_create", 2, 2, FEARG_1, f_popup_create},
583 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200584 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
585 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200586 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
587 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200588 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
589 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
590 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200591 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200592 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
593 {"popup_move", 2, 2, FEARG_1, f_popup_move},
594 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
595 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
596 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
597 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200598#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200599#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200600 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200602 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200603 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200604#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200605 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
606 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
607 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200608#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100609#ifdef FEAT_TEXT_PROP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200610 {"prop_add", 3, 3, FEARG_1, f_prop_add},
611 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
612 {"prop_list", 1, 2, FEARG_1, f_prop_list},
613 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
614 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
615 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
616 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
617 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
618 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100619#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200620 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200621 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200622#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200623 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200624#endif
625#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200626 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200627#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100628#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200629 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100630#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200631 {"range", 1, 3, FEARG_1, f_range},
632 {"readdir", 1, 2, FEARG_1, f_readdir},
633 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200634 {"reg_executing", 0, 0, 0, f_reg_executing},
635 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200636 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200638 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200639#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200640 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
641 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
642 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
643 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
644 {"remote_read", 1, 2, FEARG_1, f_remote_read},
645 {"remote_send", 2, 3, FEARG_1, f_remote_send},
646 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200647 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200648 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200649 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200650 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200651 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200652#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200653 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200654#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100655#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200656 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100657#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200658 {"screenattr", 2, 2, FEARG_1, f_screenattr},
659 {"screenchar", 2, 2, FEARG_1, f_screenchar},
660 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200661 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200662 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200663 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200664 {"screenstring", 2, 2, FEARG_1, f_screenstring},
665 {"search", 1, 4, FEARG_1, f_search},
666 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200667 {"searchpair", 3, 7, 0, f_searchpair},
668 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200669 {"searchpos", 1, 4, FEARG_1, f_searchpos},
670 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200671 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200672 {"setbufline", 3, 3, FEARG_3, f_setbufline},
673 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
674 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
675 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
676 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200677 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200678 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200679 {"setloclist", 2, 4, FEARG_2, f_setloclist},
680 {"setmatches", 1, 2, FEARG_1, f_setmatches},
681 {"setpos", 2, 2, FEARG_2, f_setpos},
682 {"setqflist", 1, 3, FEARG_1, f_setqflist},
683 {"setreg", 2, 3, FEARG_2, f_setreg},
684 {"settabvar", 3, 3, FEARG_3, f_settabvar},
685 {"settabwinvar", 4, 4, FEARG_4, f_settabwinvar},
686 {"settagstack", 2, 3, FEARG_2, f_settagstack},
687 {"setwinvar", 3, 3, FEARG_3, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688#ifdef FEAT_CRYPT
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200689 {"sha256", 1, 1, FEARG_1, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200690#endif
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200691 {"shellescape", 1, 2, FEARG_1, f_shellescape},
692 {"shiftwidth", 0, 1, FEARG_1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100693#ifdef FEAT_SIGNS
Bram Moolenaar93476fd2019-09-06 22:00:54 +0200694 {"sign_define", 1, 2, FEARG_1, f_sign_define},
695 {"sign_getdefined", 0, 1, FEARG_1, f_sign_getdefined},
696 {"sign_getplaced", 0, 2, FEARG_1, f_sign_getplaced},
697 {"sign_jump", 3, 3, FEARG_1, f_sign_jump},
698 {"sign_place", 4, 5, FEARG_1, f_sign_place},
699 {"sign_placelist", 1, 1, FEARG_1, f_sign_placelist},
700 {"sign_undefine", 0, 1, FEARG_1, f_sign_undefine},
701 {"sign_unplace", 1, 2, FEARG_1, f_sign_unplace},
702 {"sign_unplacelist", 1, 2, FEARG_1, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100703#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200704 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200705#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200706 {"sin", 1, 1, FEARG_1, f_sin},
707 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200708#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200709 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200710#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200711 {"sound_clear", 0, 0, 0, f_sound_clear},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200712 {"sound_playevent", 1, 2, FEARG_1, f_sound_playevent},
713 {"sound_playfile", 1, 2, FEARG_1, f_sound_playfile},
714 {"sound_stop", 1, 1, FEARG_1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200715#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200716 {"soundfold", 1, 1, FEARG_1, f_soundfold},
717 {"spellbadword", 0, 1, FEARG_1, f_spellbadword},
718 {"spellsuggest", 1, 3, FEARG_1, f_spellsuggest},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200719 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200720#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200721 {"sqrt", 1, 1, FEARG_1, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200722#endif
723 {"state", 0, 1, FEARG_1, f_state},
724#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200725 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200726#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200727 {"str2list", 1, 2, FEARG_1, f_str2list},
Bram Moolenaar60a8de22019-09-15 14:33:22 +0200728 {"str2nr", 1, 3, FEARG_1, f_str2nr},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200729 {"strcharpart", 2, 3, FEARG_1, f_strcharpart},
730 {"strchars", 1, 2, FEARG_1, f_strchars},
731 {"strdisplaywidth", 1, 2, FEARG_1, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200732#ifdef HAVE_STRFTIME
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200733 {"strftime", 1, 2, FEARG_1, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200734#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200735 {"strgetchar", 2, 2, FEARG_1, f_strgetchar},
736 {"stridx", 2, 3, FEARG_1, f_stridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200737 {"string", 1, 1, FEARG_1, f_string},
738 {"strlen", 1, 1, FEARG_1, f_strlen},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200739 {"strpart", 2, 3, FEARG_1, f_strpart},
740 {"strridx", 2, 3, FEARG_1, f_strridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200741 {"strtrans", 1, 1, FEARG_1, f_strtrans},
742 {"strwidth", 1, 1, FEARG_1, f_strwidth},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200743 {"submatch", 1, 2, FEARG_1, f_submatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200744 {"substitute", 4, 4, FEARG_1, f_substitute},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200745 {"swapinfo", 1, 1, FEARG_1, f_swapinfo},
746 {"swapname", 1, 1, FEARG_1, f_swapname},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200747 {"synID", 3, 3, 0, f_synID},
748 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
749 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
750 {"synconcealed", 2, 2, 0, f_synconcealed},
751 {"synstack", 2, 2, 0, f_synstack},
752 {"system", 1, 2, FEARG_1, f_system},
753 {"systemlist", 1, 2, FEARG_1, f_systemlist},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200754 {"tabpagebuflist", 0, 1, FEARG_1, f_tabpagebuflist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200755 {"tabpagenr", 0, 1, 0, f_tabpagenr},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200756 {"tabpagewinnr", 1, 2, FEARG_1, f_tabpagewinnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200757 {"tagfiles", 0, 0, 0, f_tagfiles},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200758 {"taglist", 1, 2, FEARG_1, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200759#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200760 {"tan", 1, 1, FEARG_1, f_tan},
761 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200763 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200764#ifdef FEAT_TERMINAL
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200765 {"term_dumpdiff", 2, 3, FEARG_1, f_term_dumpdiff},
766 {"term_dumpload", 1, 2, FEARG_1, f_term_dumpload},
767 {"term_dumpwrite", 2, 3, FEARG_2, f_term_dumpwrite},
768 {"term_getaltscreen", 1, 1, FEARG_1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200769# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200770 {"term_getansicolors", 1, 1, FEARG_1, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200771# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200772 {"term_getattr", 2, 2, FEARG_1, f_term_getattr},
773 {"term_getcursor", 1, 1, FEARG_1, f_term_getcursor},
774 {"term_getjob", 1, 1, FEARG_1, f_term_getjob},
775 {"term_getline", 2, 2, FEARG_1, f_term_getline},
776 {"term_getscrolled", 1, 1, FEARG_1, f_term_getscrolled},
777 {"term_getsize", 1, 1, FEARG_1, f_term_getsize},
778 {"term_getstatus", 1, 1, FEARG_1, f_term_getstatus},
779 {"term_gettitle", 1, 1, FEARG_1, f_term_gettitle},
780 {"term_gettty", 1, 2, FEARG_1, f_term_gettty},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200781 {"term_list", 0, 0, 0, f_term_list},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200782 {"term_scrape", 2, 2, FEARG_1, f_term_scrape},
783 {"term_sendkeys", 2, 2, FEARG_1, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200784# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200785 {"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200786# endif
Bram Moolenaard2842ea2019-09-26 23:08:54 +0200787 {"term_setapi", 2, 2, FEARG_1, f_term_setapi},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200788 {"term_setkill", 2, 2, FEARG_1, f_term_setkill},
789 {"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
790 {"term_setsize", 3, 3, FEARG_1, f_term_setsize},
791 {"term_start", 1, 2, FEARG_1, f_term_start},
792 {"term_wait", 1, 2, FEARG_1, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200793#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200794 {"test_alloc_fail", 3, 3, FEARG_1, f_test_alloc_fail},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200795 {"test_autochdir", 0, 0, 0, f_test_autochdir},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200796 {"test_feedinput", 1, 1, FEARG_1, f_test_feedinput},
797 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
798 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
799 {"test_getvalue", 1, 1, FEARG_1, f_test_getvalue},
800 {"test_ignore_error", 1, 1, FEARG_1, f_test_ignore_error},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200801 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200802#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200803 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200805 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200806#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200807 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200809 {"test_null_list", 0, 0, 0, f_test_null_list},
810 {"test_null_partial", 0, 0, 0, f_test_null_partial},
811 {"test_null_string", 0, 0, 0, f_test_null_string},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200812 {"test_option_not_set", 1, 1, FEARG_1, f_test_option_not_set},
813 {"test_override", 2, 2, FEARG_2, f_test_override},
814 {"test_refcount", 1, 1, FEARG_1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200815#ifdef FEAT_GUI
Bram Moolenaarce90e362019-09-08 18:58:44 +0200816 {"test_scrollbar", 3, 3, FEARG_2, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200817#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200818 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200819 {"test_settime", 1, 1, FEARG_1, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200820#ifdef FEAT_TIMERS
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200821 {"timer_info", 0, 1, FEARG_1, f_timer_info},
822 {"timer_pause", 2, 2, FEARG_1, f_timer_pause},
823 {"timer_start", 2, 3, FEARG_1, f_timer_start},
824 {"timer_stop", 1, 1, FEARG_1, f_timer_stop},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200825 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200826#endif
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200827 {"tolower", 1, 1, FEARG_1, f_tolower},
828 {"toupper", 1, 1, FEARG_1, f_toupper},
829 {"tr", 3, 3, FEARG_1, f_tr},
830 {"trim", 1, 2, FEARG_1, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200831#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200832 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200833#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200834 {"type", 1, 1, FEARG_1, f_type},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200835 {"undofile", 1, 1, FEARG_1, f_undofile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200836 {"undotree", 0, 0, 0, f_undotree},
837 {"uniq", 1, 3, FEARG_1, f_uniq},
838 {"values", 1, 1, FEARG_1, f_values},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200839 {"virtcol", 1, 1, FEARG_1, f_virtcol},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200840 {"visualmode", 0, 1, 0, f_visualmode},
841 {"wildmenumode", 0, 0, 0, f_wildmenumode},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200842 {"win_execute", 2, 3, FEARG_2, f_win_execute},
843 {"win_findbuf", 1, 1, FEARG_1, f_win_findbuf},
844 {"win_getid", 0, 2, FEARG_1, f_win_getid},
845 {"win_gotoid", 1, 1, FEARG_1, f_win_gotoid},
846 {"win_id2tabwin", 1, 1, FEARG_1, f_win_id2tabwin},
847 {"win_id2win", 1, 1, FEARG_1, f_win_id2win},
848 {"win_screenpos", 1, 1, FEARG_1, f_win_screenpos},
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200849 {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200850 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200851 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200852 {"winheight", 1, 1, FEARG_1, f_winheight},
853 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200854 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200855 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200856 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200857 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200858 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200859 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200860 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200861 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200862 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200863};
864
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200865/*
866 * Function given to ExpandGeneric() to obtain the list of internal
867 * or user defined function names.
868 */
869 char_u *
870get_function_name(expand_T *xp, int idx)
871{
872 static int intidx = -1;
873 char_u *name;
874
875 if (idx == 0)
876 intidx = -1;
877 if (intidx < 0)
878 {
879 name = get_user_func_name(xp, idx);
880 if (name != NULL)
881 return name;
882 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200883 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200884 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200885 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200886 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200887 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888 STRCAT(IObuff, ")");
889 return IObuff;
890 }
891
892 return NULL;
893}
894
895/*
896 * Function given to ExpandGeneric() to obtain the list of internal or
897 * user defined variable or function names.
898 */
899 char_u *
900get_expr_name(expand_T *xp, int idx)
901{
902 static int intidx = -1;
903 char_u *name;
904
905 if (idx == 0)
906 intidx = -1;
907 if (intidx < 0)
908 {
909 name = get_function_name(xp, idx);
910 if (name != NULL)
911 return name;
912 }
913 return get_user_var_name(xp, ++intidx);
914}
915
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200916/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200917 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918 * Return index, or -1 if not found
919 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200920 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200921find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922{
923 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200924 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200925 int cmp;
926 int x;
927
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200928 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200929
930 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200931 while (first <= last)
932 {
933 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200934 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935 if (cmp < 0)
936 last = x - 1;
937 else if (cmp > 0)
938 first = x + 1;
939 else
940 return x;
941 }
942 return -1;
943}
944
945 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200946has_internal_func(char_u *name)
947{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200948 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200949}
950
951 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200952call_internal_func(
953 char_u *name,
954 int argcount,
955 typval_T *argvars,
956 typval_T *rettv)
957{
958 int i;
959
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200960 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200961 if (i < 0)
962 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200963 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200964 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200965 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200966 return ERROR_TOOMANY;
967 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200968 global_functions[i].f_func(argvars, rettv);
969 return ERROR_NONE;
970}
971
972/*
973 * Invoke a method for base->method().
974 */
975 int
976call_internal_method(
977 char_u *name,
978 int argcount,
979 typval_T *argvars,
980 typval_T *rettv,
981 typval_T *basetv)
982{
983 int i;
984 int fi;
985 typval_T argv[MAX_FUNC_ARGS + 1];
986
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200987 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +0200988 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200989 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +0200990 if (global_functions[fi].f_argtype == 0)
991 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200992 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200993 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200994 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200995 return ERROR_TOOMANY;
996
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200997 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +0200998 {
999 // base value goes last
1000 for (i = 0; i < argcount; ++i)
1001 argv[i] = argvars[i];
1002 argv[argcount] = *basetv;
1003 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001004 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001005 {
1006 // base value goes second
1007 argv[0] = argvars[0];
1008 argv[1] = *basetv;
1009 for (i = 1; i < argcount; ++i)
1010 argv[i + 1] = argvars[i];
1011 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001012 else if (global_functions[fi].f_argtype == FEARG_3)
1013 {
1014 // base value goes third
1015 argv[0] = argvars[0];
1016 argv[1] = argvars[1];
1017 argv[2] = *basetv;
1018 for (i = 2; i < argcount; ++i)
1019 argv[i + 1] = argvars[i];
1020 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001021 else if (global_functions[fi].f_argtype == FEARG_4)
1022 {
1023 // base value goes fourth
1024 argv[0] = argvars[0];
1025 argv[1] = argvars[1];
1026 argv[2] = argvars[2];
1027 argv[3] = *basetv;
1028 for (i = 3; i < argcount; ++i)
1029 argv[i + 1] = argvars[i];
1030 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001031 else
1032 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001033 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001034 argv[0] = *basetv;
1035 for (i = 0; i < argcount; ++i)
1036 argv[i + 1] = argvars[i];
1037 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001038 argv[argcount + 1].v_type = VAR_UNKNOWN;
1039
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001040 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001041 return ERROR_NONE;
1042}
1043
1044/*
1045 * Return TRUE for a non-zero Number and a non-empty String.
1046 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001047 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001048non_zero_arg(typval_T *argvars)
1049{
1050 return ((argvars[0].v_type == VAR_NUMBER
1051 && argvars[0].vval.v_number != 0)
1052 || (argvars[0].v_type == VAR_SPECIAL
1053 && argvars[0].vval.v_number == VVAL_TRUE)
1054 || (argvars[0].v_type == VAR_STRING
1055 && argvars[0].vval.v_string != NULL
1056 && *argvars[0].vval.v_string != NUL));
1057}
1058
1059/*
1060 * Get the lnum from the first argument.
1061 * Also accepts ".", "$", etc., but that only works for the current buffer.
1062 * Returns -1 on error.
1063 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001064 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001065tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001066{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001067 linenr_T lnum;
1068
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001069 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001070 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001071 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001072 int fnum;
1073 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1074
1075 if (fp != NULL)
1076 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001077 }
1078 return lnum;
1079}
1080
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001081/*
1082 * Get the lnum from the first argument.
1083 * Also accepts "$", then "buf" is used.
1084 * Returns 0 on error.
1085 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001086 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001087tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1088{
1089 if (argvars[0].v_type == VAR_STRING
1090 && argvars[0].vval.v_string != NULL
1091 && argvars[0].vval.v_string[0] == '$'
1092 && buf != NULL)
1093 return buf->b_ml.ml_line_count;
1094 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1095}
1096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001097#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001098/*
1099 * Get the float value of "argvars[0]" into "f".
1100 * Returns FAIL when the argument is not a Number or Float.
1101 */
1102 static int
1103get_float_arg(typval_T *argvars, float_T *f)
1104{
1105 if (argvars[0].v_type == VAR_FLOAT)
1106 {
1107 *f = argvars[0].vval.v_float;
1108 return OK;
1109 }
1110 if (argvars[0].v_type == VAR_NUMBER)
1111 {
1112 *f = (float_T)argvars[0].vval.v_number;
1113 return OK;
1114 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001115 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001116 return FAIL;
1117}
1118
1119/*
1120 * "abs(expr)" function
1121 */
1122 static void
1123f_abs(typval_T *argvars, typval_T *rettv)
1124{
1125 if (argvars[0].v_type == VAR_FLOAT)
1126 {
1127 rettv->v_type = VAR_FLOAT;
1128 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1129 }
1130 else
1131 {
1132 varnumber_T n;
1133 int error = FALSE;
1134
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001135 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001136 if (error)
1137 rettv->vval.v_number = -1;
1138 else if (n > 0)
1139 rettv->vval.v_number = n;
1140 else
1141 rettv->vval.v_number = -n;
1142 }
1143}
1144
1145/*
1146 * "acos()" function
1147 */
1148 static void
1149f_acos(typval_T *argvars, typval_T *rettv)
1150{
1151 float_T f = 0.0;
1152
1153 rettv->v_type = VAR_FLOAT;
1154 if (get_float_arg(argvars, &f) == OK)
1155 rettv->vval.v_float = acos(f);
1156 else
1157 rettv->vval.v_float = 0.0;
1158}
1159#endif
1160
1161/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001162 * "and(expr, expr)" function
1163 */
1164 static void
1165f_and(typval_T *argvars, typval_T *rettv)
1166{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001167 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1168 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001169}
1170
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001171#ifdef FEAT_FLOAT
1172/*
1173 * "asin()" function
1174 */
1175 static void
1176f_asin(typval_T *argvars, typval_T *rettv)
1177{
1178 float_T f = 0.0;
1179
1180 rettv->v_type = VAR_FLOAT;
1181 if (get_float_arg(argvars, &f) == OK)
1182 rettv->vval.v_float = asin(f);
1183 else
1184 rettv->vval.v_float = 0.0;
1185}
1186
1187/*
1188 * "atan()" function
1189 */
1190 static void
1191f_atan(typval_T *argvars, typval_T *rettv)
1192{
1193 float_T f = 0.0;
1194
1195 rettv->v_type = VAR_FLOAT;
1196 if (get_float_arg(argvars, &f) == OK)
1197 rettv->vval.v_float = atan(f);
1198 else
1199 rettv->vval.v_float = 0.0;
1200}
1201
1202/*
1203 * "atan2()" function
1204 */
1205 static void
1206f_atan2(typval_T *argvars, typval_T *rettv)
1207{
1208 float_T fx = 0.0, fy = 0.0;
1209
1210 rettv->v_type = VAR_FLOAT;
1211 if (get_float_arg(argvars, &fx) == OK
1212 && get_float_arg(&argvars[1], &fy) == OK)
1213 rettv->vval.v_float = atan2(fx, fy);
1214 else
1215 rettv->vval.v_float = 0.0;
1216}
1217#endif
1218
1219/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001220 * "balloon_show()" function
1221 */
1222#ifdef FEAT_BEVAL
1223 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001224f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1225{
1226 rettv->v_type = VAR_STRING;
1227 if (balloonEval != NULL)
1228 {
1229 if (balloonEval->msg == NULL)
1230 rettv->vval.v_string = NULL;
1231 else
1232 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1233 }
1234}
1235
1236 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001237f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1238{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001239 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001240 {
1241 if (argvars[0].v_type == VAR_LIST
1242# ifdef FEAT_GUI
1243 && !gui.in_use
1244# endif
1245 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001246 {
1247 list_T *l = argvars[0].vval.v_list;
1248
1249 // empty list removes the balloon
1250 post_balloon(balloonEval, NULL,
1251 l == NULL || l->lv_len == 0 ? NULL : l);
1252 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001253 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001254 {
1255 char_u *mesg = tv_get_string_chk(&argvars[0]);
1256
1257 if (mesg != NULL)
1258 // empty string removes the balloon
1259 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1260 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001261 }
1262}
1263
Bram Moolenaar669a8282017-11-19 20:13:05 +01001264# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001265 static void
1266f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1267{
1268 if (rettv_list_alloc(rettv) == OK)
1269 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001270 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001271
1272 if (msg != NULL)
1273 {
1274 pumitem_T *array;
1275 int size = split_message(msg, &array);
1276 int i;
1277
1278 /* Skip the first and last item, they are always empty. */
1279 for (i = 1; i < size - 1; ++i)
1280 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001281 while (size > 0)
1282 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001283 vim_free(array);
1284 }
1285 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001286}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001287# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001288#endif
1289
1290/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001291 * Get buffer by number or pattern.
1292 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001293 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001294tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295{
1296 char_u *name = tv->vval.v_string;
1297 buf_T *buf;
1298
1299 if (tv->v_type == VAR_NUMBER)
1300 return buflist_findnr((int)tv->vval.v_number);
1301 if (tv->v_type != VAR_STRING)
1302 return NULL;
1303 if (name == NULL || *name == NUL)
1304 return curbuf;
1305 if (name[0] == '$' && name[1] == NUL)
1306 return lastbuf;
1307
1308 buf = buflist_find_by_name(name, curtab_only);
1309
1310 /* If not found, try expanding the name, like done for bufexists(). */
1311 if (buf == NULL)
1312 buf = find_buffer(tv);
1313
1314 return buf;
1315}
1316
1317/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001318 * Get the buffer from "arg" and give an error and return NULL if it is not
1319 * valid.
1320 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001321 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001322get_buf_arg(typval_T *arg)
1323{
1324 buf_T *buf;
1325
1326 ++emsg_off;
1327 buf = tv_get_buf(arg, FALSE);
1328 --emsg_off;
1329 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001330 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001331 return buf;
1332}
1333
1334/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001335 * "byte2line(byte)" function
1336 */
1337 static void
1338f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1339{
1340#ifndef FEAT_BYTEOFF
1341 rettv->vval.v_number = -1;
1342#else
1343 long boff = 0;
1344
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001345 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001346 if (boff < 0)
1347 rettv->vval.v_number = -1;
1348 else
1349 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1350 (linenr_T)0, &boff);
1351#endif
1352}
1353
1354 static void
1355byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1356{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001357 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358 char_u *str;
1359 varnumber_T idx;
1360
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001361 str = tv_get_string_chk(&argvars[0]);
1362 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001363 rettv->vval.v_number = -1;
1364 if (str == NULL || idx < 0)
1365 return;
1366
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367 t = str;
1368 for ( ; idx > 0; idx--)
1369 {
1370 if (*t == NUL) /* EOL reached */
1371 return;
1372 if (enc_utf8 && comp)
1373 t += utf_ptr2len(t);
1374 else
1375 t += (*mb_ptr2len)(t);
1376 }
1377 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001378}
1379
1380/*
1381 * "byteidx()" function
1382 */
1383 static void
1384f_byteidx(typval_T *argvars, typval_T *rettv)
1385{
1386 byteidx(argvars, rettv, FALSE);
1387}
1388
1389/*
1390 * "byteidxcomp()" function
1391 */
1392 static void
1393f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1394{
1395 byteidx(argvars, rettv, TRUE);
1396}
1397
1398/*
1399 * "call(func, arglist [, dict])" function
1400 */
1401 static void
1402f_call(typval_T *argvars, typval_T *rettv)
1403{
1404 char_u *func;
1405 partial_T *partial = NULL;
1406 dict_T *selfdict = NULL;
1407
1408 if (argvars[1].v_type != VAR_LIST)
1409 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001410 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001411 return;
1412 }
1413 if (argvars[1].vval.v_list == NULL)
1414 return;
1415
1416 if (argvars[0].v_type == VAR_FUNC)
1417 func = argvars[0].vval.v_string;
1418 else if (argvars[0].v_type == VAR_PARTIAL)
1419 {
1420 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001421 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001422 }
1423 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001424 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001425 if (*func == NUL)
1426 return; /* type error or empty name */
1427
1428 if (argvars[2].v_type != VAR_UNKNOWN)
1429 {
1430 if (argvars[2].v_type != VAR_DICT)
1431 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001432 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001433 return;
1434 }
1435 selfdict = argvars[2].vval.v_dict;
1436 }
1437
1438 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1439}
1440
1441#ifdef FEAT_FLOAT
1442/*
1443 * "ceil({float})" function
1444 */
1445 static void
1446f_ceil(typval_T *argvars, typval_T *rettv)
1447{
1448 float_T f = 0.0;
1449
1450 rettv->v_type = VAR_FLOAT;
1451 if (get_float_arg(argvars, &f) == OK)
1452 rettv->vval.v_float = ceil(f);
1453 else
1454 rettv->vval.v_float = 0.0;
1455}
1456#endif
1457
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001458/*
1459 * "changenr()" function
1460 */
1461 static void
1462f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1463{
1464 rettv->vval.v_number = curbuf->b_u_seq_cur;
1465}
1466
1467/*
1468 * "char2nr(string)" function
1469 */
1470 static void
1471f_char2nr(typval_T *argvars, typval_T *rettv)
1472{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001473 if (has_mbyte)
1474 {
1475 int utf8 = 0;
1476
1477 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001478 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001479
1480 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001481 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001482 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001483 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001484 }
1485 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001486 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001487}
1488
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001489 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001490get_optional_window(typval_T *argvars, int idx)
1491{
1492 win_T *win = curwin;
1493
1494 if (argvars[idx].v_type != VAR_UNKNOWN)
1495 {
1496 win = find_win_by_nr_or_id(&argvars[idx]);
1497 if (win == NULL)
1498 {
1499 emsg(_(e_invalwindow));
1500 return NULL;
1501 }
1502 }
1503 return win;
1504}
1505
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001507 * "col(string)" function
1508 */
1509 static void
1510f_col(typval_T *argvars, typval_T *rettv)
1511{
1512 colnr_T col = 0;
1513 pos_T *fp;
1514 int fnum = curbuf->b_fnum;
1515
1516 fp = var2fpos(&argvars[0], FALSE, &fnum);
1517 if (fp != NULL && fnum == curbuf->b_fnum)
1518 {
1519 if (fp->col == MAXCOL)
1520 {
1521 /* '> can be MAXCOL, get the length of the line then */
1522 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1523 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1524 else
1525 col = MAXCOL;
1526 }
1527 else
1528 {
1529 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001530 /* col(".") when the cursor is on the NUL at the end of the line
1531 * because of "coladd" can be seen as an extra column. */
1532 if (virtual_active() && fp == &curwin->w_cursor)
1533 {
1534 char_u *p = ml_get_cursor();
1535
1536 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1537 curwin->w_virtcol - curwin->w_cursor.coladd))
1538 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001539 int l;
1540
1541 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1542 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001543 }
1544 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001545 }
1546 }
1547 rettv->vval.v_number = col;
1548}
1549
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001550/*
1551 * "confirm(message, buttons[, default [, type]])" function
1552 */
1553 static void
1554f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1555{
1556#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1557 char_u *message;
1558 char_u *buttons = NULL;
1559 char_u buf[NUMBUFLEN];
1560 char_u buf2[NUMBUFLEN];
1561 int def = 1;
1562 int type = VIM_GENERIC;
1563 char_u *typestr;
1564 int error = FALSE;
1565
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001566 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001567 if (message == NULL)
1568 error = TRUE;
1569 if (argvars[1].v_type != VAR_UNKNOWN)
1570 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001571 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001572 if (buttons == NULL)
1573 error = TRUE;
1574 if (argvars[2].v_type != VAR_UNKNOWN)
1575 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001576 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001577 if (argvars[3].v_type != VAR_UNKNOWN)
1578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001579 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580 if (typestr == NULL)
1581 error = TRUE;
1582 else
1583 {
1584 switch (TOUPPER_ASC(*typestr))
1585 {
1586 case 'E': type = VIM_ERROR; break;
1587 case 'Q': type = VIM_QUESTION; break;
1588 case 'I': type = VIM_INFO; break;
1589 case 'W': type = VIM_WARNING; break;
1590 case 'G': type = VIM_GENERIC; break;
1591 }
1592 }
1593 }
1594 }
1595 }
1596
1597 if (buttons == NULL || *buttons == NUL)
1598 buttons = (char_u *)_("&Ok");
1599
1600 if (!error)
1601 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1602 def, NULL, FALSE);
1603#endif
1604}
1605
1606/*
1607 * "copy()" function
1608 */
1609 static void
1610f_copy(typval_T *argvars, typval_T *rettv)
1611{
1612 item_copy(&argvars[0], rettv, FALSE, 0);
1613}
1614
1615#ifdef FEAT_FLOAT
1616/*
1617 * "cos()" function
1618 */
1619 static void
1620f_cos(typval_T *argvars, typval_T *rettv)
1621{
1622 float_T f = 0.0;
1623
1624 rettv->v_type = VAR_FLOAT;
1625 if (get_float_arg(argvars, &f) == OK)
1626 rettv->vval.v_float = cos(f);
1627 else
1628 rettv->vval.v_float = 0.0;
1629}
1630
1631/*
1632 * "cosh()" function
1633 */
1634 static void
1635f_cosh(typval_T *argvars, typval_T *rettv)
1636{
1637 float_T f = 0.0;
1638
1639 rettv->v_type = VAR_FLOAT;
1640 if (get_float_arg(argvars, &f) == OK)
1641 rettv->vval.v_float = cosh(f);
1642 else
1643 rettv->vval.v_float = 0.0;
1644}
1645#endif
1646
1647/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001648 * "cursor(lnum, col)" function, or
1649 * "cursor(list)"
1650 *
1651 * Moves the cursor to the specified line and column.
1652 * Returns 0 when the position could be set, -1 otherwise.
1653 */
1654 static void
1655f_cursor(typval_T *argvars, typval_T *rettv)
1656{
1657 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001658 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001659 int set_curswant = TRUE;
1660
1661 rettv->vval.v_number = -1;
1662 if (argvars[1].v_type == VAR_UNKNOWN)
1663 {
1664 pos_T pos;
1665 colnr_T curswant = -1;
1666
1667 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1668 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001669 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001670 return;
1671 }
1672 line = pos.lnum;
1673 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001674 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 if (curswant >= 0)
1676 {
1677 curwin->w_curswant = curswant - 1;
1678 set_curswant = FALSE;
1679 }
1680 }
1681 else
1682 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001683 line = tv_get_lnum(argvars);
1684 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001686 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001688 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001689 return; /* type error; errmsg already given */
1690 if (line > 0)
1691 curwin->w_cursor.lnum = line;
1692 if (col > 0)
1693 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001694 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001695
1696 /* Make sure the cursor is in a valid position. */
1697 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001698 /* Correct cursor for multi-byte character. */
1699 if (has_mbyte)
1700 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001701
1702 curwin->w_set_curswant = set_curswant;
1703 rettv->vval.v_number = 0;
1704}
1705
Bram Moolenaar4f974752019-02-17 17:44:42 +01001706#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001707/*
1708 * "debugbreak()" function
1709 */
1710 static void
1711f_debugbreak(typval_T *argvars, typval_T *rettv)
1712{
1713 int pid;
1714
1715 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001716 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001717 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001718 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001719 else
1720 {
1721 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1722
1723 if (hProcess != NULL)
1724 {
1725 DebugBreakProcess(hProcess);
1726 CloseHandle(hProcess);
1727 rettv->vval.v_number = OK;
1728 }
1729 }
1730}
1731#endif
1732
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001733/*
1734 * "deepcopy()" function
1735 */
1736 static void
1737f_deepcopy(typval_T *argvars, typval_T *rettv)
1738{
1739 int noref = 0;
1740 int copyID;
1741
1742 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001743 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001744 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001745 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001746 else
1747 {
1748 copyID = get_copyID();
1749 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1750 }
1751}
1752
1753/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001754 * "did_filetype()" function
1755 */
1756 static void
1757f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1758{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001759 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001760}
1761
1762/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001763 * "empty({expr})" function
1764 */
1765 static void
1766f_empty(typval_T *argvars, typval_T *rettv)
1767{
1768 int n = FALSE;
1769
1770 switch (argvars[0].v_type)
1771 {
1772 case VAR_STRING:
1773 case VAR_FUNC:
1774 n = argvars[0].vval.v_string == NULL
1775 || *argvars[0].vval.v_string == NUL;
1776 break;
1777 case VAR_PARTIAL:
1778 n = FALSE;
1779 break;
1780 case VAR_NUMBER:
1781 n = argvars[0].vval.v_number == 0;
1782 break;
1783 case VAR_FLOAT:
1784#ifdef FEAT_FLOAT
1785 n = argvars[0].vval.v_float == 0.0;
1786 break;
1787#endif
1788 case VAR_LIST:
1789 n = argvars[0].vval.v_list == NULL
1790 || argvars[0].vval.v_list->lv_first == NULL;
1791 break;
1792 case VAR_DICT:
1793 n = argvars[0].vval.v_dict == NULL
1794 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1795 break;
1796 case VAR_SPECIAL:
1797 n = argvars[0].vval.v_number != VVAL_TRUE;
1798 break;
1799
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001800 case VAR_BLOB:
1801 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001802 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1803 break;
1804
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001805 case VAR_JOB:
1806#ifdef FEAT_JOB_CHANNEL
1807 n = argvars[0].vval.v_job == NULL
1808 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1809 break;
1810#endif
1811 case VAR_CHANNEL:
1812#ifdef FEAT_JOB_CHANNEL
1813 n = argvars[0].vval.v_channel == NULL
1814 || !channel_is_open(argvars[0].vval.v_channel);
1815 break;
1816#endif
1817 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001818 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001819 n = TRUE;
1820 break;
1821 }
1822
1823 rettv->vval.v_number = n;
1824}
1825
1826/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001827 * "environ()" function
1828 */
1829 static void
1830f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1831{
1832#if !defined(AMIGA)
1833 int i = 0;
1834 char_u *entry, *value;
1835# ifdef MSWIN
1836 extern wchar_t **_wenviron;
1837# else
1838 extern char **environ;
1839# endif
1840
1841 if (rettv_dict_alloc(rettv) != OK)
1842 return;
1843
1844# ifdef MSWIN
1845 if (*_wenviron == NULL)
1846 return;
1847# else
1848 if (*environ == NULL)
1849 return;
1850# endif
1851
1852 for (i = 0; ; ++i)
1853 {
1854# ifdef MSWIN
1855 short_u *p;
1856
1857 if ((p = (short_u *)_wenviron[i]) == NULL)
1858 return;
1859 entry = utf16_to_enc(p, NULL);
1860# else
1861 if ((entry = (char_u *)environ[i]) == NULL)
1862 return;
1863 entry = vim_strsave(entry);
1864# endif
1865 if (entry == NULL) // out of memory
1866 return;
1867 if ((value = vim_strchr(entry, '=')) == NULL)
1868 {
1869 vim_free(entry);
1870 continue;
1871 }
1872 *value++ = NUL;
1873 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1874 vim_free(entry);
1875 }
1876#endif
1877}
1878
1879/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001880 * "escape({string}, {chars})" function
1881 */
1882 static void
1883f_escape(typval_T *argvars, typval_T *rettv)
1884{
1885 char_u buf[NUMBUFLEN];
1886
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001887 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1888 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001889 rettv->v_type = VAR_STRING;
1890}
1891
1892/*
1893 * "eval()" function
1894 */
1895 static void
1896f_eval(typval_T *argvars, typval_T *rettv)
1897{
1898 char_u *s, *p;
1899
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001900 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001901 if (s != NULL)
1902 s = skipwhite(s);
1903
1904 p = s;
1905 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1906 {
1907 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001908 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001909 need_clr_eos = FALSE;
1910 rettv->v_type = VAR_NUMBER;
1911 rettv->vval.v_number = 0;
1912 }
1913 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001914 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001915}
1916
1917/*
1918 * "eventhandler()" function
1919 */
1920 static void
1921f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1922{
1923 rettv->vval.v_number = vgetc_busy;
1924}
1925
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001926static garray_T redir_execute_ga;
1927
1928/*
1929 * Append "value[value_len]" to the execute() output.
1930 */
1931 void
1932execute_redir_str(char_u *value, int value_len)
1933{
1934 int len;
1935
1936 if (value_len == -1)
1937 len = (int)STRLEN(value); /* Append the entire string */
1938 else
1939 len = value_len; /* Append only "value_len" characters */
1940 if (ga_grow(&redir_execute_ga, len) == OK)
1941 {
1942 mch_memmove((char *)redir_execute_ga.ga_data
1943 + redir_execute_ga.ga_len, value, len);
1944 redir_execute_ga.ga_len += len;
1945 }
1946}
1947
1948/*
1949 * Get next line from a list.
1950 * Called by do_cmdline() to get the next line.
1951 * Returns allocated string, or NULL for end of function.
1952 */
1953
1954 static char_u *
1955get_list_line(
1956 int c UNUSED,
1957 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001958 int indent UNUSED,
1959 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001960{
1961 listitem_T **p = (listitem_T **)cookie;
1962 listitem_T *item = *p;
1963 char_u buf[NUMBUFLEN];
1964 char_u *s;
1965
1966 if (item == NULL)
1967 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001968 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001969 *p = item->li_next;
1970 return s == NULL ? NULL : vim_strsave(s);
1971}
1972
1973/*
1974 * "execute()" function
1975 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001976 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001977execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001978{
1979 char_u *cmd = NULL;
1980 list_T *list = NULL;
1981 int save_msg_silent = msg_silent;
1982 int save_emsg_silent = emsg_silent;
1983 int save_emsg_noredir = emsg_noredir;
1984 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01001985 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001986 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01001987 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01001988 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001989
1990 rettv->vval.v_string = NULL;
1991 rettv->v_type = VAR_STRING;
1992
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001993 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001994 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001995 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001996 if (list == NULL || list->lv_first == NULL)
1997 /* empty list, no commands, empty output */
1998 return;
1999 ++list->lv_refcount;
2000 }
2001 else
2002 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002003 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002004 if (cmd == NULL)
2005 return;
2006 }
2007
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002008 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002009 {
2010 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002011 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012
2013 if (s == NULL)
2014 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002015 if (*s == NUL)
2016 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002017 if (STRNCMP(s, "silent", 6) == 0)
2018 ++msg_silent;
2019 if (STRCMP(s, "silent!") == 0)
2020 {
2021 emsg_silent = TRUE;
2022 emsg_noredir = TRUE;
2023 }
2024 }
2025 else
2026 ++msg_silent;
2027
2028 if (redir_execute)
2029 save_ga = redir_execute_ga;
2030 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2031 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002032 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002033 if (!echo_output)
2034 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002035
2036 if (cmd != NULL)
2037 do_cmdline_cmd(cmd);
2038 else
2039 {
2040 listitem_T *item = list->lv_first;
2041
2042 do_cmdline(NULL, get_list_line, (void *)&item,
2043 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2044 --list->lv_refcount;
2045 }
2046
Bram Moolenaard297f352017-01-29 20:31:21 +01002047 /* Need to append a NUL to the result. */
2048 if (ga_grow(&redir_execute_ga, 1) == OK)
2049 {
2050 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2051 rettv->vval.v_string = redir_execute_ga.ga_data;
2052 }
2053 else
2054 {
2055 ga_clear(&redir_execute_ga);
2056 rettv->vval.v_string = NULL;
2057 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002058 msg_silent = save_msg_silent;
2059 emsg_silent = save_emsg_silent;
2060 emsg_noredir = save_emsg_noredir;
2061
2062 redir_execute = save_redir_execute;
2063 if (redir_execute)
2064 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002065 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002066
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002067 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002068 if (echo_output)
2069 // When not working silently: put it in column zero. A following
2070 // "echon" will overwrite the message, unavoidably.
2071 msg_col = 0;
2072 else
2073 // When working silently: Put it back where it was, since nothing
2074 // should have been written.
2075 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002076}
2077
2078/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002079 * "execute()" function
2080 */
2081 static void
2082f_execute(typval_T *argvars, typval_T *rettv)
2083{
2084 execute_common(argvars, rettv, 0);
2085}
2086
2087/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002088 * "exists()" function
2089 */
2090 static void
2091f_exists(typval_T *argvars, typval_T *rettv)
2092{
2093 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002094 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002096 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097 if (*p == '$') /* environment variable */
2098 {
2099 /* first try "normal" environment variables (fast) */
2100 if (mch_getenv(p + 1) != NULL)
2101 n = TRUE;
2102 else
2103 {
2104 /* try expanding things like $VIM and ${HOME} */
2105 p = expand_env_save(p);
2106 if (p != NULL && *p != '$')
2107 n = TRUE;
2108 vim_free(p);
2109 }
2110 }
2111 else if (*p == '&' || *p == '+') /* option */
2112 {
2113 n = (get_option_tv(&p, NULL, TRUE) == OK);
2114 if (*skipwhite(p) != NUL)
2115 n = FALSE; /* trailing garbage */
2116 }
2117 else if (*p == '*') /* internal or user defined function */
2118 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002119 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120 }
2121 else if (*p == ':')
2122 {
2123 n = cmd_exists(p + 1);
2124 }
2125 else if (*p == '#')
2126 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002127 if (p[1] == '#')
2128 n = autocmd_supported(p + 2);
2129 else
2130 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002131 }
2132 else /* internal variable */
2133 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002134 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002135 }
2136
2137 rettv->vval.v_number = n;
2138}
2139
2140#ifdef FEAT_FLOAT
2141/*
2142 * "exp()" function
2143 */
2144 static void
2145f_exp(typval_T *argvars, typval_T *rettv)
2146{
2147 float_T f = 0.0;
2148
2149 rettv->v_type = VAR_FLOAT;
2150 if (get_float_arg(argvars, &f) == OK)
2151 rettv->vval.v_float = exp(f);
2152 else
2153 rettv->vval.v_float = 0.0;
2154}
2155#endif
2156
2157/*
2158 * "expand()" function
2159 */
2160 static void
2161f_expand(typval_T *argvars, typval_T *rettv)
2162{
2163 char_u *s;
2164 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002165 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002166 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2167 expand_T xpc;
2168 int error = FALSE;
2169 char_u *result;
2170
2171 rettv->v_type = VAR_STRING;
2172 if (argvars[1].v_type != VAR_UNKNOWN
2173 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002174 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002176 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002178 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002179 if (*s == '%' || *s == '#' || *s == '<')
2180 {
2181 ++emsg_off;
2182 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2183 --emsg_off;
2184 if (rettv->v_type == VAR_LIST)
2185 {
2186 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2187 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002188 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002189 }
2190 else
2191 rettv->vval.v_string = result;
2192 }
2193 else
2194 {
2195 /* When the optional second argument is non-zero, don't remove matches
2196 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2197 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002198 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002199 options |= WILD_KEEP_ALL;
2200 if (!error)
2201 {
2202 ExpandInit(&xpc);
2203 xpc.xp_context = EXPAND_FILES;
2204 if (p_wic)
2205 options += WILD_ICASE;
2206 if (rettv->v_type == VAR_STRING)
2207 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2208 options, WILD_ALL);
2209 else if (rettv_list_alloc(rettv) != FAIL)
2210 {
2211 int i;
2212
2213 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2214 for (i = 0; i < xpc.xp_numfiles; i++)
2215 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2216 ExpandCleanup(&xpc);
2217 }
2218 }
2219 else
2220 rettv->vval.v_string = NULL;
2221 }
2222}
2223
2224/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002225 * "expandcmd()" function
2226 * Expand all the special characters in a command string.
2227 */
2228 static void
2229f_expandcmd(typval_T *argvars, typval_T *rettv)
2230{
2231 exarg_T eap;
2232 char_u *cmdstr;
2233 char *errormsg = NULL;
2234
2235 rettv->v_type = VAR_STRING;
2236 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2237
2238 memset(&eap, 0, sizeof(eap));
2239 eap.cmd = cmdstr;
2240 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002241 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002242 eap.usefilter = FALSE;
2243 eap.nextcmd = NULL;
2244 eap.cmdidx = CMD_USER;
2245
2246 expand_filename(&eap, &cmdstr, &errormsg);
2247 if (errormsg != NULL && *errormsg != NUL)
2248 emsg(errormsg);
2249
2250 rettv->vval.v_string = cmdstr;
2251}
2252
2253/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002254 * "feedkeys()" function
2255 */
2256 static void
2257f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2258{
2259 int remap = TRUE;
2260 int insert = FALSE;
2261 char_u *keys, *flags;
2262 char_u nbuf[NUMBUFLEN];
2263 int typed = FALSE;
2264 int execute = FALSE;
2265 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002266 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002267 char_u *keys_esc;
2268
2269 /* This is not allowed in the sandbox. If the commands would still be
2270 * executed in the sandbox it would be OK, but it probably happens later,
2271 * when "sandbox" is no longer set. */
2272 if (check_secure())
2273 return;
2274
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002275 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002276
2277 if (argvars[1].v_type != VAR_UNKNOWN)
2278 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002279 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 for ( ; *flags != NUL; ++flags)
2281 {
2282 switch (*flags)
2283 {
2284 case 'n': remap = FALSE; break;
2285 case 'm': remap = TRUE; break;
2286 case 't': typed = TRUE; break;
2287 case 'i': insert = TRUE; break;
2288 case 'x': execute = TRUE; break;
2289 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002290 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002291 }
2292 }
2293 }
2294
2295 if (*keys != NUL || execute)
2296 {
2297 /* Need to escape K_SPECIAL and CSI before putting the string in the
2298 * typeahead buffer. */
2299 keys_esc = vim_strsave_escape_csi(keys);
2300 if (keys_esc != NULL)
2301 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002302 if (lowlevel)
2303 {
2304#ifdef USE_INPUT_BUF
2305 add_to_input_buf(keys, (int)STRLEN(keys));
2306#else
2307 emsg(_("E980: lowlevel input not supported"));
2308#endif
2309 }
2310 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002311 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002312 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002313 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002314 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002315#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002316 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002317#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002318 )
2319 typebuf_was_filled = TRUE;
2320 }
2321 vim_free(keys_esc);
2322
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002323 if (execute)
2324 {
2325 int save_msg_scroll = msg_scroll;
2326
2327 /* Avoid a 1 second delay when the keys start Insert mode. */
2328 msg_scroll = FALSE;
2329
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002330 if (!dangerous)
2331 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002332 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002333 if (!dangerous)
2334 --ex_normal_busy;
2335
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002336 msg_scroll |= save_msg_scroll;
2337 }
2338 }
2339 }
2340}
2341
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002342#ifdef FEAT_FLOAT
2343/*
2344 * "float2nr({float})" function
2345 */
2346 static void
2347f_float2nr(typval_T *argvars, typval_T *rettv)
2348{
2349 float_T f = 0.0;
2350
2351 if (get_float_arg(argvars, &f) == OK)
2352 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002353 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002354 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002355 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002356 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002357 else
2358 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359 }
2360}
2361
2362/*
2363 * "floor({float})" function
2364 */
2365 static void
2366f_floor(typval_T *argvars, typval_T *rettv)
2367{
2368 float_T f = 0.0;
2369
2370 rettv->v_type = VAR_FLOAT;
2371 if (get_float_arg(argvars, &f) == OK)
2372 rettv->vval.v_float = floor(f);
2373 else
2374 rettv->vval.v_float = 0.0;
2375}
2376
2377/*
2378 * "fmod()" function
2379 */
2380 static void
2381f_fmod(typval_T *argvars, typval_T *rettv)
2382{
2383 float_T fx = 0.0, fy = 0.0;
2384
2385 rettv->v_type = VAR_FLOAT;
2386 if (get_float_arg(argvars, &fx) == OK
2387 && get_float_arg(&argvars[1], &fy) == OK)
2388 rettv->vval.v_float = fmod(fx, fy);
2389 else
2390 rettv->vval.v_float = 0.0;
2391}
2392#endif
2393
2394/*
2395 * "fnameescape({string})" function
2396 */
2397 static void
2398f_fnameescape(typval_T *argvars, typval_T *rettv)
2399{
2400 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002401 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002402 rettv->v_type = VAR_STRING;
2403}
2404
2405/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002406 * "foreground()" function
2407 */
2408 static void
2409f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2410{
2411#ifdef FEAT_GUI
2412 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002413 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002415 return;
2416 }
2417#endif
2418#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002420#endif
2421}
2422
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002423 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002424common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002425{
2426 char_u *s;
2427 char_u *name;
2428 int use_string = FALSE;
2429 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002430 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002431
2432 if (argvars[0].v_type == VAR_FUNC)
2433 {
2434 /* function(MyFunc, [arg], dict) */
2435 s = argvars[0].vval.v_string;
2436 }
2437 else if (argvars[0].v_type == VAR_PARTIAL
2438 && argvars[0].vval.v_partial != NULL)
2439 {
2440 /* function(dict.MyFunc, [arg]) */
2441 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002442 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002443 }
2444 else
2445 {
2446 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002447 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 use_string = TRUE;
2449 }
2450
Bram Moolenaar843b8842016-08-21 14:36:15 +02002451 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002452 {
2453 name = s;
2454 trans_name = trans_function_name(&name, FALSE,
2455 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2456 if (*name != NUL)
2457 s = NULL;
2458 }
2459
Bram Moolenaar843b8842016-08-21 14:36:15 +02002460 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2461 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002462 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002463 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002464 else if (trans_name != NULL && (is_funcref
2465 ? find_func(trans_name) == NULL
2466 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002467 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002468 else
2469 {
2470 int dict_idx = 0;
2471 int arg_idx = 0;
2472 list_T *list = NULL;
2473
2474 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2475 {
2476 char sid_buf[25];
2477 int off = *s == 's' ? 2 : 5;
2478
2479 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2480 * also be called from another script. Using trans_function_name()
2481 * would also work, but some plugins depend on the name being
2482 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002483 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002484 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002485 if (name != NULL)
2486 {
2487 STRCPY(name, sid_buf);
2488 STRCAT(name, s + off);
2489 }
2490 }
2491 else
2492 name = vim_strsave(s);
2493
2494 if (argvars[1].v_type != VAR_UNKNOWN)
2495 {
2496 if (argvars[2].v_type != VAR_UNKNOWN)
2497 {
2498 /* function(name, [args], dict) */
2499 arg_idx = 1;
2500 dict_idx = 2;
2501 }
2502 else if (argvars[1].v_type == VAR_DICT)
2503 /* function(name, dict) */
2504 dict_idx = 1;
2505 else
2506 /* function(name, [args]) */
2507 arg_idx = 1;
2508 if (dict_idx > 0)
2509 {
2510 if (argvars[dict_idx].v_type != VAR_DICT)
2511 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002512 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002513 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002514 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002515 }
2516 if (argvars[dict_idx].vval.v_dict == NULL)
2517 dict_idx = 0;
2518 }
2519 if (arg_idx > 0)
2520 {
2521 if (argvars[arg_idx].v_type != VAR_LIST)
2522 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002523 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002524 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002525 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526 }
2527 list = argvars[arg_idx].vval.v_list;
2528 if (list == NULL || list->lv_len == 0)
2529 arg_idx = 0;
Bram Moolenaar4c054e92019-11-10 00:13:50 +01002530 else if (list->lv_len > MAX_FUNC_ARGS)
2531 {
2532 emsg_funcname((char *)e_toomanyarg, name);
2533 vim_free(name);
2534 goto theend;
2535 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002536 }
2537 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002538 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002539 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002540 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541
2542 /* result is a VAR_PARTIAL */
2543 if (pt == NULL)
2544 vim_free(name);
2545 else
2546 {
2547 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2548 {
2549 listitem_T *li;
2550 int i = 0;
2551 int arg_len = 0;
2552 int lv_len = 0;
2553
2554 if (arg_pt != NULL)
2555 arg_len = arg_pt->pt_argc;
2556 if (list != NULL)
2557 lv_len = list->lv_len;
2558 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002559 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002560 if (pt->pt_argv == NULL)
2561 {
2562 vim_free(pt);
2563 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002564 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002565 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002566 for (i = 0; i < arg_len; i++)
2567 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2568 if (lv_len > 0)
2569 for (li = list->lv_first; li != NULL;
2570 li = li->li_next)
2571 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002572 }
2573
2574 /* For "function(dict.func, [], dict)" and "func" is a partial
2575 * use "dict". That is backwards compatible. */
2576 if (dict_idx > 0)
2577 {
2578 /* The dict is bound explicitly, pt_auto is FALSE. */
2579 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2580 ++pt->pt_dict->dv_refcount;
2581 }
2582 else if (arg_pt != NULL)
2583 {
2584 /* If the dict was bound automatically the result is also
2585 * bound automatically. */
2586 pt->pt_dict = arg_pt->pt_dict;
2587 pt->pt_auto = arg_pt->pt_auto;
2588 if (pt->pt_dict != NULL)
2589 ++pt->pt_dict->dv_refcount;
2590 }
2591
2592 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002593 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2594 {
2595 pt->pt_func = arg_pt->pt_func;
2596 func_ptr_ref(pt->pt_func);
2597 vim_free(name);
2598 }
2599 else if (is_funcref)
2600 {
2601 pt->pt_func = find_func(trans_name);
2602 func_ptr_ref(pt->pt_func);
2603 vim_free(name);
2604 }
2605 else
2606 {
2607 pt->pt_name = name;
2608 func_ref(name);
2609 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002610 }
2611 rettv->v_type = VAR_PARTIAL;
2612 rettv->vval.v_partial = pt;
2613 }
2614 else
2615 {
2616 /* result is a VAR_FUNC */
2617 rettv->v_type = VAR_FUNC;
2618 rettv->vval.v_string = name;
2619 func_ref(name);
2620 }
2621 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002622theend:
2623 vim_free(trans_name);
2624}
2625
2626/*
2627 * "funcref()" function
2628 */
2629 static void
2630f_funcref(typval_T *argvars, typval_T *rettv)
2631{
2632 common_function(argvars, rettv, TRUE);
2633}
2634
2635/*
2636 * "function()" function
2637 */
2638 static void
2639f_function(typval_T *argvars, typval_T *rettv)
2640{
2641 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002642}
2643
2644/*
2645 * "garbagecollect()" function
2646 */
2647 static void
2648f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2649{
2650 /* This is postponed until we are back at the toplevel, because we may be
2651 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2652 want_garbage_collect = TRUE;
2653
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002654 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002655 garbage_collect_at_exit = TRUE;
2656}
2657
2658/*
2659 * "get()" function
2660 */
2661 static void
2662f_get(typval_T *argvars, typval_T *rettv)
2663{
2664 listitem_T *li;
2665 list_T *l;
2666 dictitem_T *di;
2667 dict_T *d;
2668 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002669 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002670
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002671 if (argvars[0].v_type == VAR_BLOB)
2672 {
2673 int error = FALSE;
2674 int idx = tv_get_number_chk(&argvars[1], &error);
2675
2676 if (!error)
2677 {
2678 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002679 if (idx < 0)
2680 idx = blob_len(argvars[0].vval.v_blob) + idx;
2681 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2682 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002683 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002684 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002685 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002686 tv = rettv;
2687 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002688 }
2689 }
2690 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 {
2692 if ((l = argvars[0].vval.v_list) != NULL)
2693 {
2694 int error = FALSE;
2695
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002696 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002697 if (!error && li != NULL)
2698 tv = &li->li_tv;
2699 }
2700 }
2701 else if (argvars[0].v_type == VAR_DICT)
2702 {
2703 if ((d = argvars[0].vval.v_dict) != NULL)
2704 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002705 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002706 if (di != NULL)
2707 tv = &di->di_tv;
2708 }
2709 }
2710 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2711 {
2712 partial_T *pt;
2713 partial_T fref_pt;
2714
2715 if (argvars[0].v_type == VAR_PARTIAL)
2716 pt = argvars[0].vval.v_partial;
2717 else
2718 {
2719 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2720 fref_pt.pt_name = argvars[0].vval.v_string;
2721 pt = &fref_pt;
2722 }
2723
2724 if (pt != NULL)
2725 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002726 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002727 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728
2729 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2730 {
2731 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002732 n = partial_name(pt);
2733 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002734 rettv->vval.v_string = NULL;
2735 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002736 {
2737 rettv->vval.v_string = vim_strsave(n);
2738 if (rettv->v_type == VAR_FUNC)
2739 func_ref(rettv->vval.v_string);
2740 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002741 }
2742 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002743 {
2744 what_is_dict = TRUE;
2745 if (pt->pt_dict != NULL)
2746 rettv_dict_set(rettv, pt->pt_dict);
2747 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002748 else if (STRCMP(what, "args") == 0)
2749 {
2750 rettv->v_type = VAR_LIST;
2751 if (rettv_list_alloc(rettv) == OK)
2752 {
2753 int i;
2754
2755 for (i = 0; i < pt->pt_argc; ++i)
2756 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2757 }
2758 }
2759 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002760 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002761
2762 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2763 // third argument
2764 if (!what_is_dict)
2765 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002766 }
2767 }
2768 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002769 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770
2771 if (tv == NULL)
2772 {
2773 if (argvars[2].v_type != VAR_UNKNOWN)
2774 copy_tv(&argvars[2], rettv);
2775 }
2776 else
2777 copy_tv(tv, rettv);
2778}
2779
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002780/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002781 * "getchangelist()" function
2782 */
2783 static void
2784f_getchangelist(typval_T *argvars, typval_T *rettv)
2785{
2786#ifdef FEAT_JUMPLIST
2787 buf_T *buf;
2788 int i;
2789 list_T *l;
2790 dict_T *d;
2791#endif
2792
2793 if (rettv_list_alloc(rettv) != OK)
2794 return;
2795
2796#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002797 if (argvars[0].v_type == VAR_UNKNOWN)
2798 buf = curbuf;
2799 else
2800 {
2801 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2802 ++emsg_off;
2803 buf = tv_get_buf(&argvars[0], FALSE);
2804 --emsg_off;
2805 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002806 if (buf == NULL)
2807 return;
2808
2809 l = list_alloc();
2810 if (l == NULL)
2811 return;
2812
2813 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2814 return;
2815 /*
2816 * The current window change list index tracks only the position in the
2817 * current buffer change list. For other buffers, use the change list
2818 * length as the current index.
2819 */
2820 list_append_number(rettv->vval.v_list,
2821 (varnumber_T)((buf == curwin->w_buffer)
2822 ? curwin->w_changelistidx : buf->b_changelistlen));
2823
2824 for (i = 0; i < buf->b_changelistlen; ++i)
2825 {
2826 if (buf->b_changelist[i].lnum == 0)
2827 continue;
2828 if ((d = dict_alloc()) == NULL)
2829 return;
2830 if (list_append_dict(l, d) == FAIL)
2831 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002832 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2833 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002834 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002835 }
2836#endif
2837}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002838
2839/*
2840 * "getcharsearch()" function
2841 */
2842 static void
2843f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2844{
2845 if (rettv_dict_alloc(rettv) != FAIL)
2846 {
2847 dict_T *dict = rettv->vval.v_dict;
2848
Bram Moolenaare0be1672018-07-08 16:50:37 +02002849 dict_add_string(dict, "char", last_csearch());
2850 dict_add_number(dict, "forward", last_csearch_forward());
2851 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002852 }
2853}
2854
2855/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002856 * "getcmdwintype()" function
2857 */
2858 static void
2859f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2860{
2861 rettv->v_type = VAR_STRING;
2862 rettv->vval.v_string = NULL;
2863#ifdef FEAT_CMDWIN
2864 rettv->vval.v_string = alloc(2);
2865 if (rettv->vval.v_string != NULL)
2866 {
2867 rettv->vval.v_string[0] = cmdwin_type;
2868 rettv->vval.v_string[1] = NUL;
2869 }
2870#endif
2871}
2872
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002873/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002874 * "getenv()" function
2875 */
2876 static void
2877f_getenv(typval_T *argvars, typval_T *rettv)
2878{
2879 int mustfree = FALSE;
2880 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2881
2882 if (p == NULL)
2883 {
2884 rettv->v_type = VAR_SPECIAL;
2885 rettv->vval.v_number = VVAL_NULL;
2886 return;
2887 }
2888 if (!mustfree)
2889 p = vim_strsave(p);
2890 rettv->vval.v_string = p;
2891 rettv->v_type = VAR_STRING;
2892}
2893
2894/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002895 * "getfontname()" function
2896 */
2897 static void
2898f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2899{
2900 rettv->v_type = VAR_STRING;
2901 rettv->vval.v_string = NULL;
2902#ifdef FEAT_GUI
2903 if (gui.in_use)
2904 {
2905 GuiFont font;
2906 char_u *name = NULL;
2907
2908 if (argvars[0].v_type == VAR_UNKNOWN)
2909 {
2910 /* Get the "Normal" font. Either the name saved by
2911 * hl_set_font_name() or from the font ID. */
2912 font = gui.norm_font;
2913 name = hl_get_font_name();
2914 }
2915 else
2916 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002917 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002918 if (STRCMP(name, "*") == 0) /* don't use font dialog */
2919 return;
2920 font = gui_mch_get_font(name, FALSE);
2921 if (font == NOFONT)
2922 return; /* Invalid font name, return empty string. */
2923 }
2924 rettv->vval.v_string = gui_mch_get_fontname(font, name);
2925 if (argvars[0].v_type != VAR_UNKNOWN)
2926 gui_mch_free_font(font);
2927 }
2928#endif
2929}
2930
2931/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01002932 * "getjumplist()" function
2933 */
2934 static void
2935f_getjumplist(typval_T *argvars, typval_T *rettv)
2936{
2937#ifdef FEAT_JUMPLIST
2938 win_T *wp;
2939 int i;
2940 list_T *l;
2941 dict_T *d;
2942#endif
2943
2944 if (rettv_list_alloc(rettv) != OK)
2945 return;
2946
2947#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02002948 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002949 if (wp == NULL)
2950 return;
2951
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01002952 cleanup_jumplist(wp, TRUE);
2953
Bram Moolenaar4f505882018-02-10 21:06:32 +01002954 l = list_alloc();
2955 if (l == NULL)
2956 return;
2957
2958 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2959 return;
2960 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
2961
2962 for (i = 0; i < wp->w_jumplistlen; ++i)
2963 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002964 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
2965 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01002966 if ((d = dict_alloc()) == NULL)
2967 return;
2968 if (list_append_dict(l, d) == FAIL)
2969 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002970 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
2971 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002972 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002973 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002974 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02002975 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002976 }
2977#endif
2978}
2979
2980/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002981 * "getpid()" function
2982 */
2983 static void
2984f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
2985{
2986 rettv->vval.v_number = mch_get_pid();
2987}
2988
2989 static void
2990getpos_both(
2991 typval_T *argvars,
2992 typval_T *rettv,
2993 int getcurpos)
2994{
2995 pos_T *fp;
2996 list_T *l;
2997 int fnum = -1;
2998
2999 if (rettv_list_alloc(rettv) == OK)
3000 {
3001 l = rettv->vval.v_list;
3002 if (getcurpos)
3003 fp = &curwin->w_cursor;
3004 else
3005 fp = var2fpos(&argvars[0], TRUE, &fnum);
3006 if (fnum != -1)
3007 list_append_number(l, (varnumber_T)fnum);
3008 else
3009 list_append_number(l, (varnumber_T)0);
3010 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3011 : (varnumber_T)0);
3012 list_append_number(l, (fp != NULL)
3013 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3014 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003015 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003016 (varnumber_T)0);
3017 if (getcurpos)
3018 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003019 int save_set_curswant = curwin->w_set_curswant;
3020 colnr_T save_curswant = curwin->w_curswant;
3021 colnr_T save_virtcol = curwin->w_virtcol;
3022
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003023 update_curswant();
3024 list_append_number(l, curwin->w_curswant == MAXCOL ?
3025 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003026
3027 // Do not change "curswant", as it is unexpected that a get
3028 // function has a side effect.
3029 if (save_set_curswant)
3030 {
3031 curwin->w_set_curswant = save_set_curswant;
3032 curwin->w_curswant = save_curswant;
3033 curwin->w_virtcol = save_virtcol;
3034 curwin->w_valid &= ~VALID_VIRTCOL;
3035 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 }
3037 }
3038 else
3039 rettv->vval.v_number = FALSE;
3040}
3041
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003042/*
3043 * "getcurpos()" function
3044 */
3045 static void
3046f_getcurpos(typval_T *argvars, typval_T *rettv)
3047{
3048 getpos_both(argvars, rettv, TRUE);
3049}
3050
3051/*
3052 * "getpos(string)" function
3053 */
3054 static void
3055f_getpos(typval_T *argvars, typval_T *rettv)
3056{
3057 getpos_both(argvars, rettv, FALSE);
3058}
3059
3060/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003061 * "getreg()" function
3062 */
3063 static void
3064f_getreg(typval_T *argvars, typval_T *rettv)
3065{
3066 char_u *strregname;
3067 int regname;
3068 int arg2 = FALSE;
3069 int return_list = FALSE;
3070 int error = FALSE;
3071
3072 if (argvars[0].v_type != VAR_UNKNOWN)
3073 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003074 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 error = strregname == NULL;
3076 if (argvars[1].v_type != VAR_UNKNOWN)
3077 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003078 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003079 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003080 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003081 }
3082 }
3083 else
3084 strregname = get_vim_var_str(VV_REG);
3085
3086 if (error)
3087 return;
3088
3089 regname = (strregname == NULL ? '"' : *strregname);
3090 if (regname == 0)
3091 regname = '"';
3092
3093 if (return_list)
3094 {
3095 rettv->v_type = VAR_LIST;
3096 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3097 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3098 if (rettv->vval.v_list == NULL)
3099 (void)rettv_list_alloc(rettv);
3100 else
3101 ++rettv->vval.v_list->lv_refcount;
3102 }
3103 else
3104 {
3105 rettv->v_type = VAR_STRING;
3106 rettv->vval.v_string = get_reg_contents(regname,
3107 arg2 ? GREG_EXPR_SRC : 0);
3108 }
3109}
3110
3111/*
3112 * "getregtype()" function
3113 */
3114 static void
3115f_getregtype(typval_T *argvars, typval_T *rettv)
3116{
3117 char_u *strregname;
3118 int regname;
3119 char_u buf[NUMBUFLEN + 2];
3120 long reglen = 0;
3121
3122 if (argvars[0].v_type != VAR_UNKNOWN)
3123 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003124 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003125 if (strregname == NULL) /* type error; errmsg already given */
3126 {
3127 rettv->v_type = VAR_STRING;
3128 rettv->vval.v_string = NULL;
3129 return;
3130 }
3131 }
3132 else
3133 /* Default to v:register */
3134 strregname = get_vim_var_str(VV_REG);
3135
3136 regname = (strregname == NULL ? '"' : *strregname);
3137 if (regname == 0)
3138 regname = '"';
3139
3140 buf[0] = NUL;
3141 buf[1] = NUL;
3142 switch (get_reg_type(regname, &reglen))
3143 {
3144 case MLINE: buf[0] = 'V'; break;
3145 case MCHAR: buf[0] = 'v'; break;
3146 case MBLOCK:
3147 buf[0] = Ctrl_V;
3148 sprintf((char *)buf + 1, "%ld", reglen + 1);
3149 break;
3150 }
3151 rettv->v_type = VAR_STRING;
3152 rettv->vval.v_string = vim_strsave(buf);
3153}
3154
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003155/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003156 * "gettagstack()" function
3157 */
3158 static void
3159f_gettagstack(typval_T *argvars, typval_T *rettv)
3160{
3161 win_T *wp = curwin; // default is current window
3162
3163 if (rettv_dict_alloc(rettv) != OK)
3164 return;
3165
3166 if (argvars[0].v_type != VAR_UNKNOWN)
3167 {
3168 wp = find_win_by_nr_or_id(&argvars[0]);
3169 if (wp == NULL)
3170 return;
3171 }
3172
3173 get_tagstack(wp, rettv->vval.v_dict);
3174}
3175
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003176/* for VIM_VERSION_ defines */
3177#include "version.h"
3178
3179/*
3180 * "has()" function
3181 */
3182 static void
3183f_has(typval_T *argvars, typval_T *rettv)
3184{
3185 int i;
3186 char_u *name;
3187 int n = FALSE;
3188 static char *(has_list[]) =
3189 {
3190#ifdef AMIGA
3191 "amiga",
3192# ifdef FEAT_ARP
3193 "arp",
3194# endif
3195#endif
3196#ifdef __BEOS__
3197 "beos",
3198#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003199#if defined(BSD) && !defined(MACOS_X)
3200 "bsd",
3201#endif
3202#ifdef hpux
3203 "hpux",
3204#endif
3205#ifdef __linux__
3206 "linux",
3207#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003208#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003209 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3210 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003211# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003212 "macunix", /* Mac OS X, with the darwin feature */
3213 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003214# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003215#endif
3216#ifdef __QNX__
3217 "qnx",
3218#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003219#ifdef SUN_SYSTEM
3220 "sun",
3221#else
3222 "moon",
3223#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003224#ifdef UNIX
3225 "unix",
3226#endif
3227#ifdef VMS
3228 "vms",
3229#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003230#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003231 "win32",
3232#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003233#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003234 "win32unix",
3235#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003236#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003237 "win64",
3238#endif
3239#ifdef EBCDIC
3240 "ebcdic",
3241#endif
3242#ifndef CASE_INSENSITIVE_FILENAME
3243 "fname_case",
3244#endif
3245#ifdef HAVE_ACL
3246 "acl",
3247#endif
3248#ifdef FEAT_ARABIC
3249 "arabic",
3250#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003251 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003252#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003253 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003254#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003255#ifdef FEAT_AUTOSERVERNAME
3256 "autoservername",
3257#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003258#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003259 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003260# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003261 "balloon_multiline",
3262# endif
3263#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003264#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003265 "balloon_eval_term",
3266#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003267#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3268 "builtin_terms",
3269# ifdef ALL_BUILTIN_TCAPS
3270 "all_builtin_terms",
3271# endif
3272#endif
3273#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003274 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003275 || defined(FEAT_GUI_MOTIF))
3276 "browsefilter",
3277#endif
3278#ifdef FEAT_BYTEOFF
3279 "byte_offset",
3280#endif
3281#ifdef FEAT_JOB_CHANNEL
3282 "channel",
3283#endif
3284#ifdef FEAT_CINDENT
3285 "cindent",
3286#endif
3287#ifdef FEAT_CLIENTSERVER
3288 "clientserver",
3289#endif
3290#ifdef FEAT_CLIPBOARD
3291 "clipboard",
3292#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003293 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003294 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003295 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003296#ifdef FEAT_CONCEAL
3297 "conceal",
3298#endif
3299#ifdef FEAT_CRYPT
3300 "cryptv",
3301 "crypt-blowfish",
3302 "crypt-blowfish2",
3303#endif
3304#ifdef FEAT_CSCOPE
3305 "cscope",
3306#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003307 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308#ifdef CURSOR_SHAPE
3309 "cursorshape",
3310#endif
3311#ifdef DEBUG
3312 "debug",
3313#endif
3314#ifdef FEAT_CON_DIALOG
3315 "dialog_con",
3316#endif
3317#ifdef FEAT_GUI_DIALOG
3318 "dialog_gui",
3319#endif
3320#ifdef FEAT_DIFF
3321 "diff",
3322#endif
3323#ifdef FEAT_DIGRAPHS
3324 "digraphs",
3325#endif
3326#ifdef FEAT_DIRECTX
3327 "directx",
3328#endif
3329#ifdef FEAT_DND
3330 "dnd",
3331#endif
3332#ifdef FEAT_EMACS_TAGS
3333 "emacs_tags",
3334#endif
3335 "eval", /* always present, of course! */
3336 "ex_extra", /* graduated feature */
3337#ifdef FEAT_SEARCH_EXTRA
3338 "extra_search",
3339#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003340#ifdef FEAT_SEARCHPATH
3341 "file_in_path",
3342#endif
3343#ifdef FEAT_FILTERPIPE
3344 "filterpipe",
3345#endif
3346#ifdef FEAT_FIND_ID
3347 "find_in_path",
3348#endif
3349#ifdef FEAT_FLOAT
3350 "float",
3351#endif
3352#ifdef FEAT_FOLDING
3353 "folding",
3354#endif
3355#ifdef FEAT_FOOTER
3356 "footer",
3357#endif
3358#if !defined(USE_SYSTEM) && defined(UNIX)
3359 "fork",
3360#endif
3361#ifdef FEAT_GETTEXT
3362 "gettext",
3363#endif
3364#ifdef FEAT_GUI
3365 "gui",
3366#endif
3367#ifdef FEAT_GUI_ATHENA
3368# ifdef FEAT_GUI_NEXTAW
3369 "gui_neXtaw",
3370# else
3371 "gui_athena",
3372# endif
3373#endif
3374#ifdef FEAT_GUI_GTK
3375 "gui_gtk",
3376# ifdef USE_GTK3
3377 "gui_gtk3",
3378# else
3379 "gui_gtk2",
3380# endif
3381#endif
3382#ifdef FEAT_GUI_GNOME
3383 "gui_gnome",
3384#endif
3385#ifdef FEAT_GUI_MAC
3386 "gui_mac",
3387#endif
3388#ifdef FEAT_GUI_MOTIF
3389 "gui_motif",
3390#endif
3391#ifdef FEAT_GUI_PHOTON
3392 "gui_photon",
3393#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003394#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003395 "gui_win32",
3396#endif
3397#ifdef FEAT_HANGULIN
3398 "hangul_input",
3399#endif
3400#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3401 "iconv",
3402#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003404#ifdef FEAT_JOB_CHANNEL
3405 "job",
3406#endif
3407#ifdef FEAT_JUMPLIST
3408 "jumplist",
3409#endif
3410#ifdef FEAT_KEYMAP
3411 "keymap",
3412#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003413 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003414#ifdef FEAT_LANGMAP
3415 "langmap",
3416#endif
3417#ifdef FEAT_LIBCALL
3418 "libcall",
3419#endif
3420#ifdef FEAT_LINEBREAK
3421 "linebreak",
3422#endif
3423#ifdef FEAT_LISP
3424 "lispindent",
3425#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003426 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003427 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428#ifdef FEAT_LUA
3429# ifndef DYNAMIC_LUA
3430 "lua",
3431# endif
3432#endif
3433#ifdef FEAT_MENU
3434 "menu",
3435#endif
3436#ifdef FEAT_SESSION
3437 "mksession",
3438#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003439 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003440 "mouse",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003441#ifdef FEAT_MOUSESHAPE
3442 "mouseshape",
3443#endif
3444#if defined(UNIX) || defined(VMS)
3445# ifdef FEAT_MOUSE_DEC
3446 "mouse_dec",
3447# endif
3448# ifdef FEAT_MOUSE_GPM
3449 "mouse_gpm",
3450# endif
3451# ifdef FEAT_MOUSE_JSB
3452 "mouse_jsbterm",
3453# endif
3454# ifdef FEAT_MOUSE_NET
3455 "mouse_netterm",
3456# endif
3457# ifdef FEAT_MOUSE_PTERM
3458 "mouse_pterm",
3459# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003460# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003461 "mouse_sgr",
3462# endif
3463# ifdef FEAT_SYSMOUSE
3464 "mouse_sysmouse",
3465# endif
3466# ifdef FEAT_MOUSE_URXVT
3467 "mouse_urxvt",
3468# endif
3469# ifdef FEAT_MOUSE_XTERM
3470 "mouse_xterm",
3471# endif
3472#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003473 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003474#ifdef FEAT_MBYTE_IME
3475 "multi_byte_ime",
3476#endif
3477#ifdef FEAT_MULTI_LANG
3478 "multi_lang",
3479#endif
3480#ifdef FEAT_MZSCHEME
3481#ifndef DYNAMIC_MZSCHEME
3482 "mzscheme",
3483#endif
3484#endif
3485#ifdef FEAT_NUM64
3486 "num64",
3487#endif
3488#ifdef FEAT_OLE
3489 "ole",
3490#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003491#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003493#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003494#ifdef FEAT_PATH_EXTRA
3495 "path_extra",
3496#endif
3497#ifdef FEAT_PERL
3498#ifndef DYNAMIC_PERL
3499 "perl",
3500#endif
3501#endif
3502#ifdef FEAT_PERSISTENT_UNDO
3503 "persistent_undo",
3504#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003505#if defined(FEAT_PYTHON)
3506 "python_compiled",
3507# if defined(DYNAMIC_PYTHON)
3508 "python_dynamic",
3509# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003510 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003511 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003512# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003513#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003514#if defined(FEAT_PYTHON3)
3515 "python3_compiled",
3516# if defined(DYNAMIC_PYTHON3)
3517 "python3_dynamic",
3518# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003519 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003520 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003521# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003522#endif
3523#ifdef FEAT_POSTSCRIPT
3524 "postscript",
3525#endif
3526#ifdef FEAT_PRINTER
3527 "printer",
3528#endif
3529#ifdef FEAT_PROFILE
3530 "profile",
3531#endif
3532#ifdef FEAT_RELTIME
3533 "reltime",
3534#endif
3535#ifdef FEAT_QUICKFIX
3536 "quickfix",
3537#endif
3538#ifdef FEAT_RIGHTLEFT
3539 "rightleft",
3540#endif
3541#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3542 "ruby",
3543#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003544 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003545#ifdef FEAT_CMDL_INFO
3546 "showcmd",
3547 "cmdline_info",
3548#endif
3549#ifdef FEAT_SIGNS
3550 "signs",
3551#endif
3552#ifdef FEAT_SMARTINDENT
3553 "smartindent",
3554#endif
3555#ifdef STARTUPTIME
3556 "startuptime",
3557#endif
3558#ifdef FEAT_STL_OPT
3559 "statusline",
3560#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561#ifdef FEAT_NETBEANS_INTG
3562 "netbeans_intg",
3563#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003564#ifdef FEAT_SOUND
3565 "sound",
3566#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003567#ifdef FEAT_SPELL
3568 "spell",
3569#endif
3570#ifdef FEAT_SYN_HL
3571 "syntax",
3572#endif
3573#if defined(USE_SYSTEM) || !defined(UNIX)
3574 "system",
3575#endif
3576#ifdef FEAT_TAG_BINS
3577 "tag_binary",
3578#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003579#ifdef FEAT_TCL
3580# ifndef DYNAMIC_TCL
3581 "tcl",
3582# endif
3583#endif
3584#ifdef FEAT_TERMGUICOLORS
3585 "termguicolors",
3586#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003587#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003588 "terminal",
3589#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003590#ifdef TERMINFO
3591 "terminfo",
3592#endif
3593#ifdef FEAT_TERMRESPONSE
3594 "termresponse",
3595#endif
3596#ifdef FEAT_TEXTOBJ
3597 "textobjects",
3598#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003599#ifdef FEAT_TEXT_PROP
3600 "textprop",
3601#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602#ifdef HAVE_TGETENT
3603 "tgetent",
3604#endif
3605#ifdef FEAT_TIMERS
3606 "timers",
3607#endif
3608#ifdef FEAT_TITLE
3609 "title",
3610#endif
3611#ifdef FEAT_TOOLBAR
3612 "toolbar",
3613#endif
3614#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3615 "unnamedplus",
3616#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003617 "user-commands", /* was accidentally included in 5.4 */
3618 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003619#ifdef FEAT_VARTABS
3620 "vartabs",
3621#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003622 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003623#ifdef FEAT_VIMINFO
3624 "viminfo",
3625#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003626 "vimscript-1",
3627 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003628 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003629 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003630 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003631 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003632 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003633 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003634#ifdef FEAT_VTP
3635 "vtp",
3636#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637#ifdef FEAT_WILDIGN
3638 "wildignore",
3639#endif
3640#ifdef FEAT_WILDMENU
3641 "wildmenu",
3642#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644#ifdef FEAT_WAK
3645 "winaltkeys",
3646#endif
3647#ifdef FEAT_WRITEBACKUP
3648 "writebackup",
3649#endif
3650#ifdef FEAT_XIM
3651 "xim",
3652#endif
3653#ifdef FEAT_XFONTSET
3654 "xfontset",
3655#endif
3656#ifdef FEAT_XPM_W32
3657 "xpm",
3658 "xpm_w32", /* for backward compatibility */
3659#else
3660# if defined(HAVE_XPM)
3661 "xpm",
3662# endif
3663#endif
3664#ifdef USE_XSMP
3665 "xsmp",
3666#endif
3667#ifdef USE_XSMP_INTERACT
3668 "xsmp_interact",
3669#endif
3670#ifdef FEAT_XCLIPBOARD
3671 "xterm_clipboard",
3672#endif
3673#ifdef FEAT_XTERM_SAVE
3674 "xterm_save",
3675#endif
3676#if defined(UNIX) && defined(FEAT_X11)
3677 "X11",
3678#endif
3679 NULL
3680 };
3681
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003682 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003683 for (i = 0; has_list[i] != NULL; ++i)
3684 if (STRICMP(name, has_list[i]) == 0)
3685 {
3686 n = TRUE;
3687 break;
3688 }
3689
3690 if (n == FALSE)
3691 {
3692 if (STRNICMP(name, "patch", 5) == 0)
3693 {
3694 if (name[5] == '-'
3695 && STRLEN(name) >= 11
3696 && vim_isdigit(name[6])
3697 && vim_isdigit(name[8])
3698 && vim_isdigit(name[10]))
3699 {
3700 int major = atoi((char *)name + 6);
3701 int minor = atoi((char *)name + 8);
3702
3703 /* Expect "patch-9.9.01234". */
3704 n = (major < VIM_VERSION_MAJOR
3705 || (major == VIM_VERSION_MAJOR
3706 && (minor < VIM_VERSION_MINOR
3707 || (minor == VIM_VERSION_MINOR
3708 && has_patch(atoi((char *)name + 10))))));
3709 }
3710 else
3711 n = has_patch(atoi((char *)name + 5));
3712 }
3713 else if (STRICMP(name, "vim_starting") == 0)
3714 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003715 else if (STRICMP(name, "ttyin") == 0)
3716 n = mch_input_isatty();
3717 else if (STRICMP(name, "ttyout") == 0)
3718 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003719 else if (STRICMP(name, "multi_byte_encoding") == 0)
3720 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003721#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722 else if (STRICMP(name, "balloon_multiline") == 0)
3723 n = multiline_balloon_available();
3724#endif
3725#ifdef DYNAMIC_TCL
3726 else if (STRICMP(name, "tcl") == 0)
3727 n = tcl_enabled(FALSE);
3728#endif
3729#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3730 else if (STRICMP(name, "iconv") == 0)
3731 n = iconv_enabled(FALSE);
3732#endif
3733#ifdef DYNAMIC_LUA
3734 else if (STRICMP(name, "lua") == 0)
3735 n = lua_enabled(FALSE);
3736#endif
3737#ifdef DYNAMIC_MZSCHEME
3738 else if (STRICMP(name, "mzscheme") == 0)
3739 n = mzscheme_enabled(FALSE);
3740#endif
3741#ifdef DYNAMIC_RUBY
3742 else if (STRICMP(name, "ruby") == 0)
3743 n = ruby_enabled(FALSE);
3744#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003745#ifdef DYNAMIC_PYTHON
3746 else if (STRICMP(name, "python") == 0)
3747 n = python_enabled(FALSE);
3748#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003749#ifdef DYNAMIC_PYTHON3
3750 else if (STRICMP(name, "python3") == 0)
3751 n = python3_enabled(FALSE);
3752#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003753#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3754 else if (STRICMP(name, "pythonx") == 0)
3755 {
3756# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3757 if (p_pyx == 0)
3758 n = python3_enabled(FALSE) || python_enabled(FALSE);
3759 else if (p_pyx == 3)
3760 n = python3_enabled(FALSE);
3761 else if (p_pyx == 2)
3762 n = python_enabled(FALSE);
3763# elif defined(DYNAMIC_PYTHON)
3764 n = python_enabled(FALSE);
3765# elif defined(DYNAMIC_PYTHON3)
3766 n = python3_enabled(FALSE);
3767# endif
3768 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003769#endif
3770#ifdef DYNAMIC_PERL
3771 else if (STRICMP(name, "perl") == 0)
3772 n = perl_enabled(FALSE);
3773#endif
3774#ifdef FEAT_GUI
3775 else if (STRICMP(name, "gui_running") == 0)
3776 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777# ifdef FEAT_BROWSE
3778 else if (STRICMP(name, "browse") == 0)
3779 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3780# endif
3781#endif
3782#ifdef FEAT_SYN_HL
3783 else if (STRICMP(name, "syntax_items") == 0)
3784 n = syntax_present(curwin);
3785#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003786#ifdef FEAT_VTP
3787 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003788 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003789#endif
3790#ifdef FEAT_NETBEANS_INTG
3791 else if (STRICMP(name, "netbeans_enabled") == 0)
3792 n = netbeans_active();
3793#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003794#ifdef FEAT_MOUSE_GPM
3795 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3796 n = gpm_enabled();
3797#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003798#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003799 else if (STRICMP(name, "terminal") == 0)
3800 n = terminal_enabled();
3801#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003802#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003803 else if (STRICMP(name, "conpty") == 0)
3804 n = use_conpty();
3805#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003806#ifdef FEAT_CLIPBOARD
3807 else if (STRICMP(name, "clipboard_working") == 0)
3808 n = clip_star.available;
3809#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003810 }
3811
3812 rettv->vval.v_number = n;
3813}
3814
3815/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003816 * "haslocaldir()" function
3817 */
3818 static void
3819f_haslocaldir(typval_T *argvars, typval_T *rettv)
3820{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003821 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003822 win_T *wp = NULL;
3823
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003824 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3825
3826 // Check for window-local and tab-local directories
3827 if (wp != NULL && wp->w_localdir != NULL)
3828 rettv->vval.v_number = 1;
3829 else if (tp != NULL && tp->tp_localdir != NULL)
3830 rettv->vval.v_number = 2;
3831 else
3832 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003833}
3834
3835/*
3836 * "hasmapto()" function
3837 */
3838 static void
3839f_hasmapto(typval_T *argvars, typval_T *rettv)
3840{
3841 char_u *name;
3842 char_u *mode;
3843 char_u buf[NUMBUFLEN];
3844 int abbr = FALSE;
3845
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003846 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003847 if (argvars[1].v_type == VAR_UNKNOWN)
3848 mode = (char_u *)"nvo";
3849 else
3850 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003851 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003852 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003853 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003854 }
3855
3856 if (map_to_exists(name, mode, abbr))
3857 rettv->vval.v_number = TRUE;
3858 else
3859 rettv->vval.v_number = FALSE;
3860}
3861
3862/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003863 * "highlightID(name)" function
3864 */
3865 static void
3866f_hlID(typval_T *argvars, typval_T *rettv)
3867{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003868 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003869}
3870
3871/*
3872 * "highlight_exists()" function
3873 */
3874 static void
3875f_hlexists(typval_T *argvars, typval_T *rettv)
3876{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003877 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003878}
3879
3880/*
3881 * "hostname()" function
3882 */
3883 static void
3884f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3885{
3886 char_u hostname[256];
3887
3888 mch_get_host_name(hostname, 256);
3889 rettv->v_type = VAR_STRING;
3890 rettv->vval.v_string = vim_strsave(hostname);
3891}
3892
3893/*
3894 * iconv() function
3895 */
3896 static void
3897f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3898{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003899 char_u buf1[NUMBUFLEN];
3900 char_u buf2[NUMBUFLEN];
3901 char_u *from, *to, *str;
3902 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003903
3904 rettv->v_type = VAR_STRING;
3905 rettv->vval.v_string = NULL;
3906
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003907 str = tv_get_string(&argvars[0]);
3908 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3909 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003910 vimconv.vc_type = CONV_NONE;
3911 convert_setup(&vimconv, from, to);
3912
3913 /* If the encodings are equal, no conversion needed. */
3914 if (vimconv.vc_type == CONV_NONE)
3915 rettv->vval.v_string = vim_strsave(str);
3916 else
3917 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
3918
3919 convert_setup(&vimconv, NULL, NULL);
3920 vim_free(from);
3921 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003922}
3923
3924/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003925 * "index()" function
3926 */
3927 static void
3928f_index(typval_T *argvars, typval_T *rettv)
3929{
3930 list_T *l;
3931 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003932 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003933 long idx = 0;
3934 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003935 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003936
3937 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003938 if (argvars[0].v_type == VAR_BLOB)
3939 {
3940 typval_T tv;
3941 int start = 0;
3942
3943 if (argvars[2].v_type != VAR_UNKNOWN)
3944 {
3945 start = tv_get_number_chk(&argvars[2], &error);
3946 if (error)
3947 return;
3948 }
3949 b = argvars[0].vval.v_blob;
3950 if (b == NULL)
3951 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01003952 if (start < 0)
3953 {
3954 start = blob_len(b) + start;
3955 if (start < 0)
3956 start = 0;
3957 }
3958
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003959 for (idx = start; idx < blob_len(b); ++idx)
3960 {
3961 tv.v_type = VAR_NUMBER;
3962 tv.vval.v_number = blob_get(b, idx);
3963 if (tv_equal(&tv, &argvars[1], ic, FALSE))
3964 {
3965 rettv->vval.v_number = idx;
3966 return;
3967 }
3968 }
3969 return;
3970 }
3971 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003972 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003973 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003974 return;
3975 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003976
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003977 l = argvars[0].vval.v_list;
3978 if (l != NULL)
3979 {
3980 item = l->lv_first;
3981 if (argvars[2].v_type != VAR_UNKNOWN)
3982 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003983 /* Start at specified item. Use the cached index that list_find()
3984 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003985 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003986 idx = l->lv_idx;
3987 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003988 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003989 if (error)
3990 item = NULL;
3991 }
3992
3993 for ( ; item != NULL; item = item->li_next, ++idx)
3994 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
3995 {
3996 rettv->vval.v_number = idx;
3997 break;
3998 }
3999 }
4000}
4001
4002static int inputsecret_flag = 0;
4003
4004/*
4005 * "input()" function
4006 * Also handles inputsecret() when inputsecret is set.
4007 */
4008 static void
4009f_input(typval_T *argvars, typval_T *rettv)
4010{
4011 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4012}
4013
4014/*
4015 * "inputdialog()" function
4016 */
4017 static void
4018f_inputdialog(typval_T *argvars, typval_T *rettv)
4019{
4020#if defined(FEAT_GUI_TEXTDIALOG)
4021 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4022 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4023 {
4024 char_u *message;
4025 char_u buf[NUMBUFLEN];
4026 char_u *defstr = (char_u *)"";
4027
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004028 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004029 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004030 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004031 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4032 else
4033 IObuff[0] = NUL;
4034 if (message != NULL && defstr != NULL
4035 && do_dialog(VIM_QUESTION, NULL, message,
4036 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4037 rettv->vval.v_string = vim_strsave(IObuff);
4038 else
4039 {
4040 if (message != NULL && defstr != NULL
4041 && argvars[1].v_type != VAR_UNKNOWN
4042 && argvars[2].v_type != VAR_UNKNOWN)
4043 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004044 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004045 else
4046 rettv->vval.v_string = NULL;
4047 }
4048 rettv->v_type = VAR_STRING;
4049 }
4050 else
4051#endif
4052 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4053}
4054
4055/*
4056 * "inputlist()" function
4057 */
4058 static void
4059f_inputlist(typval_T *argvars, typval_T *rettv)
4060{
4061 listitem_T *li;
4062 int selected;
4063 int mouse_used;
4064
4065#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004066 /* While starting up, there is no place to enter text. When running tests
4067 * with --not-a-term we assume feedkeys() will be used. */
4068 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004069 return;
4070#endif
4071 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4072 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004073 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004074 return;
4075 }
4076
4077 msg_start();
4078 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4079 lines_left = Rows; /* avoid more prompt */
4080 msg_scroll = TRUE;
4081 msg_clr_eos();
4082
4083 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4084 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004085 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004086 msg_putchar('\n');
4087 }
4088
4089 /* Ask for choice. */
4090 selected = prompt_for_number(&mouse_used);
4091 if (mouse_used)
4092 selected -= lines_left;
4093
4094 rettv->vval.v_number = selected;
4095}
4096
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004097static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4098
4099/*
4100 * "inputrestore()" function
4101 */
4102 static void
4103f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4104{
4105 if (ga_userinput.ga_len > 0)
4106 {
4107 --ga_userinput.ga_len;
4108 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4109 + ga_userinput.ga_len);
4110 /* default return is zero == OK */
4111 }
4112 else if (p_verbose > 1)
4113 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004114 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004115 rettv->vval.v_number = 1; /* Failed */
4116 }
4117}
4118
4119/*
4120 * "inputsave()" function
4121 */
4122 static void
4123f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4124{
4125 /* Add an entry to the stack of typeahead storage. */
4126 if (ga_grow(&ga_userinput, 1) == OK)
4127 {
4128 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4129 + ga_userinput.ga_len);
4130 ++ga_userinput.ga_len;
4131 /* default return is zero == OK */
4132 }
4133 else
4134 rettv->vval.v_number = 1; /* Failed */
4135}
4136
4137/*
4138 * "inputsecret()" function
4139 */
4140 static void
4141f_inputsecret(typval_T *argvars, typval_T *rettv)
4142{
4143 ++cmdline_star;
4144 ++inputsecret_flag;
4145 f_input(argvars, rettv);
4146 --cmdline_star;
4147 --inputsecret_flag;
4148}
4149
4150/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004151 * "invert(expr)" function
4152 */
4153 static void
4154f_invert(typval_T *argvars, typval_T *rettv)
4155{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004156 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004157}
4158
4159/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004160 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4161 * or it refers to a List or Dictionary that is locked.
4162 */
4163 static int
4164tv_islocked(typval_T *tv)
4165{
4166 return (tv->v_lock & VAR_LOCKED)
4167 || (tv->v_type == VAR_LIST
4168 && tv->vval.v_list != NULL
4169 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4170 || (tv->v_type == VAR_DICT
4171 && tv->vval.v_dict != NULL
4172 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4173}
4174
4175/*
4176 * "islocked()" function
4177 */
4178 static void
4179f_islocked(typval_T *argvars, typval_T *rettv)
4180{
4181 lval_T lv;
4182 char_u *end;
4183 dictitem_T *di;
4184
4185 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004186 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004187 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004188 if (end != NULL && lv.ll_name != NULL)
4189 {
4190 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004191 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004192 else
4193 {
4194 if (lv.ll_tv == NULL)
4195 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004196 di = find_var(lv.ll_name, NULL, TRUE);
4197 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004198 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004199 /* Consider a variable locked when:
4200 * 1. the variable itself is locked
4201 * 2. the value of the variable is locked.
4202 * 3. the List or Dict value is locked.
4203 */
4204 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4205 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004206 }
4207 }
4208 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004209 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004210 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004211 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004212 else if (lv.ll_list != NULL)
4213 /* List item. */
4214 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4215 else
4216 /* Dictionary item. */
4217 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4218 }
4219 }
4220
4221 clear_lval(&lv);
4222}
4223
4224#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4225/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004226 * "isinf()" function
4227 */
4228 static void
4229f_isinf(typval_T *argvars, typval_T *rettv)
4230{
4231 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4232 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4233}
4234
4235/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004236 * "isnan()" function
4237 */
4238 static void
4239f_isnan(typval_T *argvars, typval_T *rettv)
4240{
4241 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4242 && isnan(argvars[0].vval.v_float);
4243}
4244#endif
4245
4246/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247 * "last_buffer_nr()" function.
4248 */
4249 static void
4250f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4251{
4252 int n = 0;
4253 buf_T *buf;
4254
Bram Moolenaar29323592016-07-24 22:04:11 +02004255 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004256 if (n < buf->b_fnum)
4257 n = buf->b_fnum;
4258
4259 rettv->vval.v_number = n;
4260}
4261
4262/*
4263 * "len()" function
4264 */
4265 static void
4266f_len(typval_T *argvars, typval_T *rettv)
4267{
4268 switch (argvars[0].v_type)
4269 {
4270 case VAR_STRING:
4271 case VAR_NUMBER:
4272 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004273 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004274 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004275 case VAR_BLOB:
4276 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4277 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004278 case VAR_LIST:
4279 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4280 break;
4281 case VAR_DICT:
4282 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4283 break;
4284 case VAR_UNKNOWN:
4285 case VAR_SPECIAL:
4286 case VAR_FLOAT:
4287 case VAR_FUNC:
4288 case VAR_PARTIAL:
4289 case VAR_JOB:
4290 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004291 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004292 break;
4293 }
4294}
4295
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004296 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004297libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004298{
4299#ifdef FEAT_LIBCALL
4300 char_u *string_in;
4301 char_u **string_result;
4302 int nr_result;
4303#endif
4304
4305 rettv->v_type = type;
4306 if (type != VAR_NUMBER)
4307 rettv->vval.v_string = NULL;
4308
4309 if (check_restricted() || check_secure())
4310 return;
4311
4312#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004313 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004314 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4315 {
4316 string_in = NULL;
4317 if (argvars[2].v_type == VAR_STRING)
4318 string_in = argvars[2].vval.v_string;
4319 if (type == VAR_NUMBER)
4320 string_result = NULL;
4321 else
4322 string_result = &rettv->vval.v_string;
4323 if (mch_libcall(argvars[0].vval.v_string,
4324 argvars[1].vval.v_string,
4325 string_in,
4326 argvars[2].vval.v_number,
4327 string_result,
4328 &nr_result) == OK
4329 && type == VAR_NUMBER)
4330 rettv->vval.v_number = nr_result;
4331 }
4332#endif
4333}
4334
4335/*
4336 * "libcall()" function
4337 */
4338 static void
4339f_libcall(typval_T *argvars, typval_T *rettv)
4340{
4341 libcall_common(argvars, rettv, VAR_STRING);
4342}
4343
4344/*
4345 * "libcallnr()" function
4346 */
4347 static void
4348f_libcallnr(typval_T *argvars, typval_T *rettv)
4349{
4350 libcall_common(argvars, rettv, VAR_NUMBER);
4351}
4352
4353/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004354 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004355 */
4356 static void
4357f_line(typval_T *argvars, typval_T *rettv)
4358{
4359 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004360 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004361 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004362 int id;
4363 tabpage_T *tp;
4364 win_T *wp;
4365 win_T *save_curwin;
4366 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004367
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004368 if (argvars[1].v_type != VAR_UNKNOWN)
4369 {
4370 // use window specified in the second argument
4371 id = (int)tv_get_number(&argvars[1]);
4372 wp = win_id2wp_tp(id, &tp);
4373 if (wp != NULL && tp != NULL)
4374 {
4375 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4376 == OK)
4377 {
4378 check_cursor();
4379 fp = var2fpos(&argvars[0], TRUE, &fnum);
4380 }
4381 restore_win_noblock(save_curwin, save_curtab, TRUE);
4382 }
4383 }
4384 else
4385 // use current window
4386 fp = var2fpos(&argvars[0], TRUE, &fnum);
4387
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004388 if (fp != NULL)
4389 lnum = fp->lnum;
4390 rettv->vval.v_number = lnum;
4391}
4392
4393/*
4394 * "line2byte(lnum)" function
4395 */
4396 static void
4397f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4398{
4399#ifndef FEAT_BYTEOFF
4400 rettv->vval.v_number = -1;
4401#else
4402 linenr_T lnum;
4403
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004404 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004405 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4406 rettv->vval.v_number = -1;
4407 else
4408 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4409 if (rettv->vval.v_number >= 0)
4410 ++rettv->vval.v_number;
4411#endif
4412}
4413
4414/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004415 * "localtime()" function
4416 */
4417 static void
4418f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4419{
4420 rettv->vval.v_number = (varnumber_T)time(NULL);
4421}
4422
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004423#ifdef FEAT_FLOAT
4424/*
4425 * "log()" function
4426 */
4427 static void
4428f_log(typval_T *argvars, typval_T *rettv)
4429{
4430 float_T f = 0.0;
4431
4432 rettv->v_type = VAR_FLOAT;
4433 if (get_float_arg(argvars, &f) == OK)
4434 rettv->vval.v_float = log(f);
4435 else
4436 rettv->vval.v_float = 0.0;
4437}
4438
4439/*
4440 * "log10()" function
4441 */
4442 static void
4443f_log10(typval_T *argvars, typval_T *rettv)
4444{
4445 float_T f = 0.0;
4446
4447 rettv->v_type = VAR_FLOAT;
4448 if (get_float_arg(argvars, &f) == OK)
4449 rettv->vval.v_float = log10(f);
4450 else
4451 rettv->vval.v_float = 0.0;
4452}
4453#endif
4454
4455#ifdef FEAT_LUA
4456/*
4457 * "luaeval()" function
4458 */
4459 static void
4460f_luaeval(typval_T *argvars, typval_T *rettv)
4461{
4462 char_u *str;
4463 char_u buf[NUMBUFLEN];
4464
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004465 if (check_restricted() || check_secure())
4466 return;
4467
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004468 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004469 do_luaeval(str, argvars + 1, rettv);
4470}
4471#endif
4472
4473/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004474 * "maparg()" function
4475 */
4476 static void
4477f_maparg(typval_T *argvars, typval_T *rettv)
4478{
4479 get_maparg(argvars, rettv, TRUE);
4480}
4481
4482/*
4483 * "mapcheck()" function
4484 */
4485 static void
4486f_mapcheck(typval_T *argvars, typval_T *rettv)
4487{
4488 get_maparg(argvars, rettv, FALSE);
4489}
4490
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004491typedef enum
4492{
4493 MATCH_END, /* matchend() */
4494 MATCH_MATCH, /* match() */
4495 MATCH_STR, /* matchstr() */
4496 MATCH_LIST, /* matchlist() */
4497 MATCH_POS /* matchstrpos() */
4498} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004499
4500 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004501find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004502{
4503 char_u *str = NULL;
4504 long len = 0;
4505 char_u *expr = NULL;
4506 char_u *pat;
4507 regmatch_T regmatch;
4508 char_u patbuf[NUMBUFLEN];
4509 char_u strbuf[NUMBUFLEN];
4510 char_u *save_cpo;
4511 long start = 0;
4512 long nth = 1;
4513 colnr_T startcol = 0;
4514 int match = 0;
4515 list_T *l = NULL;
4516 listitem_T *li = NULL;
4517 long idx = 0;
4518 char_u *tofree = NULL;
4519
4520 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4521 save_cpo = p_cpo;
4522 p_cpo = (char_u *)"";
4523
4524 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004525 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004526 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004527 /* type MATCH_LIST: return empty list when there are no matches.
4528 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004529 if (rettv_list_alloc(rettv) == FAIL)
4530 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004531 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004532 && (list_append_string(rettv->vval.v_list,
4533 (char_u *)"", 0) == FAIL
4534 || list_append_number(rettv->vval.v_list,
4535 (varnumber_T)-1) == FAIL
4536 || list_append_number(rettv->vval.v_list,
4537 (varnumber_T)-1) == FAIL
4538 || list_append_number(rettv->vval.v_list,
4539 (varnumber_T)-1) == FAIL))
4540 {
4541 list_free(rettv->vval.v_list);
4542 rettv->vval.v_list = NULL;
4543 goto theend;
4544 }
4545 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004546 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004547 {
4548 rettv->v_type = VAR_STRING;
4549 rettv->vval.v_string = NULL;
4550 }
4551
4552 if (argvars[0].v_type == VAR_LIST)
4553 {
4554 if ((l = argvars[0].vval.v_list) == NULL)
4555 goto theend;
4556 li = l->lv_first;
4557 }
4558 else
4559 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004560 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004561 len = (long)STRLEN(str);
4562 }
4563
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004564 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004565 if (pat == NULL)
4566 goto theend;
4567
4568 if (argvars[2].v_type != VAR_UNKNOWN)
4569 {
4570 int error = FALSE;
4571
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004572 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004573 if (error)
4574 goto theend;
4575 if (l != NULL)
4576 {
4577 li = list_find(l, start);
4578 if (li == NULL)
4579 goto theend;
4580 idx = l->lv_idx; /* use the cached index */
4581 }
4582 else
4583 {
4584 if (start < 0)
4585 start = 0;
4586 if (start > len)
4587 goto theend;
4588 /* When "count" argument is there ignore matches before "start",
4589 * otherwise skip part of the string. Differs when pattern is "^"
4590 * or "\<". */
4591 if (argvars[3].v_type != VAR_UNKNOWN)
4592 startcol = start;
4593 else
4594 {
4595 str += start;
4596 len -= start;
4597 }
4598 }
4599
4600 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004601 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004602 if (error)
4603 goto theend;
4604 }
4605
4606 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4607 if (regmatch.regprog != NULL)
4608 {
4609 regmatch.rm_ic = p_ic;
4610
4611 for (;;)
4612 {
4613 if (l != NULL)
4614 {
4615 if (li == NULL)
4616 {
4617 match = FALSE;
4618 break;
4619 }
4620 vim_free(tofree);
4621 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4622 if (str == NULL)
4623 break;
4624 }
4625
4626 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4627
4628 if (match && --nth <= 0)
4629 break;
4630 if (l == NULL && !match)
4631 break;
4632
4633 /* Advance to just after the match. */
4634 if (l != NULL)
4635 {
4636 li = li->li_next;
4637 ++idx;
4638 }
4639 else
4640 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004641 startcol = (colnr_T)(regmatch.startp[0]
4642 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004643 if (startcol > (colnr_T)len
4644 || str + startcol <= regmatch.startp[0])
4645 {
4646 match = FALSE;
4647 break;
4648 }
4649 }
4650 }
4651
4652 if (match)
4653 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004654 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004655 {
4656 listitem_T *li1 = rettv->vval.v_list->lv_first;
4657 listitem_T *li2 = li1->li_next;
4658 listitem_T *li3 = li2->li_next;
4659 listitem_T *li4 = li3->li_next;
4660
4661 vim_free(li1->li_tv.vval.v_string);
4662 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4663 (int)(regmatch.endp[0] - regmatch.startp[0]));
4664 li3->li_tv.vval.v_number =
4665 (varnumber_T)(regmatch.startp[0] - expr);
4666 li4->li_tv.vval.v_number =
4667 (varnumber_T)(regmatch.endp[0] - expr);
4668 if (l != NULL)
4669 li2->li_tv.vval.v_number = (varnumber_T)idx;
4670 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004671 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004672 {
4673 int i;
4674
4675 /* return list with matched string and submatches */
4676 for (i = 0; i < NSUBEXP; ++i)
4677 {
4678 if (regmatch.endp[i] == NULL)
4679 {
4680 if (list_append_string(rettv->vval.v_list,
4681 (char_u *)"", 0) == FAIL)
4682 break;
4683 }
4684 else if (list_append_string(rettv->vval.v_list,
4685 regmatch.startp[i],
4686 (int)(regmatch.endp[i] - regmatch.startp[i]))
4687 == FAIL)
4688 break;
4689 }
4690 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004691 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004692 {
4693 /* return matched string */
4694 if (l != NULL)
4695 copy_tv(&li->li_tv, rettv);
4696 else
4697 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4698 (int)(regmatch.endp[0] - regmatch.startp[0]));
4699 }
4700 else if (l != NULL)
4701 rettv->vval.v_number = idx;
4702 else
4703 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004704 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004705 rettv->vval.v_number =
4706 (varnumber_T)(regmatch.startp[0] - str);
4707 else
4708 rettv->vval.v_number =
4709 (varnumber_T)(regmatch.endp[0] - str);
4710 rettv->vval.v_number += (varnumber_T)(str - expr);
4711 }
4712 }
4713 vim_regfree(regmatch.regprog);
4714 }
4715
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004716theend:
4717 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718 /* matchstrpos() without a list: drop the second item. */
4719 listitem_remove(rettv->vval.v_list,
4720 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004721 vim_free(tofree);
4722 p_cpo = save_cpo;
4723}
4724
4725/*
4726 * "match()" function
4727 */
4728 static void
4729f_match(typval_T *argvars, typval_T *rettv)
4730{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004731 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004732}
4733
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734/*
4735 * "matchend()" function
4736 */
4737 static void
4738f_matchend(typval_T *argvars, typval_T *rettv)
4739{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004740 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004741}
4742
4743/*
4744 * "matchlist()" function
4745 */
4746 static void
4747f_matchlist(typval_T *argvars, typval_T *rettv)
4748{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004749 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004750}
4751
4752/*
4753 * "matchstr()" function
4754 */
4755 static void
4756f_matchstr(typval_T *argvars, typval_T *rettv)
4757{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004758 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004759}
4760
4761/*
4762 * "matchstrpos()" function
4763 */
4764 static void
4765f_matchstrpos(typval_T *argvars, typval_T *rettv)
4766{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004767 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768}
4769
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004770 static void
4771max_min(typval_T *argvars, typval_T *rettv, int domax)
4772{
4773 varnumber_T n = 0;
4774 varnumber_T i;
4775 int error = FALSE;
4776
4777 if (argvars[0].v_type == VAR_LIST)
4778 {
4779 list_T *l;
4780 listitem_T *li;
4781
4782 l = argvars[0].vval.v_list;
4783 if (l != NULL)
4784 {
4785 li = l->lv_first;
4786 if (li != NULL)
4787 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004788 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004789 for (;;)
4790 {
4791 li = li->li_next;
4792 if (li == NULL)
4793 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004794 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004795 if (domax ? i > n : i < n)
4796 n = i;
4797 }
4798 }
4799 }
4800 }
4801 else if (argvars[0].v_type == VAR_DICT)
4802 {
4803 dict_T *d;
4804 int first = TRUE;
4805 hashitem_T *hi;
4806 int todo;
4807
4808 d = argvars[0].vval.v_dict;
4809 if (d != NULL)
4810 {
4811 todo = (int)d->dv_hashtab.ht_used;
4812 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4813 {
4814 if (!HASHITEM_EMPTY(hi))
4815 {
4816 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004817 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004818 if (first)
4819 {
4820 n = i;
4821 first = FALSE;
4822 }
4823 else if (domax ? i > n : i < n)
4824 n = i;
4825 }
4826 }
4827 }
4828 }
4829 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004830 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004831 rettv->vval.v_number = error ? 0 : n;
4832}
4833
4834/*
4835 * "max()" function
4836 */
4837 static void
4838f_max(typval_T *argvars, typval_T *rettv)
4839{
4840 max_min(argvars, rettv, TRUE);
4841}
4842
4843/*
4844 * "min()" function
4845 */
4846 static void
4847f_min(typval_T *argvars, typval_T *rettv)
4848{
4849 max_min(argvars, rettv, FALSE);
4850}
4851
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852#if defined(FEAT_MZSCHEME) || defined(PROTO)
4853/*
4854 * "mzeval()" function
4855 */
4856 static void
4857f_mzeval(typval_T *argvars, typval_T *rettv)
4858{
4859 char_u *str;
4860 char_u buf[NUMBUFLEN];
4861
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004862 if (check_restricted() || check_secure())
4863 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004864 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004865 do_mzeval(str, rettv);
4866}
4867
4868 void
4869mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4870{
4871 typval_T argvars[3];
4872
4873 argvars[0].v_type = VAR_STRING;
4874 argvars[0].vval.v_string = name;
4875 copy_tv(args, &argvars[1]);
4876 argvars[2].v_type = VAR_UNKNOWN;
4877 f_call(argvars, rettv);
4878 clear_tv(&argvars[1]);
4879}
4880#endif
4881
4882/*
4883 * "nextnonblank()" function
4884 */
4885 static void
4886f_nextnonblank(typval_T *argvars, typval_T *rettv)
4887{
4888 linenr_T lnum;
4889
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004890 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004891 {
4892 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
4893 {
4894 lnum = 0;
4895 break;
4896 }
4897 if (*skipwhite(ml_get(lnum)) != NUL)
4898 break;
4899 }
4900 rettv->vval.v_number = lnum;
4901}
4902
4903/*
4904 * "nr2char()" function
4905 */
4906 static void
4907f_nr2char(typval_T *argvars, typval_T *rettv)
4908{
4909 char_u buf[NUMBUFLEN];
4910
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911 if (has_mbyte)
4912 {
4913 int utf8 = 0;
4914
4915 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004916 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01004918 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004919 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004920 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004921 }
4922 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004923 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004924 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004925 buf[1] = NUL;
4926 }
4927 rettv->v_type = VAR_STRING;
4928 rettv->vval.v_string = vim_strsave(buf);
4929}
4930
4931/*
4932 * "or(expr, expr)" function
4933 */
4934 static void
4935f_or(typval_T *argvars, typval_T *rettv)
4936{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004937 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
4938 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004939}
4940
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004941#ifdef FEAT_PERL
4942/*
4943 * "perleval()" function
4944 */
4945 static void
4946f_perleval(typval_T *argvars, typval_T *rettv)
4947{
4948 char_u *str;
4949 char_u buf[NUMBUFLEN];
4950
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004951 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004952 do_perleval(str, rettv);
4953}
4954#endif
4955
4956#ifdef FEAT_FLOAT
4957/*
4958 * "pow()" function
4959 */
4960 static void
4961f_pow(typval_T *argvars, typval_T *rettv)
4962{
4963 float_T fx = 0.0, fy = 0.0;
4964
4965 rettv->v_type = VAR_FLOAT;
4966 if (get_float_arg(argvars, &fx) == OK
4967 && get_float_arg(&argvars[1], &fy) == OK)
4968 rettv->vval.v_float = pow(fx, fy);
4969 else
4970 rettv->vval.v_float = 0.0;
4971}
4972#endif
4973
4974/*
4975 * "prevnonblank()" function
4976 */
4977 static void
4978f_prevnonblank(typval_T *argvars, typval_T *rettv)
4979{
4980 linenr_T lnum;
4981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004982 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004983 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
4984 lnum = 0;
4985 else
4986 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
4987 --lnum;
4988 rettv->vval.v_number = lnum;
4989}
4990
4991/* This dummy va_list is here because:
4992 * - passing a NULL pointer doesn't work when va_list isn't a pointer
4993 * - locally in the function results in a "used before set" warning
4994 * - using va_start() to initialize it gives "function with fixed args" error */
4995static va_list ap;
4996
4997/*
4998 * "printf()" function
4999 */
5000 static void
5001f_printf(typval_T *argvars, typval_T *rettv)
5002{
5003 char_u buf[NUMBUFLEN];
5004 int len;
5005 char_u *s;
5006 int saved_did_emsg = did_emsg;
5007 char *fmt;
5008
5009 rettv->v_type = VAR_STRING;
5010 rettv->vval.v_string = NULL;
5011
5012 /* Get the required length, allocate the buffer and do it for real. */
5013 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005014 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005015 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005016 if (!did_emsg)
5017 {
5018 s = alloc(len + 1);
5019 if (s != NULL)
5020 {
5021 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005022 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5023 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005024 }
5025 }
5026 did_emsg |= saved_did_emsg;
5027}
5028
5029/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005030 * "pum_getpos()" function
5031 */
5032 static void
5033f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5034{
5035 if (rettv_dict_alloc(rettv) != OK)
5036 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005037 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005038}
5039
5040/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005041 * "pumvisible()" function
5042 */
5043 static void
5044f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5045{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005046 if (pum_visible())
5047 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005048}
5049
5050#ifdef FEAT_PYTHON3
5051/*
5052 * "py3eval()" function
5053 */
5054 static void
5055f_py3eval(typval_T *argvars, typval_T *rettv)
5056{
5057 char_u *str;
5058 char_u buf[NUMBUFLEN];
5059
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005060 if (check_restricted() || check_secure())
5061 return;
5062
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005063 if (p_pyx == 0)
5064 p_pyx = 3;
5065
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005066 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005067 do_py3eval(str, rettv);
5068}
5069#endif
5070
5071#ifdef FEAT_PYTHON
5072/*
5073 * "pyeval()" function
5074 */
5075 static void
5076f_pyeval(typval_T *argvars, typval_T *rettv)
5077{
5078 char_u *str;
5079 char_u buf[NUMBUFLEN];
5080
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005081 if (check_restricted() || check_secure())
5082 return;
5083
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005084 if (p_pyx == 0)
5085 p_pyx = 2;
5086
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005087 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005088 do_pyeval(str, rettv);
5089}
5090#endif
5091
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005092#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5093/*
5094 * "pyxeval()" function
5095 */
5096 static void
5097f_pyxeval(typval_T *argvars, typval_T *rettv)
5098{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005099 if (check_restricted() || check_secure())
5100 return;
5101
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005102# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5103 init_pyxversion();
5104 if (p_pyx == 2)
5105 f_pyeval(argvars, rettv);
5106 else
5107 f_py3eval(argvars, rettv);
5108# elif defined(FEAT_PYTHON)
5109 f_pyeval(argvars, rettv);
5110# elif defined(FEAT_PYTHON3)
5111 f_py3eval(argvars, rettv);
5112# endif
5113}
5114#endif
5115
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005116/*
5117 * "range()" function
5118 */
5119 static void
5120f_range(typval_T *argvars, typval_T *rettv)
5121{
5122 varnumber_T start;
5123 varnumber_T end;
5124 varnumber_T stride = 1;
5125 varnumber_T i;
5126 int error = FALSE;
5127
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005128 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005129 if (argvars[1].v_type == VAR_UNKNOWN)
5130 {
5131 end = start - 1;
5132 start = 0;
5133 }
5134 else
5135 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005136 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005138 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005139 }
5140
5141 if (error)
5142 return; /* type error; errmsg already given */
5143 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005144 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005146 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005147 else
5148 {
5149 if (rettv_list_alloc(rettv) == OK)
5150 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5151 if (list_append_number(rettv->vval.v_list,
5152 (varnumber_T)i) == FAIL)
5153 break;
5154 }
5155}
5156
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005157 static void
5158return_register(int regname, typval_T *rettv)
5159{
5160 char_u buf[2] = {0, 0};
5161
5162 buf[0] = (char_u)regname;
5163 rettv->v_type = VAR_STRING;
5164 rettv->vval.v_string = vim_strsave(buf);
5165}
5166
5167/*
5168 * "reg_executing()" function
5169 */
5170 static void
5171f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5172{
5173 return_register(reg_executing, rettv);
5174}
5175
5176/*
5177 * "reg_recording()" function
5178 */
5179 static void
5180f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5181{
5182 return_register(reg_recording, rettv);
5183}
5184
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005185#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005186/*
5187 * Convert a List to proftime_T.
5188 * Return FAIL when there is something wrong.
5189 */
5190 static int
5191list2proftime(typval_T *arg, proftime_T *tm)
5192{
5193 long n1, n2;
5194 int error = FALSE;
5195
5196 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5197 || arg->vval.v_list->lv_len != 2)
5198 return FAIL;
5199 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5200 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005201# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005202 tm->HighPart = n1;
5203 tm->LowPart = n2;
5204# else
5205 tm->tv_sec = n1;
5206 tm->tv_usec = n2;
5207# endif
5208 return error ? FAIL : OK;
5209}
5210#endif /* FEAT_RELTIME */
5211
5212/*
5213 * "reltime()" function
5214 */
5215 static void
5216f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5217{
5218#ifdef FEAT_RELTIME
5219 proftime_T res;
5220 proftime_T start;
5221
5222 if (argvars[0].v_type == VAR_UNKNOWN)
5223 {
5224 /* No arguments: get current time. */
5225 profile_start(&res);
5226 }
5227 else if (argvars[1].v_type == VAR_UNKNOWN)
5228 {
5229 if (list2proftime(&argvars[0], &res) == FAIL)
5230 return;
5231 profile_end(&res);
5232 }
5233 else
5234 {
5235 /* Two arguments: compute the difference. */
5236 if (list2proftime(&argvars[0], &start) == FAIL
5237 || list2proftime(&argvars[1], &res) == FAIL)
5238 return;
5239 profile_sub(&res, &start);
5240 }
5241
5242 if (rettv_list_alloc(rettv) == OK)
5243 {
5244 long n1, n2;
5245
Bram Moolenaar4f974752019-02-17 17:44:42 +01005246# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005247 n1 = res.HighPart;
5248 n2 = res.LowPart;
5249# else
5250 n1 = res.tv_sec;
5251 n2 = res.tv_usec;
5252# endif
5253 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5254 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5255 }
5256#endif
5257}
5258
5259#ifdef FEAT_FLOAT
5260/*
5261 * "reltimefloat()" function
5262 */
5263 static void
5264f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5265{
5266# ifdef FEAT_RELTIME
5267 proftime_T tm;
5268# endif
5269
5270 rettv->v_type = VAR_FLOAT;
5271 rettv->vval.v_float = 0;
5272# ifdef FEAT_RELTIME
5273 if (list2proftime(&argvars[0], &tm) == OK)
5274 rettv->vval.v_float = profile_float(&tm);
5275# endif
5276}
5277#endif
5278
5279/*
5280 * "reltimestr()" function
5281 */
5282 static void
5283f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5284{
5285#ifdef FEAT_RELTIME
5286 proftime_T tm;
5287#endif
5288
5289 rettv->v_type = VAR_STRING;
5290 rettv->vval.v_string = NULL;
5291#ifdef FEAT_RELTIME
5292 if (list2proftime(&argvars[0], &tm) == OK)
5293 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5294#endif
5295}
5296
5297#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 static void
5299make_connection(void)
5300{
5301 if (X_DISPLAY == NULL
5302# ifdef FEAT_GUI
5303 && !gui.in_use
5304# endif
5305 )
5306 {
5307 x_force_connect = TRUE;
5308 setup_term_clip();
5309 x_force_connect = FALSE;
5310 }
5311}
5312
5313 static int
5314check_connection(void)
5315{
5316 make_connection();
5317 if (X_DISPLAY == NULL)
5318 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005319 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005320 return FAIL;
5321 }
5322 return OK;
5323}
5324#endif
5325
5326#ifdef FEAT_CLIENTSERVER
5327 static void
5328remote_common(typval_T *argvars, typval_T *rettv, int expr)
5329{
5330 char_u *server_name;
5331 char_u *keys;
5332 char_u *r = NULL;
5333 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005334 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005335# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005336 HWND w;
5337# else
5338 Window w;
5339# endif
5340
5341 if (check_restricted() || check_secure())
5342 return;
5343
5344# ifdef FEAT_X11
5345 if (check_connection() == FAIL)
5346 return;
5347# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005348 if (argvars[2].v_type != VAR_UNKNOWN
5349 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005350 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005351
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005352 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005353 if (server_name == NULL)
5354 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005355 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005356# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005357 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005358# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005359 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5360 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005361# endif
5362 {
5363 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005364 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005365 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005366 vim_free(r);
5367 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005368 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005369 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005370 return;
5371 }
5372
5373 rettv->vval.v_string = r;
5374
5375 if (argvars[2].v_type != VAR_UNKNOWN)
5376 {
5377 dictitem_T v;
5378 char_u str[30];
5379 char_u *idvar;
5380
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005381 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005382 if (idvar != NULL && *idvar != NUL)
5383 {
5384 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5385 v.di_tv.v_type = VAR_STRING;
5386 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005387 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005388 vim_free(v.di_tv.vval.v_string);
5389 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005390 }
5391}
5392#endif
5393
5394/*
5395 * "remote_expr()" function
5396 */
5397 static void
5398f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5399{
5400 rettv->v_type = VAR_STRING;
5401 rettv->vval.v_string = NULL;
5402#ifdef FEAT_CLIENTSERVER
5403 remote_common(argvars, rettv, TRUE);
5404#endif
5405}
5406
5407/*
5408 * "remote_foreground()" function
5409 */
5410 static void
5411f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5412{
5413#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005414# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005415 /* On Win32 it's done in this application. */
5416 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005417 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005418
5419 if (server_name != NULL)
5420 serverForeground(server_name);
5421 }
5422# else
5423 /* Send a foreground() expression to the server. */
5424 argvars[1].v_type = VAR_STRING;
5425 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5426 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005427 rettv->v_type = VAR_STRING;
5428 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005429 remote_common(argvars, rettv, TRUE);
5430 vim_free(argvars[1].vval.v_string);
5431# endif
5432#endif
5433}
5434
5435 static void
5436f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5437{
5438#ifdef FEAT_CLIENTSERVER
5439 dictitem_T v;
5440 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005441# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005442 long_u n = 0;
5443# endif
5444 char_u *serverid;
5445
5446 if (check_restricted() || check_secure())
5447 {
5448 rettv->vval.v_number = -1;
5449 return;
5450 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005451 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005452 if (serverid == NULL)
5453 {
5454 rettv->vval.v_number = -1;
5455 return; /* type error; errmsg already given */
5456 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005457# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005458 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5459 if (n == 0)
5460 rettv->vval.v_number = -1;
5461 else
5462 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005463 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005464 rettv->vval.v_number = (s != NULL);
5465 }
5466# else
5467 if (check_connection() == FAIL)
5468 return;
5469
5470 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5471 serverStrToWin(serverid), &s);
5472# endif
5473
5474 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5475 {
5476 char_u *retvar;
5477
5478 v.di_tv.v_type = VAR_STRING;
5479 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005480 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005481 if (retvar != NULL)
5482 set_var(retvar, &v.di_tv, FALSE);
5483 vim_free(v.di_tv.vval.v_string);
5484 }
5485#else
5486 rettv->vval.v_number = -1;
5487#endif
5488}
5489
5490 static void
5491f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5492{
5493 char_u *r = NULL;
5494
5495#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005496 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005497
5498 if (serverid != NULL && !check_restricted() && !check_secure())
5499 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005500 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005501# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005502 /* The server's HWND is encoded in the 'id' parameter */
5503 long_u n = 0;
5504# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005505
5506 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005507 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005508
Bram Moolenaar4f974752019-02-17 17:44:42 +01005509# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005510 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5511 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005512 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005513 if (r == NULL)
5514# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005515 if (check_connection() == FAIL
5516 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5517 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005518# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005519 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005520 }
5521#endif
5522 rettv->v_type = VAR_STRING;
5523 rettv->vval.v_string = r;
5524}
5525
5526/*
5527 * "remote_send()" function
5528 */
5529 static void
5530f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5531{
5532 rettv->v_type = VAR_STRING;
5533 rettv->vval.v_string = NULL;
5534#ifdef FEAT_CLIENTSERVER
5535 remote_common(argvars, rettv, FALSE);
5536#endif
5537}
5538
5539/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005540 * "remote_startserver()" function
5541 */
5542 static void
5543f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5544{
5545#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005546 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005547
5548 if (server == NULL)
5549 return; /* type error; errmsg already given */
5550 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005551 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005552 else
5553 {
5554# ifdef FEAT_X11
5555 if (check_connection() == OK)
5556 serverRegisterName(X_DISPLAY, server);
5557# else
5558 serverSetName(server);
5559# endif
5560 }
5561#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005562 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005563#endif
5564}
5565
5566/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005567 * "rename({from}, {to})" function
5568 */
5569 static void
5570f_rename(typval_T *argvars, typval_T *rettv)
5571{
5572 char_u buf[NUMBUFLEN];
5573
5574 if (check_restricted() || check_secure())
5575 rettv->vval.v_number = -1;
5576 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005577 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5578 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005579}
5580
5581/*
5582 * "repeat()" function
5583 */
5584 static void
5585f_repeat(typval_T *argvars, typval_T *rettv)
5586{
5587 char_u *p;
5588 int n;
5589 int slen;
5590 int len;
5591 char_u *r;
5592 int i;
5593
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005594 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005595 if (argvars[0].v_type == VAR_LIST)
5596 {
5597 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5598 while (n-- > 0)
5599 if (list_extend(rettv->vval.v_list,
5600 argvars[0].vval.v_list, NULL) == FAIL)
5601 break;
5602 }
5603 else
5604 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005605 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005606 rettv->v_type = VAR_STRING;
5607 rettv->vval.v_string = NULL;
5608
5609 slen = (int)STRLEN(p);
5610 len = slen * n;
5611 if (len <= 0)
5612 return;
5613
5614 r = alloc(len + 1);
5615 if (r != NULL)
5616 {
5617 for (i = 0; i < n; i++)
5618 mch_memmove(r + i * slen, p, (size_t)slen);
5619 r[len] = NUL;
5620 }
5621
5622 rettv->vval.v_string = r;
5623 }
5624}
5625
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005626#define SP_NOMOVE 0x01 /* don't move cursor */
5627#define SP_REPEAT 0x02 /* repeat to find outer pair */
5628#define SP_RETCOUNT 0x04 /* return matchcount */
5629#define SP_SETPCMARK 0x08 /* set previous context mark */
5630#define SP_START 0x10 /* accept match at start position */
5631#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5632#define SP_END 0x40 /* leave cursor at end of match */
5633#define SP_COLUMN 0x80 /* start at cursor column */
5634
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005635/*
5636 * Get flags for a search function.
5637 * Possibly sets "p_ws".
5638 * Returns BACKWARD, FORWARD or zero (for an error).
5639 */
5640 static int
5641get_search_arg(typval_T *varp, int *flagsp)
5642{
5643 int dir = FORWARD;
5644 char_u *flags;
5645 char_u nbuf[NUMBUFLEN];
5646 int mask;
5647
5648 if (varp->v_type != VAR_UNKNOWN)
5649 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005650 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005651 if (flags == NULL)
5652 return 0; /* type error; errmsg already given */
5653 while (*flags != NUL)
5654 {
5655 switch (*flags)
5656 {
5657 case 'b': dir = BACKWARD; break;
5658 case 'w': p_ws = TRUE; break;
5659 case 'W': p_ws = FALSE; break;
5660 default: mask = 0;
5661 if (flagsp != NULL)
5662 switch (*flags)
5663 {
5664 case 'c': mask = SP_START; break;
5665 case 'e': mask = SP_END; break;
5666 case 'm': mask = SP_RETCOUNT; break;
5667 case 'n': mask = SP_NOMOVE; break;
5668 case 'p': mask = SP_SUBPAT; break;
5669 case 'r': mask = SP_REPEAT; break;
5670 case 's': mask = SP_SETPCMARK; break;
5671 case 'z': mask = SP_COLUMN; break;
5672 }
5673 if (mask == 0)
5674 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005675 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005676 dir = 0;
5677 }
5678 else
5679 *flagsp |= mask;
5680 }
5681 if (dir == 0)
5682 break;
5683 ++flags;
5684 }
5685 }
5686 return dir;
5687}
5688
5689/*
5690 * Shared by search() and searchpos() functions.
5691 */
5692 static int
5693search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5694{
5695 int flags;
5696 char_u *pat;
5697 pos_T pos;
5698 pos_T save_cursor;
5699 int save_p_ws = p_ws;
5700 int dir;
5701 int retval = 0; /* default: FAIL */
5702 long lnum_stop = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005703#ifdef FEAT_RELTIME
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005704 proftime_T tm;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005705 long time_limit = 0;
5706#endif
5707 int options = SEARCH_KEEP;
5708 int subpatnum;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005709 searchit_arg_T sia;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005710
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005711 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005712 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5713 if (dir == 0)
5714 goto theend;
5715 flags = *flagsp;
5716 if (flags & SP_START)
5717 options |= SEARCH_START;
5718 if (flags & SP_END)
5719 options |= SEARCH_END;
5720 if (flags & SP_COLUMN)
5721 options |= SEARCH_COL;
5722
5723 /* Optional arguments: line number to stop searching and timeout. */
5724 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5725 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005726 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005727 if (lnum_stop < 0)
5728 goto theend;
5729#ifdef FEAT_RELTIME
5730 if (argvars[3].v_type != VAR_UNKNOWN)
5731 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005732 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005733 if (time_limit < 0)
5734 goto theend;
5735 }
5736#endif
5737 }
5738
5739#ifdef FEAT_RELTIME
5740 /* Set the time limit, if there is one. */
5741 profile_setlimit(time_limit, &tm);
5742#endif
5743
5744 /*
5745 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5746 * Check to make sure only those flags are set.
5747 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5748 * flags cannot be set. Check for that condition also.
5749 */
5750 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5751 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5752 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005753 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005754 goto theend;
5755 }
5756
5757 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005758 vim_memset(&sia, 0, sizeof(sia));
5759 sia.sa_stop_lnum = (linenr_T)lnum_stop;
5760#ifdef FEAT_RELTIME
5761 sia.sa_tm = &tm;
5762#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005763 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02005764 options, RE_SEARCH, &sia);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005765 if (subpatnum != FAIL)
5766 {
5767 if (flags & SP_SUBPAT)
5768 retval = subpatnum;
5769 else
5770 retval = pos.lnum;
5771 if (flags & SP_SETPCMARK)
5772 setpcmark();
5773 curwin->w_cursor = pos;
5774 if (match_pos != NULL)
5775 {
5776 /* Store the match cursor position */
5777 match_pos->lnum = pos.lnum;
5778 match_pos->col = pos.col + 1;
5779 }
5780 /* "/$" will put the cursor after the end of the line, may need to
5781 * correct that here */
5782 check_cursor();
5783 }
5784
5785 /* If 'n' flag is used: restore cursor position. */
5786 if (flags & SP_NOMOVE)
5787 curwin->w_cursor = save_cursor;
5788 else
5789 curwin->w_set_curswant = TRUE;
5790theend:
5791 p_ws = save_p_ws;
5792
5793 return retval;
5794}
5795
5796#ifdef FEAT_FLOAT
5797
5798/*
5799 * round() is not in C90, use ceil() or floor() instead.
5800 */
5801 float_T
5802vim_round(float_T f)
5803{
5804 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
5805}
5806
5807/*
5808 * "round({float})" function
5809 */
5810 static void
5811f_round(typval_T *argvars, typval_T *rettv)
5812{
5813 float_T f = 0.0;
5814
5815 rettv->v_type = VAR_FLOAT;
5816 if (get_float_arg(argvars, &f) == OK)
5817 rettv->vval.v_float = vim_round(f);
5818 else
5819 rettv->vval.v_float = 0.0;
5820}
5821#endif
5822
Bram Moolenaare99be0e2019-03-26 22:51:09 +01005823#ifdef FEAT_RUBY
5824/*
5825 * "rubyeval()" function
5826 */
5827 static void
5828f_rubyeval(typval_T *argvars, typval_T *rettv)
5829{
5830 char_u *str;
5831 char_u buf[NUMBUFLEN];
5832
5833 str = tv_get_string_buf(&argvars[0], buf);
5834 do_rubyeval(str, rettv);
5835}
5836#endif
5837
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005838/*
5839 * "screenattr()" function
5840 */
5841 static void
5842f_screenattr(typval_T *argvars, typval_T *rettv)
5843{
5844 int row;
5845 int col;
5846 int c;
5847
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005848 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5849 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005850 if (row < 0 || row >= screen_Rows
5851 || col < 0 || col >= screen_Columns)
5852 c = -1;
5853 else
5854 c = ScreenAttrs[LineOffset[row] + col];
5855 rettv->vval.v_number = c;
5856}
5857
5858/*
5859 * "screenchar()" function
5860 */
5861 static void
5862f_screenchar(typval_T *argvars, typval_T *rettv)
5863{
5864 int row;
5865 int col;
5866 int off;
5867 int c;
5868
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005869 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5870 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005871 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005872 c = -1;
5873 else
5874 {
5875 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005876 if (enc_utf8 && ScreenLinesUC[off] != 0)
5877 c = ScreenLinesUC[off];
5878 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005879 c = ScreenLines[off];
5880 }
5881 rettv->vval.v_number = c;
5882}
5883
5884/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005885 * "screenchars()" function
5886 */
5887 static void
5888f_screenchars(typval_T *argvars, typval_T *rettv)
5889{
5890 int row;
5891 int col;
5892 int off;
5893 int c;
5894 int i;
5895
5896 if (rettv_list_alloc(rettv) == FAIL)
5897 return;
5898 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5899 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5900 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5901 return;
5902
5903 off = LineOffset[row] + col;
5904 if (enc_utf8 && ScreenLinesUC[off] != 0)
5905 c = ScreenLinesUC[off];
5906 else
5907 c = ScreenLines[off];
5908 list_append_number(rettv->vval.v_list, (varnumber_T)c);
5909
5910 if (enc_utf8)
5911
5912 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
5913 list_append_number(rettv->vval.v_list,
5914 (varnumber_T)ScreenLinesC[i][off]);
5915}
5916
5917/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005918 * "screencol()" function
5919 *
5920 * First column is 1 to be consistent with virtcol().
5921 */
5922 static void
5923f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
5924{
5925 rettv->vval.v_number = screen_screencol() + 1;
5926}
5927
5928/*
5929 * "screenrow()" function
5930 */
5931 static void
5932f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
5933{
5934 rettv->vval.v_number = screen_screenrow() + 1;
5935}
5936
5937/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005938 * "screenstring()" function
5939 */
5940 static void
5941f_screenstring(typval_T *argvars, typval_T *rettv)
5942{
5943 int row;
5944 int col;
5945 int off;
5946 int c;
5947 int i;
5948 char_u buf[MB_MAXBYTES + 1];
5949 int buflen = 0;
5950
5951 rettv->vval.v_string = NULL;
5952 rettv->v_type = VAR_STRING;
5953
5954 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5955 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5956 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5957 return;
5958
5959 off = LineOffset[row] + col;
5960 if (enc_utf8 && ScreenLinesUC[off] != 0)
5961 c = ScreenLinesUC[off];
5962 else
5963 c = ScreenLines[off];
5964 buflen += mb_char2bytes(c, buf);
5965
5966 if (enc_utf8)
5967 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
5968 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
5969
5970 buf[buflen] = NUL;
5971 rettv->vval.v_string = vim_strsave(buf);
5972}
5973
5974/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005975 * "search()" function
5976 */
5977 static void
5978f_search(typval_T *argvars, typval_T *rettv)
5979{
5980 int flags = 0;
5981
5982 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
5983}
5984
5985/*
5986 * "searchdecl()" function
5987 */
5988 static void
5989f_searchdecl(typval_T *argvars, typval_T *rettv)
5990{
5991 int locally = 1;
5992 int thisblock = 0;
5993 int error = FALSE;
5994 char_u *name;
5995
5996 rettv->vval.v_number = 1; /* default: FAIL */
5997
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005998 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005999 if (argvars[1].v_type != VAR_UNKNOWN)
6000 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006001 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006002 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006003 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006004 }
6005 if (!error && name != NULL)
6006 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6007 locally, thisblock, SEARCH_KEEP) == FAIL;
6008}
6009
6010/*
6011 * Used by searchpair() and searchpairpos()
6012 */
6013 static int
6014searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6015{
6016 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006017 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 int save_p_ws = p_ws;
6019 int dir;
6020 int flags = 0;
6021 char_u nbuf1[NUMBUFLEN];
6022 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 int retval = 0; /* default: FAIL */
6024 long lnum_stop = 0;
6025 long time_limit = 0;
6026
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006027 /* Get the three pattern arguments: start, middle, end. Will result in an
6028 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006029 spat = tv_get_string_chk(&argvars[0]);
6030 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6031 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006032 if (spat == NULL || mpat == NULL || epat == NULL)
6033 goto theend; /* type error */
6034
6035 /* Handle the optional fourth argument: flags */
6036 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6037 if (dir == 0)
6038 goto theend;
6039
6040 /* Don't accept SP_END or SP_SUBPAT.
6041 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6042 */
6043 if ((flags & (SP_END | SP_SUBPAT)) != 0
6044 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6045 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006046 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006047 goto theend;
6048 }
6049
6050 /* Using 'r' implies 'W', otherwise it doesn't work. */
6051 if (flags & SP_REPEAT)
6052 p_ws = FALSE;
6053
6054 /* Optional fifth argument: skip expression */
6055 if (argvars[3].v_type == VAR_UNKNOWN
6056 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006057 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006058 else
6059 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006060 skip = &argvars[4];
6061 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6062 && skip->v_type != VAR_STRING)
6063 {
6064 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006065 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006066 goto theend;
6067 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006068 if (argvars[5].v_type != VAR_UNKNOWN)
6069 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006070 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006071 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006072 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006073 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006074 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006075 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006076#ifdef FEAT_RELTIME
6077 if (argvars[6].v_type != VAR_UNKNOWN)
6078 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006079 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006080 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006081 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006082 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006084 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006085 }
6086#endif
6087 }
6088 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006089
6090 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6091 match_pos, lnum_stop, time_limit);
6092
6093theend:
6094 p_ws = save_p_ws;
6095
6096 return retval;
6097}
6098
6099/*
6100 * "searchpair()" function
6101 */
6102 static void
6103f_searchpair(typval_T *argvars, typval_T *rettv)
6104{
6105 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6106}
6107
6108/*
6109 * "searchpairpos()" function
6110 */
6111 static void
6112f_searchpairpos(typval_T *argvars, typval_T *rettv)
6113{
6114 pos_T match_pos;
6115 int lnum = 0;
6116 int col = 0;
6117
6118 if (rettv_list_alloc(rettv) == FAIL)
6119 return;
6120
6121 if (searchpair_cmn(argvars, &match_pos) > 0)
6122 {
6123 lnum = match_pos.lnum;
6124 col = match_pos.col;
6125 }
6126
6127 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6128 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6129}
6130
6131/*
6132 * Search for a start/middle/end thing.
6133 * Used by searchpair(), see its documentation for the details.
6134 * Returns 0 or -1 for no match,
6135 */
6136 long
6137do_searchpair(
6138 char_u *spat, /* start pattern */
6139 char_u *mpat, /* middle pattern */
6140 char_u *epat, /* end pattern */
6141 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006142 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143 int flags, /* SP_SETPCMARK and other SP_ values */
6144 pos_T *match_pos,
6145 linenr_T lnum_stop, /* stop at this line if not zero */
6146 long time_limit UNUSED) /* stop after this many msec */
6147{
6148 char_u *save_cpo;
6149 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6150 long retval = 0;
6151 pos_T pos;
6152 pos_T firstpos;
6153 pos_T foundpos;
6154 pos_T save_cursor;
6155 pos_T save_pos;
6156 int n;
6157 int r;
6158 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006159 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006160 int err;
6161 int options = SEARCH_KEEP;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006162#ifdef FEAT_RELTIME
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006163 proftime_T tm;
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006164#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006165
6166 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6167 save_cpo = p_cpo;
6168 p_cpo = empty_option;
6169
6170#ifdef FEAT_RELTIME
6171 /* Set the time limit, if there is one. */
6172 profile_setlimit(time_limit, &tm);
6173#endif
6174
6175 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6176 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006177 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6178 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006179 if (pat2 == NULL || pat3 == NULL)
6180 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006181 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006182 if (*mpat == NUL)
6183 STRCPY(pat3, pat2);
6184 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006185 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186 spat, epat, mpat);
6187 if (flags & SP_START)
6188 options |= SEARCH_START;
6189
Bram Moolenaar48570482017-10-30 21:48:41 +01006190 if (skip != NULL)
6191 {
6192 /* Empty string means to not use the skip expression. */
6193 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6194 use_skip = skip->vval.v_string != NULL
6195 && *skip->vval.v_string != NUL;
6196 }
6197
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006198 save_cursor = curwin->w_cursor;
6199 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006200 CLEAR_POS(&firstpos);
6201 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006202 pat = pat3;
6203 for (;;)
6204 {
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006205 searchit_arg_T sia;
6206
6207 vim_memset(&sia, 0, sizeof(sia));
6208 sia.sa_stop_lnum = lnum_stop;
6209#ifdef FEAT_RELTIME
6210 sia.sa_tm = &tm;
6211#endif
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006212 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaar92ea26b2019-10-18 20:53:34 +02006213 options, RE_SEARCH, &sia);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006214 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215 /* didn't find it or found the first match again: FAIL */
6216 break;
6217
6218 if (firstpos.lnum == 0)
6219 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006220 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006221 {
6222 /* Found the same position again. Can happen with a pattern that
6223 * has "\zs" at the end and searching backwards. Advance one
6224 * character and try again. */
6225 if (dir == BACKWARD)
6226 decl(&pos);
6227 else
6228 incl(&pos);
6229 }
6230 foundpos = pos;
6231
6232 /* clear the start flag to avoid getting stuck here */
6233 options &= ~SEARCH_START;
6234
6235 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006236 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006237 {
6238 save_pos = curwin->w_cursor;
6239 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006240 err = FALSE;
6241 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006242 curwin->w_cursor = save_pos;
6243 if (err)
6244 {
6245 /* Evaluating {skip} caused an error, break here. */
6246 curwin->w_cursor = save_cursor;
6247 retval = -1;
6248 break;
6249 }
6250 if (r)
6251 continue;
6252 }
6253
6254 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6255 {
6256 /* Found end when searching backwards or start when searching
6257 * forward: nested pair. */
6258 ++nest;
6259 pat = pat2; /* nested, don't search for middle */
6260 }
6261 else
6262 {
6263 /* Found end when searching forward or start when searching
6264 * backward: end of (nested) pair; or found middle in outer pair. */
6265 if (--nest == 1)
6266 pat = pat3; /* outer level, search for middle */
6267 }
6268
6269 if (nest == 0)
6270 {
6271 /* Found the match: return matchcount or line number. */
6272 if (flags & SP_RETCOUNT)
6273 ++retval;
6274 else
6275 retval = pos.lnum;
6276 if (flags & SP_SETPCMARK)
6277 setpcmark();
6278 curwin->w_cursor = pos;
6279 if (!(flags & SP_REPEAT))
6280 break;
6281 nest = 1; /* search for next unmatched */
6282 }
6283 }
6284
6285 if (match_pos != NULL)
6286 {
6287 /* Store the match cursor position */
6288 match_pos->lnum = curwin->w_cursor.lnum;
6289 match_pos->col = curwin->w_cursor.col + 1;
6290 }
6291
6292 /* If 'n' flag is used or search failed: restore cursor position. */
6293 if ((flags & SP_NOMOVE) || retval == 0)
6294 curwin->w_cursor = save_cursor;
6295
6296theend:
6297 vim_free(pat2);
6298 vim_free(pat3);
6299 if (p_cpo == empty_option)
6300 p_cpo = save_cpo;
6301 else
6302 /* Darn, evaluating the {skip} expression changed the value. */
6303 free_string_option(save_cpo);
6304
6305 return retval;
6306}
6307
6308/*
6309 * "searchpos()" function
6310 */
6311 static void
6312f_searchpos(typval_T *argvars, typval_T *rettv)
6313{
6314 pos_T match_pos;
6315 int lnum = 0;
6316 int col = 0;
6317 int n;
6318 int flags = 0;
6319
6320 if (rettv_list_alloc(rettv) == FAIL)
6321 return;
6322
6323 n = search_cmn(argvars, &match_pos, &flags);
6324 if (n > 0)
6325 {
6326 lnum = match_pos.lnum;
6327 col = match_pos.col;
6328 }
6329
6330 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6331 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6332 if (flags & SP_SUBPAT)
6333 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6334}
6335
6336 static void
6337f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6338{
6339#ifdef FEAT_CLIENTSERVER
6340 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006341 char_u *server = tv_get_string_chk(&argvars[0]);
6342 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343
6344 rettv->vval.v_number = -1;
6345 if (server == NULL || reply == NULL)
6346 return;
6347 if (check_restricted() || check_secure())
6348 return;
6349# ifdef FEAT_X11
6350 if (check_connection() == FAIL)
6351 return;
6352# endif
6353
6354 if (serverSendReply(server, reply) < 0)
6355 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006356 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006357 return;
6358 }
6359 rettv->vval.v_number = 0;
6360#else
6361 rettv->vval.v_number = -1;
6362#endif
6363}
6364
6365 static void
6366f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6367{
6368 char_u *r = NULL;
6369
6370#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006371# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006372 r = serverGetVimNames();
6373# else
6374 make_connection();
6375 if (X_DISPLAY != NULL)
6376 r = serverGetVimNames(X_DISPLAY);
6377# endif
6378#endif
6379 rettv->v_type = VAR_STRING;
6380 rettv->vval.v_string = r;
6381}
6382
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006383 static void
6384f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6385{
6386 dict_T *d;
6387 dictitem_T *di;
6388 char_u *csearch;
6389
6390 if (argvars[0].v_type != VAR_DICT)
6391 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006392 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393 return;
6394 }
6395
6396 if ((d = argvars[0].vval.v_dict) != NULL)
6397 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006398 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006399 if (csearch != NULL)
6400 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006401 if (enc_utf8)
6402 {
6403 int pcc[MAX_MCO];
6404 int c = utfc_ptr2char(csearch, pcc);
6405
6406 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6407 }
6408 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006409 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006410 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006411 }
6412
6413 di = dict_find(d, (char_u *)"forward", -1);
6414 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006415 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 ? FORWARD : BACKWARD);
6417
6418 di = dict_find(d, (char_u *)"until", -1);
6419 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006420 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421 }
6422}
6423
6424/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006425 * "setenv()" function
6426 */
6427 static void
6428f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6429{
6430 char_u namebuf[NUMBUFLEN];
6431 char_u valbuf[NUMBUFLEN];
6432 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6433
6434 if (argvars[1].v_type == VAR_SPECIAL
6435 && argvars[1].vval.v_number == VVAL_NULL)
6436 vim_unsetenv(name);
6437 else
6438 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6439}
6440
6441/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442 * "setfperm({fname}, {mode})" function
6443 */
6444 static void
6445f_setfperm(typval_T *argvars, typval_T *rettv)
6446{
6447 char_u *fname;
6448 char_u modebuf[NUMBUFLEN];
6449 char_u *mode_str;
6450 int i;
6451 int mask;
6452 int mode = 0;
6453
6454 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006455 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006456 if (fname == NULL)
6457 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006458 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006459 if (mode_str == NULL)
6460 return;
6461 if (STRLEN(mode_str) != 9)
6462 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006463 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006464 return;
6465 }
6466
6467 mask = 1;
6468 for (i = 8; i >= 0; --i)
6469 {
6470 if (mode_str[i] != '-')
6471 mode |= mask;
6472 mask = mask << 1;
6473 }
6474 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6475}
6476
6477/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006478 * "setpos()" function
6479 */
6480 static void
6481f_setpos(typval_T *argvars, typval_T *rettv)
6482{
6483 pos_T pos;
6484 int fnum;
6485 char_u *name;
6486 colnr_T curswant = -1;
6487
6488 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006489 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006490 if (name != NULL)
6491 {
6492 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6493 {
6494 if (--pos.col < 0)
6495 pos.col = 0;
6496 if (name[0] == '.' && name[1] == NUL)
6497 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006498 /* set cursor; "fnum" is ignored */
6499 curwin->w_cursor = pos;
6500 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006502 curwin->w_curswant = curswant - 1;
6503 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006505 check_cursor();
6506 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507 }
6508 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6509 {
6510 /* set mark */
6511 if (setmark_pos(name[1], &pos, fnum) == OK)
6512 rettv->vval.v_number = 0;
6513 }
6514 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006515 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006516 }
6517 }
6518}
6519
6520/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006521 * "setreg()" function
6522 */
6523 static void
6524f_setreg(typval_T *argvars, typval_T *rettv)
6525{
6526 int regname;
6527 char_u *strregname;
6528 char_u *stropt;
6529 char_u *strval;
6530 int append;
6531 char_u yank_type;
6532 long block_len;
6533
6534 block_len = -1;
6535 yank_type = MAUTO;
6536 append = FALSE;
6537
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006538 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 rettv->vval.v_number = 1; /* FAIL is default */
6540
6541 if (strregname == NULL)
6542 return; /* type error; errmsg already given */
6543 regname = *strregname;
6544 if (regname == 0 || regname == '@')
6545 regname = '"';
6546
6547 if (argvars[2].v_type != VAR_UNKNOWN)
6548 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006549 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 if (stropt == NULL)
6551 return; /* type error */
6552 for (; *stropt != NUL; ++stropt)
6553 switch (*stropt)
6554 {
6555 case 'a': case 'A': /* append */
6556 append = TRUE;
6557 break;
6558 case 'v': case 'c': /* character-wise selection */
6559 yank_type = MCHAR;
6560 break;
6561 case 'V': case 'l': /* line-wise selection */
6562 yank_type = MLINE;
6563 break;
6564 case 'b': case Ctrl_V: /* block-wise selection */
6565 yank_type = MBLOCK;
6566 if (VIM_ISDIGIT(stropt[1]))
6567 {
6568 ++stropt;
6569 block_len = getdigits(&stropt) - 1;
6570 --stropt;
6571 }
6572 break;
6573 }
6574 }
6575
6576 if (argvars[1].v_type == VAR_LIST)
6577 {
6578 char_u **lstval;
6579 char_u **allocval;
6580 char_u buf[NUMBUFLEN];
6581 char_u **curval;
6582 char_u **curallocval;
6583 list_T *ll = argvars[1].vval.v_list;
6584 listitem_T *li;
6585 int len;
6586
6587 /* If the list is NULL handle like an empty list. */
6588 len = ll == NULL ? 0 : ll->lv_len;
6589
6590 /* First half: use for pointers to result lines; second half: use for
6591 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006592 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006593 if (lstval == NULL)
6594 return;
6595 curval = lstval;
6596 allocval = lstval + len + 2;
6597 curallocval = allocval;
6598
6599 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6600 li = li->li_next)
6601 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006602 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006603 if (strval == NULL)
6604 goto free_lstval;
6605 if (strval == buf)
6606 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006607 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006608 * overwrite the string. */
6609 strval = vim_strsave(buf);
6610 if (strval == NULL)
6611 goto free_lstval;
6612 *curallocval++ = strval;
6613 }
6614 *curval++ = strval;
6615 }
6616 *curval++ = NULL;
6617
6618 write_reg_contents_lst(regname, lstval, -1,
6619 append, yank_type, block_len);
6620free_lstval:
6621 while (curallocval > allocval)
6622 vim_free(*--curallocval);
6623 vim_free(lstval);
6624 }
6625 else
6626 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006627 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006628 if (strval == NULL)
6629 return;
6630 write_reg_contents_ex(regname, strval, -1,
6631 append, yank_type, block_len);
6632 }
6633 rettv->vval.v_number = 0;
6634}
6635
6636/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006637 * "settagstack()" function
6638 */
6639 static void
6640f_settagstack(typval_T *argvars, typval_T *rettv)
6641{
6642 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6643 win_T *wp;
6644 dict_T *d;
6645 int action = 'r';
6646
6647 rettv->vval.v_number = -1;
6648
6649 // first argument: window number or id
6650 wp = find_win_by_nr_or_id(&argvars[0]);
6651 if (wp == NULL)
6652 return;
6653
6654 // second argument: dict with items to set in the tag stack
6655 if (argvars[1].v_type != VAR_DICT)
6656 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006657 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006658 return;
6659 }
6660 d = argvars[1].vval.v_dict;
6661 if (d == NULL)
6662 return;
6663
6664 // third argument: action - 'a' for append and 'r' for replace.
6665 // default is to replace the stack.
6666 if (argvars[2].v_type == VAR_UNKNOWN)
6667 action = 'r';
6668 else if (argvars[2].v_type == VAR_STRING)
6669 {
6670 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006671 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006672 if (actstr == NULL)
6673 return;
6674 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6675 action = *actstr;
6676 else
6677 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006678 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006679 return;
6680 }
6681 }
6682 else
6683 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006684 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006685 return;
6686 }
6687
6688 if (set_tagstack(wp, d, action) == OK)
6689 rettv->vval.v_number = 0;
6690}
6691
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006692#ifdef FEAT_CRYPT
6693/*
6694 * "sha256({string})" function
6695 */
6696 static void
6697f_sha256(typval_T *argvars, typval_T *rettv)
6698{
6699 char_u *p;
6700
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006701 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006702 rettv->vval.v_string = vim_strsave(
6703 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6704 rettv->v_type = VAR_STRING;
6705}
6706#endif /* FEAT_CRYPT */
6707
6708/*
6709 * "shellescape({string})" function
6710 */
6711 static void
6712f_shellescape(typval_T *argvars, typval_T *rettv)
6713{
Bram Moolenaar20615522017-06-05 18:46:26 +02006714 int do_special = non_zero_arg(&argvars[1]);
6715
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006716 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006717 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006718 rettv->v_type = VAR_STRING;
6719}
6720
6721/*
6722 * shiftwidth() function
6723 */
6724 static void
6725f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6726{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006727 rettv->vval.v_number = 0;
6728
6729 if (argvars[0].v_type != VAR_UNKNOWN)
6730 {
6731 long col;
6732
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006733 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006734 if (col < 0)
6735 return; // type error; errmsg already given
6736#ifdef FEAT_VARTABS
6737 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6738 return;
6739#endif
6740 }
6741
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006742 rettv->vval.v_number = get_sw_value(curbuf);
6743}
6744
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006745#ifdef FEAT_FLOAT
6746/*
6747 * "sin()" function
6748 */
6749 static void
6750f_sin(typval_T *argvars, typval_T *rettv)
6751{
6752 float_T f = 0.0;
6753
6754 rettv->v_type = VAR_FLOAT;
6755 if (get_float_arg(argvars, &f) == OK)
6756 rettv->vval.v_float = sin(f);
6757 else
6758 rettv->vval.v_float = 0.0;
6759}
6760
6761/*
6762 * "sinh()" function
6763 */
6764 static void
6765f_sinh(typval_T *argvars, typval_T *rettv)
6766{
6767 float_T f = 0.0;
6768
6769 rettv->v_type = VAR_FLOAT;
6770 if (get_float_arg(argvars, &f) == OK)
6771 rettv->vval.v_float = sinh(f);
6772 else
6773 rettv->vval.v_float = 0.0;
6774}
6775#endif
6776
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006777/*
6778 * "soundfold({word})" function
6779 */
6780 static void
6781f_soundfold(typval_T *argvars, typval_T *rettv)
6782{
6783 char_u *s;
6784
6785 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006786 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006787#ifdef FEAT_SPELL
6788 rettv->vval.v_string = eval_soundfold(s);
6789#else
6790 rettv->vval.v_string = vim_strsave(s);
6791#endif
6792}
6793
6794/*
6795 * "spellbadword()" function
6796 */
6797 static void
6798f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6799{
6800 char_u *word = (char_u *)"";
6801 hlf_T attr = HLF_COUNT;
6802 int len = 0;
6803
6804 if (rettv_list_alloc(rettv) == FAIL)
6805 return;
6806
6807#ifdef FEAT_SPELL
6808 if (argvars[0].v_type == VAR_UNKNOWN)
6809 {
6810 /* Find the start and length of the badly spelled word. */
6811 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
6812 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006813 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006814 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006815 curwin->w_set_curswant = TRUE;
6816 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006817 }
6818 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
6819 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006820 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006821 int capcol = -1;
6822
6823 if (str != NULL)
6824 {
6825 /* Check the argument for spelling. */
6826 while (*str != NUL)
6827 {
6828 len = spell_check(curwin, str, &attr, &capcol, FALSE);
6829 if (attr != HLF_COUNT)
6830 {
6831 word = str;
6832 break;
6833 }
6834 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02006835 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02006836 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006837 }
6838 }
6839 }
6840#endif
6841
6842 list_append_string(rettv->vval.v_list, word, len);
6843 list_append_string(rettv->vval.v_list, (char_u *)(
6844 attr == HLF_SPB ? "bad" :
6845 attr == HLF_SPR ? "rare" :
6846 attr == HLF_SPL ? "local" :
6847 attr == HLF_SPC ? "caps" :
6848 ""), -1);
6849}
6850
6851/*
6852 * "spellsuggest()" function
6853 */
6854 static void
6855f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
6856{
6857#ifdef FEAT_SPELL
6858 char_u *str;
6859 int typeerr = FALSE;
6860 int maxcount;
6861 garray_T ga;
6862 int i;
6863 listitem_T *li;
6864 int need_capital = FALSE;
6865#endif
6866
6867 if (rettv_list_alloc(rettv) == FAIL)
6868 return;
6869
6870#ifdef FEAT_SPELL
6871 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
6872 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006873 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006874 if (argvars[1].v_type != VAR_UNKNOWN)
6875 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006876 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006877 if (maxcount <= 0)
6878 return;
6879 if (argvars[2].v_type != VAR_UNKNOWN)
6880 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006881 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006882 if (typeerr)
6883 return;
6884 }
6885 }
6886 else
6887 maxcount = 25;
6888
6889 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
6890
6891 for (i = 0; i < ga.ga_len; ++i)
6892 {
6893 str = ((char_u **)ga.ga_data)[i];
6894
6895 li = listitem_alloc();
6896 if (li == NULL)
6897 vim_free(str);
6898 else
6899 {
6900 li->li_tv.v_type = VAR_STRING;
6901 li->li_tv.v_lock = 0;
6902 li->li_tv.vval.v_string = str;
6903 list_append(rettv->vval.v_list, li);
6904 }
6905 }
6906 ga_clear(&ga);
6907 }
6908#endif
6909}
6910
6911 static void
6912f_split(typval_T *argvars, typval_T *rettv)
6913{
6914 char_u *str;
6915 char_u *end;
6916 char_u *pat = NULL;
6917 regmatch_T regmatch;
6918 char_u patbuf[NUMBUFLEN];
6919 char_u *save_cpo;
6920 int match;
6921 colnr_T col = 0;
6922 int keepempty = FALSE;
6923 int typeerr = FALSE;
6924
6925 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6926 save_cpo = p_cpo;
6927 p_cpo = (char_u *)"";
6928
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006929 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006930 if (argvars[1].v_type != VAR_UNKNOWN)
6931 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006932 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006933 if (pat == NULL)
6934 typeerr = TRUE;
6935 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006936 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006937 }
6938 if (pat == NULL || *pat == NUL)
6939 pat = (char_u *)"[\\x01- ]\\+";
6940
6941 if (rettv_list_alloc(rettv) == FAIL)
6942 return;
6943 if (typeerr)
6944 return;
6945
6946 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6947 if (regmatch.regprog != NULL)
6948 {
6949 regmatch.rm_ic = FALSE;
6950 while (*str != NUL || keepempty)
6951 {
6952 if (*str == NUL)
6953 match = FALSE; /* empty item at the end */
6954 else
6955 match = vim_regexec_nl(&regmatch, str, col);
6956 if (match)
6957 end = regmatch.startp[0];
6958 else
6959 end = str + STRLEN(str);
6960 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
6961 && *str != NUL && match && end < regmatch.endp[0]))
6962 {
6963 if (list_append_string(rettv->vval.v_list, str,
6964 (int)(end - str)) == FAIL)
6965 break;
6966 }
6967 if (!match)
6968 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01006969 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006970 if (regmatch.endp[0] > str)
6971 col = 0;
6972 else
Bram Moolenaar13505972019-01-24 15:04:48 +01006973 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006974 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 str = regmatch.endp[0];
6976 }
6977
6978 vim_regfree(regmatch.regprog);
6979 }
6980
6981 p_cpo = save_cpo;
6982}
6983
6984#ifdef FEAT_FLOAT
6985/*
6986 * "sqrt()" function
6987 */
6988 static void
6989f_sqrt(typval_T *argvars, typval_T *rettv)
6990{
6991 float_T f = 0.0;
6992
6993 rettv->v_type = VAR_FLOAT;
6994 if (get_float_arg(argvars, &f) == OK)
6995 rettv->vval.v_float = sqrt(f);
6996 else
6997 rettv->vval.v_float = 0.0;
6998}
6999
7000/*
7001 * "str2float()" function
7002 */
7003 static void
7004f_str2float(typval_T *argvars, typval_T *rettv)
7005{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007006 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007007 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007008
Bram Moolenaar08243d22017-01-10 16:12:29 +01007009 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 p = skipwhite(p + 1);
7011 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007012 if (isneg)
7013 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007014 rettv->v_type = VAR_FLOAT;
7015}
7016#endif
7017
7018/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007019 * "str2list()" function
7020 */
7021 static void
7022f_str2list(typval_T *argvars, typval_T *rettv)
7023{
7024 char_u *p;
7025 int utf8 = FALSE;
7026
7027 if (rettv_list_alloc(rettv) == FAIL)
7028 return;
7029
7030 if (argvars[1].v_type != VAR_UNKNOWN)
7031 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7032
7033 p = tv_get_string(&argvars[0]);
7034
7035 if (has_mbyte || utf8)
7036 {
7037 int (*ptr2len)(char_u *);
7038 int (*ptr2char)(char_u *);
7039
7040 if (utf8 || enc_utf8)
7041 {
7042 ptr2len = utf_ptr2len;
7043 ptr2char = utf_ptr2char;
7044 }
7045 else
7046 {
7047 ptr2len = mb_ptr2len;
7048 ptr2char = mb_ptr2char;
7049 }
7050
7051 for ( ; *p != NUL; p += (*ptr2len)(p))
7052 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7053 }
7054 else
7055 for ( ; *p != NUL; ++p)
7056 list_append_number(rettv->vval.v_list, *p);
7057}
7058
7059/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007060 * "str2nr()" function
7061 */
7062 static void
7063f_str2nr(typval_T *argvars, typval_T *rettv)
7064{
7065 int base = 10;
7066 char_u *p;
7067 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007068 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007069 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007070
7071 if (argvars[1].v_type != VAR_UNKNOWN)
7072 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007073 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007074 if (base != 2 && base != 8 && base != 10 && base != 16)
7075 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007076 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007077 return;
7078 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007079 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7080 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007081 }
7082
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007083 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007084 isneg = (*p == '-');
7085 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007086 p = skipwhite(p + 1);
7087 switch (base)
7088 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007089 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7090 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7091 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007093 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7094 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007095 if (isneg)
7096 rettv->vval.v_number = -n;
7097 else
7098 rettv->vval.v_number = n;
7099
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007100}
7101
7102#ifdef HAVE_STRFTIME
7103/*
7104 * "strftime({format}[, {time}])" function
7105 */
7106 static void
7107f_strftime(typval_T *argvars, typval_T *rettv)
7108{
7109 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007110 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007111 struct tm *curtime;
7112 time_t seconds;
7113 char_u *p;
7114
7115 rettv->v_type = VAR_STRING;
7116
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007117 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 if (argvars[1].v_type == VAR_UNKNOWN)
7119 seconds = time(NULL);
7120 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007121 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007122 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007123 /* MSVC returns NULL for an invalid value of seconds. */
7124 if (curtime == NULL)
7125 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7126 else
7127 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007128 vimconv_T conv;
7129 char_u *enc;
7130
7131 conv.vc_type = CONV_NONE;
7132 enc = enc_locale();
7133 convert_setup(&conv, p_enc, enc);
7134 if (conv.vc_type != CONV_NONE)
7135 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 if (p != NULL)
7137 (void)strftime((char *)result_buf, sizeof(result_buf),
7138 (char *)p, curtime);
7139 else
7140 result_buf[0] = NUL;
7141
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007142 if (conv.vc_type != CONV_NONE)
7143 vim_free(p);
7144 convert_setup(&conv, enc, p_enc);
7145 if (conv.vc_type != CONV_NONE)
7146 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7147 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 rettv->vval.v_string = vim_strsave(result_buf);
7149
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007150 /* Release conversion descriptors */
7151 convert_setup(&conv, NULL, NULL);
7152 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007153 }
7154}
7155#endif
7156
7157/*
7158 * "strgetchar()" function
7159 */
7160 static void
7161f_strgetchar(typval_T *argvars, typval_T *rettv)
7162{
7163 char_u *str;
7164 int len;
7165 int error = FALSE;
7166 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007167 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007168
7169 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007170 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007171 if (str == NULL)
7172 return;
7173 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007174 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007175 if (error)
7176 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007177
Bram Moolenaar13505972019-01-24 15:04:48 +01007178 while (charidx >= 0 && byteidx < len)
7179 {
7180 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007181 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007182 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7183 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007184 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007185 --charidx;
7186 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007187 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188}
7189
7190/*
7191 * "stridx()" function
7192 */
7193 static void
7194f_stridx(typval_T *argvars, typval_T *rettv)
7195{
7196 char_u buf[NUMBUFLEN];
7197 char_u *needle;
7198 char_u *haystack;
7199 char_u *save_haystack;
7200 char_u *pos;
7201 int start_idx;
7202
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007203 needle = tv_get_string_chk(&argvars[1]);
7204 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007205 rettv->vval.v_number = -1;
7206 if (needle == NULL || haystack == NULL)
7207 return; /* type error; errmsg already given */
7208
7209 if (argvars[2].v_type != VAR_UNKNOWN)
7210 {
7211 int error = FALSE;
7212
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007213 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007214 if (error || start_idx >= (int)STRLEN(haystack))
7215 return;
7216 if (start_idx >= 0)
7217 haystack += start_idx;
7218 }
7219
7220 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7221 if (pos != NULL)
7222 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7223}
7224
7225/*
7226 * "string()" function
7227 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007228 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007229f_string(typval_T *argvars, typval_T *rettv)
7230{
7231 char_u *tofree;
7232 char_u numbuf[NUMBUFLEN];
7233
7234 rettv->v_type = VAR_STRING;
7235 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7236 get_copyID());
7237 /* Make a copy if we have a value but it's not in allocated memory. */
7238 if (rettv->vval.v_string != NULL && tofree == NULL)
7239 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7240}
7241
7242/*
7243 * "strlen()" function
7244 */
7245 static void
7246f_strlen(typval_T *argvars, typval_T *rettv)
7247{
7248 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007249 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007250}
7251
7252/*
7253 * "strchars()" function
7254 */
7255 static void
7256f_strchars(typval_T *argvars, typval_T *rettv)
7257{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007258 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007259 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007260 varnumber_T len = 0;
7261 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007262
7263 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007264 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007265 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007266 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007267 else
7268 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007269 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7270 while (*s != NUL)
7271 {
7272 func_mb_ptr2char_adv(&s);
7273 ++len;
7274 }
7275 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007276 }
7277}
7278
7279/*
7280 * "strdisplaywidth()" function
7281 */
7282 static void
7283f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7284{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007285 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007286 int col = 0;
7287
7288 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007289 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007290
7291 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7292}
7293
7294/*
7295 * "strwidth()" function
7296 */
7297 static void
7298f_strwidth(typval_T *argvars, typval_T *rettv)
7299{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007300 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007301
Bram Moolenaar13505972019-01-24 15:04:48 +01007302 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007303}
7304
7305/*
7306 * "strcharpart()" function
7307 */
7308 static void
7309f_strcharpart(typval_T *argvars, typval_T *rettv)
7310{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007311 char_u *p;
7312 int nchar;
7313 int nbyte = 0;
7314 int charlen;
7315 int len = 0;
7316 int slen;
7317 int error = FALSE;
7318
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007319 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007320 slen = (int)STRLEN(p);
7321
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007322 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007323 if (!error)
7324 {
7325 if (nchar > 0)
7326 while (nchar > 0 && nbyte < slen)
7327 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007328 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007329 --nchar;
7330 }
7331 else
7332 nbyte = nchar;
7333 if (argvars[2].v_type != VAR_UNKNOWN)
7334 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007335 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007336 while (charlen > 0 && nbyte + len < slen)
7337 {
7338 int off = nbyte + len;
7339
7340 if (off < 0)
7341 len += 1;
7342 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007343 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007344 --charlen;
7345 }
7346 }
7347 else
7348 len = slen - nbyte; /* default: all bytes that are available. */
7349 }
7350
7351 /*
7352 * Only return the overlap between the specified part and the actual
7353 * string.
7354 */
7355 if (nbyte < 0)
7356 {
7357 len += nbyte;
7358 nbyte = 0;
7359 }
7360 else if (nbyte > slen)
7361 nbyte = slen;
7362 if (len < 0)
7363 len = 0;
7364 else if (nbyte + len > slen)
7365 len = slen - nbyte;
7366
7367 rettv->v_type = VAR_STRING;
7368 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007369}
7370
7371/*
7372 * "strpart()" function
7373 */
7374 static void
7375f_strpart(typval_T *argvars, typval_T *rettv)
7376{
7377 char_u *p;
7378 int n;
7379 int len;
7380 int slen;
7381 int error = FALSE;
7382
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007383 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007384 slen = (int)STRLEN(p);
7385
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007386 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007387 if (error)
7388 len = 0;
7389 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007390 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007391 else
7392 len = slen - n; /* default len: all bytes that are available. */
7393
7394 /*
7395 * Only return the overlap between the specified part and the actual
7396 * string.
7397 */
7398 if (n < 0)
7399 {
7400 len += n;
7401 n = 0;
7402 }
7403 else if (n > slen)
7404 n = slen;
7405 if (len < 0)
7406 len = 0;
7407 else if (n + len > slen)
7408 len = slen - n;
7409
7410 rettv->v_type = VAR_STRING;
7411 rettv->vval.v_string = vim_strnsave(p + n, len);
7412}
7413
7414/*
7415 * "strridx()" function
7416 */
7417 static void
7418f_strridx(typval_T *argvars, typval_T *rettv)
7419{
7420 char_u buf[NUMBUFLEN];
7421 char_u *needle;
7422 char_u *haystack;
7423 char_u *rest;
7424 char_u *lastmatch = NULL;
7425 int haystack_len, end_idx;
7426
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007427 needle = tv_get_string_chk(&argvars[1]);
7428 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007429
7430 rettv->vval.v_number = -1;
7431 if (needle == NULL || haystack == NULL)
7432 return; /* type error; errmsg already given */
7433
7434 haystack_len = (int)STRLEN(haystack);
7435 if (argvars[2].v_type != VAR_UNKNOWN)
7436 {
7437 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007438 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439 if (end_idx < 0)
7440 return; /* can never find a match */
7441 }
7442 else
7443 end_idx = haystack_len;
7444
7445 if (*needle == NUL)
7446 {
7447 /* Empty string matches past the end. */
7448 lastmatch = haystack + end_idx;
7449 }
7450 else
7451 {
7452 for (rest = haystack; *rest != '\0'; ++rest)
7453 {
7454 rest = (char_u *)strstr((char *)rest, (char *)needle);
7455 if (rest == NULL || rest > haystack + end_idx)
7456 break;
7457 lastmatch = rest;
7458 }
7459 }
7460
7461 if (lastmatch == NULL)
7462 rettv->vval.v_number = -1;
7463 else
7464 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7465}
7466
7467/*
7468 * "strtrans()" function
7469 */
7470 static void
7471f_strtrans(typval_T *argvars, typval_T *rettv)
7472{
7473 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007474 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007475}
7476
7477/*
7478 * "submatch()" function
7479 */
7480 static void
7481f_submatch(typval_T *argvars, typval_T *rettv)
7482{
7483 int error = FALSE;
7484 int no;
7485 int retList = 0;
7486
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007487 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488 if (error)
7489 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007490 if (no < 0 || no >= NSUBEXP)
7491 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007492 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007493 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007494 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007496 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007497 if (error)
7498 return;
7499
7500 if (retList == 0)
7501 {
7502 rettv->v_type = VAR_STRING;
7503 rettv->vval.v_string = reg_submatch(no);
7504 }
7505 else
7506 {
7507 rettv->v_type = VAR_LIST;
7508 rettv->vval.v_list = reg_submatch_list(no);
7509 }
7510}
7511
7512/*
7513 * "substitute()" function
7514 */
7515 static void
7516f_substitute(typval_T *argvars, typval_T *rettv)
7517{
7518 char_u patbuf[NUMBUFLEN];
7519 char_u subbuf[NUMBUFLEN];
7520 char_u flagsbuf[NUMBUFLEN];
7521
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007522 char_u *str = tv_get_string_chk(&argvars[0]);
7523 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007524 char_u *sub = NULL;
7525 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007526 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007527
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007528 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7529 expr = &argvars[2];
7530 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007531 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007532
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007533 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007534 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7535 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007536 rettv->vval.v_string = NULL;
7537 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007538 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007539}
7540
7541/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007542 * "swapinfo(swap_filename)" function
7543 */
7544 static void
7545f_swapinfo(typval_T *argvars, typval_T *rettv)
7546{
7547 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007548 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007549}
7550
7551/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007552 * "swapname(expr)" function
7553 */
7554 static void
7555f_swapname(typval_T *argvars, typval_T *rettv)
7556{
7557 buf_T *buf;
7558
7559 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007560 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007561 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7562 || buf->b_ml.ml_mfp->mf_fname == NULL)
7563 rettv->vval.v_string = NULL;
7564 else
7565 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7566}
7567
7568/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007569 * "synID(lnum, col, trans)" function
7570 */
7571 static void
7572f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7573{
7574 int id = 0;
7575#ifdef FEAT_SYN_HL
7576 linenr_T lnum;
7577 colnr_T col;
7578 int trans;
7579 int transerr = FALSE;
7580
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007581 lnum = tv_get_lnum(argvars); /* -1 on type error */
7582 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7583 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007584
7585 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7586 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7587 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7588#endif
7589
7590 rettv->vval.v_number = id;
7591}
7592
7593/*
7594 * "synIDattr(id, what [, mode])" function
7595 */
7596 static void
7597f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7598{
7599 char_u *p = NULL;
7600#ifdef FEAT_SYN_HL
7601 int id;
7602 char_u *what;
7603 char_u *mode;
7604 char_u modebuf[NUMBUFLEN];
7605 int modec;
7606
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007607 id = (int)tv_get_number(&argvars[0]);
7608 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007609 if (argvars[2].v_type != VAR_UNKNOWN)
7610 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007611 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007612 modec = TOLOWER_ASC(mode[0]);
7613 if (modec != 't' && modec != 'c' && modec != 'g')
7614 modec = 0; /* replace invalid with current */
7615 }
7616 else
7617 {
7618#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7619 if (USE_24BIT)
7620 modec = 'g';
7621 else
7622#endif
7623 if (t_colors > 1)
7624 modec = 'c';
7625 else
7626 modec = 't';
7627 }
7628
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007629 switch (TOLOWER_ASC(what[0]))
7630 {
7631 case 'b':
7632 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7633 p = highlight_color(id, what, modec);
7634 else /* bold */
7635 p = highlight_has_attr(id, HL_BOLD, modec);
7636 break;
7637
7638 case 'f': /* fg[#] or font */
7639 p = highlight_color(id, what, modec);
7640 break;
7641
7642 case 'i':
7643 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7644 p = highlight_has_attr(id, HL_INVERSE, modec);
7645 else /* italic */
7646 p = highlight_has_attr(id, HL_ITALIC, modec);
7647 break;
7648
7649 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007650 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007651 break;
7652
7653 case 'r': /* reverse */
7654 p = highlight_has_attr(id, HL_INVERSE, modec);
7655 break;
7656
7657 case 's':
7658 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7659 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007660 /* strikeout */
7661 else if (TOLOWER_ASC(what[1]) == 't' &&
7662 TOLOWER_ASC(what[2]) == 'r')
7663 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007664 else /* standout */
7665 p = highlight_has_attr(id, HL_STANDOUT, modec);
7666 break;
7667
7668 case 'u':
7669 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7670 /* underline */
7671 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7672 else
7673 /* undercurl */
7674 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7675 break;
7676 }
7677
7678 if (p != NULL)
7679 p = vim_strsave(p);
7680#endif
7681 rettv->v_type = VAR_STRING;
7682 rettv->vval.v_string = p;
7683}
7684
7685/*
7686 * "synIDtrans(id)" function
7687 */
7688 static void
7689f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7690{
7691 int id;
7692
7693#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007694 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007695
7696 if (id > 0)
7697 id = syn_get_final_id(id);
7698 else
7699#endif
7700 id = 0;
7701
7702 rettv->vval.v_number = id;
7703}
7704
7705/*
7706 * "synconcealed(lnum, col)" function
7707 */
7708 static void
7709f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7710{
7711#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7712 linenr_T lnum;
7713 colnr_T col;
7714 int syntax_flags = 0;
7715 int cchar;
7716 int matchid = 0;
7717 char_u str[NUMBUFLEN];
7718#endif
7719
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007720 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007721
7722#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007723 lnum = tv_get_lnum(argvars); /* -1 on type error */
7724 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007725
7726 vim_memset(str, NUL, sizeof(str));
7727
7728 if (rettv_list_alloc(rettv) != FAIL)
7729 {
7730 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7731 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7732 && curwin->w_p_cole > 0)
7733 {
7734 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7735 syntax_flags = get_syntax_info(&matchid);
7736
7737 /* get the conceal character */
7738 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7739 {
7740 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007741 if (cchar == NUL && curwin->w_p_cole == 1)
7742 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007743 if (cchar != NUL)
7744 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007745 if (has_mbyte)
7746 (*mb_char2bytes)(cchar, str);
7747 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007748 str[0] = cchar;
7749 }
7750 }
7751 }
7752
7753 list_append_number(rettv->vval.v_list,
7754 (syntax_flags & HL_CONCEAL) != 0);
7755 /* -1 to auto-determine strlen */
7756 list_append_string(rettv->vval.v_list, str, -1);
7757 list_append_number(rettv->vval.v_list, matchid);
7758 }
7759#endif
7760}
7761
7762/*
7763 * "synstack(lnum, col)" function
7764 */
7765 static void
7766f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7767{
7768#ifdef FEAT_SYN_HL
7769 linenr_T lnum;
7770 colnr_T col;
7771 int i;
7772 int id;
7773#endif
7774
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007775 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007776
7777#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007778 lnum = tv_get_lnum(argvars); /* -1 on type error */
7779 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007780
7781 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7782 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7783 && rettv_list_alloc(rettv) != FAIL)
7784 {
7785 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
7786 for (i = 0; ; ++i)
7787 {
7788 id = syn_get_stack_item(i);
7789 if (id < 0)
7790 break;
7791 if (list_append_number(rettv->vval.v_list, id) == FAIL)
7792 break;
7793 }
7794 }
7795#endif
7796}
7797
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798/*
7799 * "tabpagebuflist()" function
7800 */
7801 static void
7802f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7803{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007804 tabpage_T *tp;
7805 win_T *wp = NULL;
7806
7807 if (argvars[0].v_type == VAR_UNKNOWN)
7808 wp = firstwin;
7809 else
7810 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007811 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007812 if (tp != NULL)
7813 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
7814 }
7815 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
7816 {
7817 for (; wp != NULL; wp = wp->w_next)
7818 if (list_append_number(rettv->vval.v_list,
7819 wp->w_buffer->b_fnum) == FAIL)
7820 break;
7821 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007822}
7823
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007824/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007825 * "tagfiles()" function
7826 */
7827 static void
7828f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
7829{
7830 char_u *fname;
7831 tagname_T tn;
7832 int first;
7833
7834 if (rettv_list_alloc(rettv) == FAIL)
7835 return;
7836 fname = alloc(MAXPATHL);
7837 if (fname == NULL)
7838 return;
7839
7840 for (first = TRUE; ; first = FALSE)
7841 if (get_tagfname(&tn, first, fname) == FAIL
7842 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
7843 break;
7844 tagname_free(&tn);
7845 vim_free(fname);
7846}
7847
7848/*
7849 * "taglist()" function
7850 */
7851 static void
7852f_taglist(typval_T *argvars, typval_T *rettv)
7853{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007854 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007855 char_u *tag_pattern;
7856
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007857 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007858
7859 rettv->vval.v_number = FALSE;
7860 if (*tag_pattern == NUL)
7861 return;
7862
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007863 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007864 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007865 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007866 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007867}
7868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007869#ifdef FEAT_FLOAT
7870/*
7871 * "tan()" function
7872 */
7873 static void
7874f_tan(typval_T *argvars, typval_T *rettv)
7875{
7876 float_T f = 0.0;
7877
7878 rettv->v_type = VAR_FLOAT;
7879 if (get_float_arg(argvars, &f) == OK)
7880 rettv->vval.v_float = tan(f);
7881 else
7882 rettv->vval.v_float = 0.0;
7883}
7884
7885/*
7886 * "tanh()" function
7887 */
7888 static void
7889f_tanh(typval_T *argvars, typval_T *rettv)
7890{
7891 float_T f = 0.0;
7892
7893 rettv->v_type = VAR_FLOAT;
7894 if (get_float_arg(argvars, &f) == OK)
7895 rettv->vval.v_float = tanh(f);
7896 else
7897 rettv->vval.v_float = 0.0;
7898}
7899#endif
7900
7901/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007902 * "tolower(string)" function
7903 */
7904 static void
7905f_tolower(typval_T *argvars, typval_T *rettv)
7906{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007907 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007908 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007909}
7910
7911/*
7912 * "toupper(string)" function
7913 */
7914 static void
7915f_toupper(typval_T *argvars, typval_T *rettv)
7916{
7917 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007918 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007919}
7920
7921/*
7922 * "tr(string, fromstr, tostr)" function
7923 */
7924 static void
7925f_tr(typval_T *argvars, typval_T *rettv)
7926{
7927 char_u *in_str;
7928 char_u *fromstr;
7929 char_u *tostr;
7930 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931 int inlen;
7932 int fromlen;
7933 int tolen;
7934 int idx;
7935 char_u *cpstr;
7936 int cplen;
7937 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007938 char_u buf[NUMBUFLEN];
7939 char_u buf2[NUMBUFLEN];
7940 garray_T ga;
7941
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007942 in_str = tv_get_string(&argvars[0]);
7943 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
7944 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007945
7946 /* Default return value: empty string. */
7947 rettv->v_type = VAR_STRING;
7948 rettv->vval.v_string = NULL;
7949 if (fromstr == NULL || tostr == NULL)
7950 return; /* type error; errmsg already given */
7951 ga_init2(&ga, (int)sizeof(char), 80);
7952
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007953 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007954 /* not multi-byte: fromstr and tostr must be the same length */
7955 if (STRLEN(fromstr) != STRLEN(tostr))
7956 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007957error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007958 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007959 ga_clear(&ga);
7960 return;
7961 }
7962
7963 /* fromstr and tostr have to contain the same number of chars */
7964 while (*in_str != NUL)
7965 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007966 if (has_mbyte)
7967 {
7968 inlen = (*mb_ptr2len)(in_str);
7969 cpstr = in_str;
7970 cplen = inlen;
7971 idx = 0;
7972 for (p = fromstr; *p != NUL; p += fromlen)
7973 {
7974 fromlen = (*mb_ptr2len)(p);
7975 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
7976 {
7977 for (p = tostr; *p != NUL; p += tolen)
7978 {
7979 tolen = (*mb_ptr2len)(p);
7980 if (idx-- == 0)
7981 {
7982 cplen = tolen;
7983 cpstr = p;
7984 break;
7985 }
7986 }
7987 if (*p == NUL) /* tostr is shorter than fromstr */
7988 goto error;
7989 break;
7990 }
7991 ++idx;
7992 }
7993
7994 if (first && cpstr == in_str)
7995 {
7996 /* Check that fromstr and tostr have the same number of
7997 * (multi-byte) characters. Done only once when a character
7998 * of in_str doesn't appear in fromstr. */
7999 first = FALSE;
8000 for (p = tostr; *p != NUL; p += tolen)
8001 {
8002 tolen = (*mb_ptr2len)(p);
8003 --idx;
8004 }
8005 if (idx != 0)
8006 goto error;
8007 }
8008
8009 (void)ga_grow(&ga, cplen);
8010 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8011 ga.ga_len += cplen;
8012
8013 in_str += inlen;
8014 }
8015 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008016 {
8017 /* When not using multi-byte chars we can do it faster. */
8018 p = vim_strchr(fromstr, *in_str);
8019 if (p != NULL)
8020 ga_append(&ga, tostr[p - fromstr]);
8021 else
8022 ga_append(&ga, *in_str);
8023 ++in_str;
8024 }
8025 }
8026
8027 /* add a terminating NUL */
8028 (void)ga_grow(&ga, 1);
8029 ga_append(&ga, NUL);
8030
8031 rettv->vval.v_string = ga.ga_data;
8032}
8033
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008034/*
8035 * "trim({expr})" function
8036 */
8037 static void
8038f_trim(typval_T *argvars, typval_T *rettv)
8039{
8040 char_u buf1[NUMBUFLEN];
8041 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008042 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008043 char_u *mask = NULL;
8044 char_u *tail;
8045 char_u *prev;
8046 char_u *p;
8047 int c1;
8048
8049 rettv->v_type = VAR_STRING;
8050 if (head == NULL)
8051 {
8052 rettv->vval.v_string = NULL;
8053 return;
8054 }
8055
8056 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008057 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008058
8059 while (*head != NUL)
8060 {
8061 c1 = PTR2CHAR(head);
8062 if (mask == NULL)
8063 {
8064 if (c1 > ' ' && c1 != 0xa0)
8065 break;
8066 }
8067 else
8068 {
8069 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8070 if (c1 == PTR2CHAR(p))
8071 break;
8072 if (*p == NUL)
8073 break;
8074 }
8075 MB_PTR_ADV(head);
8076 }
8077
8078 for (tail = head + STRLEN(head); tail > head; tail = prev)
8079 {
8080 prev = tail;
8081 MB_PTR_BACK(head, prev);
8082 c1 = PTR2CHAR(prev);
8083 if (mask == NULL)
8084 {
8085 if (c1 > ' ' && c1 != 0xa0)
8086 break;
8087 }
8088 else
8089 {
8090 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8091 if (c1 == PTR2CHAR(p))
8092 break;
8093 if (*p == NUL)
8094 break;
8095 }
8096 }
8097 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8098}
8099
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008100#ifdef FEAT_FLOAT
8101/*
8102 * "trunc({float})" function
8103 */
8104 static void
8105f_trunc(typval_T *argvars, typval_T *rettv)
8106{
8107 float_T f = 0.0;
8108
8109 rettv->v_type = VAR_FLOAT;
8110 if (get_float_arg(argvars, &f) == OK)
8111 /* trunc() is not in C90, use floor() or ceil() instead. */
8112 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8113 else
8114 rettv->vval.v_float = 0.0;
8115}
8116#endif
8117
8118/*
8119 * "type(expr)" function
8120 */
8121 static void
8122f_type(typval_T *argvars, typval_T *rettv)
8123{
8124 int n = -1;
8125
8126 switch (argvars[0].v_type)
8127 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008128 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8129 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008131 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8132 case VAR_LIST: n = VAR_TYPE_LIST; break;
8133 case VAR_DICT: n = VAR_TYPE_DICT; break;
8134 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008135 case VAR_SPECIAL:
8136 if (argvars[0].vval.v_number == VVAL_FALSE
8137 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008138 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008139 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008140 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008141 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008142 case VAR_JOB: n = VAR_TYPE_JOB; break;
8143 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008144 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008145 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008146 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008147 n = -1;
8148 break;
8149 }
8150 rettv->vval.v_number = n;
8151}
8152
8153/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008154 * "virtcol(string)" function
8155 */
8156 static void
8157f_virtcol(typval_T *argvars, typval_T *rettv)
8158{
8159 colnr_T vcol = 0;
8160 pos_T *fp;
8161 int fnum = curbuf->b_fnum;
8162
8163 fp = var2fpos(&argvars[0], FALSE, &fnum);
8164 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8165 && fnum == curbuf->b_fnum)
8166 {
8167 getvvcol(curwin, fp, NULL, NULL, &vcol);
8168 ++vcol;
8169 }
8170
8171 rettv->vval.v_number = vcol;
8172}
8173
8174/*
8175 * "visualmode()" function
8176 */
8177 static void
8178f_visualmode(typval_T *argvars, typval_T *rettv)
8179{
8180 char_u str[2];
8181
8182 rettv->v_type = VAR_STRING;
8183 str[0] = curbuf->b_visual_mode_eval;
8184 str[1] = NUL;
8185 rettv->vval.v_string = vim_strsave(str);
8186
8187 /* A non-zero number or non-empty string argument: reset mode. */
8188 if (non_zero_arg(&argvars[0]))
8189 curbuf->b_visual_mode_eval = NUL;
8190}
8191
8192/*
8193 * "wildmenumode()" function
8194 */
8195 static void
8196f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8197{
8198#ifdef FEAT_WILDMENU
8199 if (wild_menu_showing)
8200 rettv->vval.v_number = 1;
8201#endif
8202}
8203
8204/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008205 * "wordcount()" function
8206 */
8207 static void
8208f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8209{
8210 if (rettv_dict_alloc(rettv) == FAIL)
8211 return;
8212 cursor_pos_info(rettv->vval.v_dict);
8213}
8214
8215/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008216 * "xor(expr, expr)" function
8217 */
8218 static void
8219f_xor(typval_T *argvars, typval_T *rettv)
8220{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008221 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8222 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008223}
8224
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008225#endif /* FEAT_EVAL */