blob: 04e131391682a1953bd37642fe803b0e22841427 [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);
54static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020056static void f_confirm(typval_T *argvars, typval_T *rettv);
57static void f_copy(typval_T *argvars, typval_T *rettv);
58#ifdef FEAT_FLOAT
59static void f_cos(typval_T *argvars, typval_T *rettv);
60static void f_cosh(typval_T *argvars, typval_T *rettv);
61#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010063#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020064static void f_debugbreak(typval_T *argvars, typval_T *rettv);
65#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020068static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020069static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_escape(typval_T *argvars, typval_T *rettv);
71static void f_eval(typval_T *argvars, typval_T *rettv);
72static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020074static void f_exists(typval_T *argvars, typval_T *rettv);
75#ifdef FEAT_FLOAT
76static void f_exp(typval_T *argvars, typval_T *rettv);
77#endif
78static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020079static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020081#ifdef FEAT_FLOAT
82static void f_float2nr(typval_T *argvars, typval_T *rettv);
83static void f_floor(typval_T *argvars, typval_T *rettv);
84static void f_fmod(typval_T *argvars, typval_T *rettv);
85#endif
86static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020087static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020088static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_function(typval_T *argvars, typval_T *rettv);
90static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
91static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010092static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020094static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020095static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010097static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020098static void f_getpid(typval_T *argvars, typval_T *rettv);
99static void f_getcurpos(typval_T *argvars, typval_T *rettv);
100static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_getreg(typval_T *argvars, typval_T *rettv);
102static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100103static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
106static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200107static void f_hlID(typval_T *argvars, typval_T *rettv);
108static void f_hlexists(typval_T *argvars, typval_T *rettv);
109static void f_hostname(typval_T *argvars, typval_T *rettv);
110static void f_iconv(typval_T *argvars, typval_T *rettv);
111static void f_indent(typval_T *argvars, typval_T *rettv);
112static void f_index(typval_T *argvars, typval_T *rettv);
113static void f_input(typval_T *argvars, typval_T *rettv);
114static void f_inputdialog(typval_T *argvars, typval_T *rettv);
115static void f_inputlist(typval_T *argvars, typval_T *rettv);
116static void f_inputrestore(typval_T *argvars, typval_T *rettv);
117static void f_inputsave(typval_T *argvars, typval_T *rettv);
118static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200120static void f_islocked(typval_T *argvars, typval_T *rettv);
121#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200122static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200123static void f_isnan(typval_T *argvars, typval_T *rettv);
124#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
126static void f_len(typval_T *argvars, typval_T *rettv);
127static void f_libcall(typval_T *argvars, typval_T *rettv);
128static void f_libcallnr(typval_T *argvars, typval_T *rettv);
129static void f_line(typval_T *argvars, typval_T *rettv);
130static void f_line2byte(typval_T *argvars, typval_T *rettv);
131static void f_lispindent(typval_T *argvars, typval_T *rettv);
132static void f_localtime(typval_T *argvars, typval_T *rettv);
133#ifdef FEAT_FLOAT
134static void f_log(typval_T *argvars, typval_T *rettv);
135static void f_log10(typval_T *argvars, typval_T *rettv);
136#endif
137#ifdef FEAT_LUA
138static void f_luaeval(typval_T *argvars, typval_T *rettv);
139#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200140static void f_maparg(typval_T *argvars, typval_T *rettv);
141static void f_mapcheck(typval_T *argvars, typval_T *rettv);
142static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200143static void f_matchend(typval_T *argvars, typval_T *rettv);
144static void f_matchlist(typval_T *argvars, typval_T *rettv);
145static void f_matchstr(typval_T *argvars, typval_T *rettv);
146static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
147static void f_max(typval_T *argvars, typval_T *rettv);
148static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200149#ifdef FEAT_MZSCHEME
150static void f_mzeval(typval_T *argvars, typval_T *rettv);
151#endif
152static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
153static void f_nr2char(typval_T *argvars, typval_T *rettv);
154static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200155#ifdef FEAT_PERL
156static void f_perleval(typval_T *argvars, typval_T *rettv);
157#endif
158#ifdef FEAT_FLOAT
159static void f_pow(typval_T *argvars, typval_T *rettv);
160#endif
161static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
162static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200163static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200164static void f_pumvisible(typval_T *argvars, typval_T *rettv);
165#ifdef FEAT_PYTHON3
166static void f_py3eval(typval_T *argvars, typval_T *rettv);
167#endif
168#ifdef FEAT_PYTHON
169static void f_pyeval(typval_T *argvars, typval_T *rettv);
170#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100171#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
172static void f_pyxeval(typval_T *argvars, typval_T *rettv);
173#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200174static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200175static void f_reg_executing(typval_T *argvars, typval_T *rettv);
176static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_reltime(typval_T *argvars, typval_T *rettv);
178#ifdef FEAT_FLOAT
179static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
180#endif
181static void f_reltimestr(typval_T *argvars, typval_T *rettv);
182static void f_remote_expr(typval_T *argvars, typval_T *rettv);
183static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
184static void f_remote_peek(typval_T *argvars, typval_T *rettv);
185static void f_remote_read(typval_T *argvars, typval_T *rettv);
186static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100187static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200188static void f_rename(typval_T *argvars, typval_T *rettv);
189static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200190#ifdef FEAT_FLOAT
191static void f_round(typval_T *argvars, typval_T *rettv);
192#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100193#ifdef FEAT_RUBY
194static void f_rubyeval(typval_T *argvars, typval_T *rettv);
195#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_screenattr(typval_T *argvars, typval_T *rettv);
197static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100198static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200199static void f_screencol(typval_T *argvars, typval_T *rettv);
200static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100201static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200202static void f_search(typval_T *argvars, typval_T *rettv);
203static void f_searchdecl(typval_T *argvars, typval_T *rettv);
204static void f_searchpair(typval_T *argvars, typval_T *rettv);
205static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
206static void f_searchpos(typval_T *argvars, typval_T *rettv);
207static void f_server2client(typval_T *argvars, typval_T *rettv);
208static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200210static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200211static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200212static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100214static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200215#ifdef FEAT_CRYPT
216static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200217#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200218static void f_shellescape(typval_T *argvars, typval_T *rettv);
219static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200220#ifdef FEAT_FLOAT
221static void f_sin(typval_T *argvars, typval_T *rettv);
222static void f_sinh(typval_T *argvars, typval_T *rettv);
223#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200224static void f_soundfold(typval_T *argvars, typval_T *rettv);
225static void f_spellbadword(typval_T *argvars, typval_T *rettv);
226static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
227static void f_split(typval_T *argvars, typval_T *rettv);
228#ifdef FEAT_FLOAT
229static void f_sqrt(typval_T *argvars, typval_T *rettv);
230static void f_str2float(typval_T *argvars, typval_T *rettv);
231#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200232static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200233static void f_str2nr(typval_T *argvars, typval_T *rettv);
234static void f_strchars(typval_T *argvars, typval_T *rettv);
235#ifdef HAVE_STRFTIME
236static void f_strftime(typval_T *argvars, typval_T *rettv);
237#endif
238static void f_strgetchar(typval_T *argvars, typval_T *rettv);
239static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200240static void f_strlen(typval_T *argvars, typval_T *rettv);
241static void f_strcharpart(typval_T *argvars, typval_T *rettv);
242static void f_strpart(typval_T *argvars, typval_T *rettv);
243static void f_strridx(typval_T *argvars, typval_T *rettv);
244static void f_strtrans(typval_T *argvars, typval_T *rettv);
245static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
246static void f_strwidth(typval_T *argvars, typval_T *rettv);
247static void f_submatch(typval_T *argvars, typval_T *rettv);
248static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200249static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200250static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200251static void f_synID(typval_T *argvars, typval_T *rettv);
252static void f_synIDattr(typval_T *argvars, typval_T *rettv);
253static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
254static void f_synstack(typval_T *argvars, typval_T *rettv);
255static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200257static void f_taglist(typval_T *argvars, typval_T *rettv);
258static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200259#ifdef FEAT_FLOAT
260static void f_tan(typval_T *argvars, typval_T *rettv);
261static void f_tanh(typval_T *argvars, typval_T *rettv);
262#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200263static void f_tolower(typval_T *argvars, typval_T *rettv);
264static void f_toupper(typval_T *argvars, typval_T *rettv);
265static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100266static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200267#ifdef FEAT_FLOAT
268static void f_trunc(typval_T *argvars, typval_T *rettv);
269#endif
270static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200271static void f_virtcol(typval_T *argvars, typval_T *rettv);
272static void f_visualmode(typval_T *argvars, typval_T *rettv);
273static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200274static void f_wordcount(typval_T *argvars, typval_T *rettv);
275static void f_xor(typval_T *argvars, typval_T *rettv);
276
277/*
278 * Array with names and number of arguments of all internal functions
279 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
280 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200281typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200282{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200283 char *f_name; // function name
284 char f_min_argc; // minimal number of arguments
285 char f_max_argc; // maximal number of arguments
286 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200287 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200288 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200289} funcentry_T;
290
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200291// values for f_argtype; zero means it cannot be used as a method
292#define FEARG_1 1 // base is the first argument
293#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200294#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200295#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200296#define FEARG_LAST 9 // base is the last argument
297
Bram Moolenaarac92e252019-08-03 21:58:38 +0200298static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200299{
300#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200301 {"abs", 1, 1, FEARG_1, f_abs},
302 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200303#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200304 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200305 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200306 {"append", 2, 2, FEARG_LAST, f_append},
307 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
308 {"argc", 0, 1, 0, f_argc},
309 {"argidx", 0, 0, 0, f_argidx},
310 {"arglistid", 0, 2, 0, f_arglistid},
311 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200312#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200313 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200314#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200315 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200316 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200317 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200318 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200319 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
320 {"assert_false", 1, 2, FEARG_1, f_assert_false},
321 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
322 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200323 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200324 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200325 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200326 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200327#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200328 {"atan", 1, 1, FEARG_1, f_atan},
329 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200330#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100331#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200332 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200333 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100334# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200335 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100336# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100337#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200338 {"browse", 4, 4, 0, f_browse},
339 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200340 {"bufadd", 1, 1, FEARG_1, f_bufadd},
341 {"bufexists", 1, 1, FEARG_1, f_bufexists},
342 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200343 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
344 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200345 {"buflisted", 1, 1, FEARG_1, f_buflisted},
346 {"bufload", 1, 1, FEARG_1, f_bufload},
347 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200348 {"bufname", 0, 1, FEARG_1, f_bufname},
349 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200350 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
351 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200352 {"byte2line", 1, 1, FEARG_1, f_byte2line},
353 {"byteidx", 2, 2, FEARG_1, f_byteidx},
354 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
355 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200356#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200357 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200358#endif
359#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200360 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
361 {"ch_close", 1, 1, FEARG_1, f_ch_close},
362 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
363 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
364 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
365 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
366 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
367 {"ch_info", 1, 1, FEARG_1, f_ch_info},
368 {"ch_log", 1, 2, FEARG_1, f_ch_log},
369 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
370 {"ch_open", 1, 2, FEARG_1, f_ch_open},
371 {"ch_read", 1, 2, FEARG_1, f_ch_read},
372 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
373 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
374 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
375 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
376 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
377 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200378#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200379 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200380 {"char2nr", 1, 2, FEARG_1, f_char2nr},
381 {"chdir", 1, 1, FEARG_1, f_chdir},
382 {"cindent", 1, 1, FEARG_1, f_cindent},
383 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
384 {"col", 1, 1, FEARG_1, f_col},
385 {"complete", 2, 2, FEARG_2, f_complete},
386 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200387 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200388 {"complete_info", 0, 1, FEARG_1, f_complete_info},
389 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200390 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200392 {"cos", 1, 1, FEARG_1, f_cos},
393 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200394#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200395 {"count", 2, 4, FEARG_1, f_count},
396 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200397 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100398#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200399 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200400#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200401 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
402 {"delete", 1, 2, FEARG_1, f_delete},
403 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200404 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200405 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
406 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200407 {"empty", 1, 1, FEARG_1, f_empty},
408 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200409 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200410 {"eval", 1, 1, FEARG_1, f_eval},
411 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200412 {"executable", 1, 1, FEARG_1, f_executable},
413 {"execute", 1, 2, FEARG_1, f_execute},
414 {"exepath", 1, 1, FEARG_1, f_exepath},
415 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200416#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200417 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200418#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200419 {"expand", 1, 3, FEARG_1, f_expand},
420 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200421 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200422 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
423 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
424 {"filereadable", 1, 1, FEARG_1, f_filereadable},
425 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200426 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200427 {"finddir", 1, 3, FEARG_1, f_finddir},
428 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200429#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200430 {"float2nr", 1, 1, FEARG_1, f_float2nr},
431 {"floor", 1, 1, FEARG_1, f_floor},
432 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200433#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200434 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
435 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
436 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
437 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
438 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200439 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200440 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200441 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200442 {"funcref", 1, 3, FEARG_1, f_funcref},
443 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200444 {"garbagecollect", 0, 1, 0, f_garbagecollect},
445 {"get", 2, 3, FEARG_1, f_get},
446 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200447 {"getbufline", 2, 3, FEARG_1, f_getbufline},
448 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
449 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200450 {"getchar", 0, 1, 0, f_getchar},
451 {"getcharmod", 0, 0, 0, f_getcharmod},
452 {"getcharsearch", 0, 0, 0, f_getcharsearch},
453 {"getcmdline", 0, 0, 0, f_getcmdline},
454 {"getcmdpos", 0, 0, 0, f_getcmdpos},
455 {"getcmdtype", 0, 0, 0, f_getcmdtype},
456 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200457 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200458 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200459 {"getcwd", 0, 2, FEARG_1, f_getcwd},
460 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200461 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200462 {"getfperm", 1, 1, FEARG_1, f_getfperm},
463 {"getfsize", 1, 1, FEARG_1, f_getfsize},
464 {"getftime", 1, 1, FEARG_1, f_getftime},
465 {"getftype", 1, 1, FEARG_1, f_getftype},
Bram Moolenaara3a12462019-09-07 15:08:38 +0200466 {"getimstatus", 0, 0, 0, f_getimstatus},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200467 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
468 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200469 {"getloclist", 1, 2, 0, f_getloclist},
470 {"getmatches", 0, 1, 0, f_getmatches},
471 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200472 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200473 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200474 {"getreg", 0, 3, FEARG_1, f_getreg},
475 {"getregtype", 0, 1, FEARG_1, f_getregtype},
476 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
477 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
478 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200479 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
480 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
481 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200482 {"getwinposx", 0, 0, 0, f_getwinposx},
483 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200484 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
485 {"glob", 1, 4, FEARG_1, f_glob},
486 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
487 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200488 {"has", 1, 1, 0, f_has},
489 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200490 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
491 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
492 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
493 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
494 {"histadd", 2, 2, FEARG_2, f_histadd},
495 {"histdel", 1, 2, FEARG_1, f_histdel},
496 {"histget", 1, 2, FEARG_1, f_histget},
497 {"histnr", 1, 1, FEARG_1, f_histnr},
498 {"hlID", 1, 1, FEARG_1, f_hlID},
499 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200500 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200501 {"iconv", 3, 3, FEARG_1, f_iconv},
502 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200503 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200504 {"input", 1, 3, FEARG_1, f_input},
505 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
506 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200507 {"inputrestore", 0, 0, 0, f_inputrestore},
508 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200509 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200510 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200511 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200512 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200513#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200514 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200515#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200516 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200517#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200518 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200519#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200520 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200521#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200522 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
523 {"job_info", 0, 1, FEARG_1, f_job_info},
524 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
525 {"job_start", 1, 2, FEARG_1, f_job_start},
526 {"job_status", 1, 1, FEARG_1, f_job_status},
527 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200529 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200530 {"js_decode", 1, 1, FEARG_1, f_js_decode},
531 {"js_encode", 1, 1, FEARG_1, f_js_encode},
532 {"json_decode", 1, 1, FEARG_1, f_json_decode},
533 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200534 {"keys", 1, 1, FEARG_1, f_keys},
535 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
536 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200537 {"libcall", 3, 3, FEARG_3, f_libcall},
538 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200539 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200540 {"line2byte", 1, 1, FEARG_1, f_line2byte},
541 {"lispindent", 1, 1, FEARG_1, f_lispindent},
542 {"list2str", 1, 2, FEARG_1, f_list2str},
543 {"listener_add", 1, 2, FEARG_2, f_listener_add},
544 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
545 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200546 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200547#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200548 {"log", 1, 1, FEARG_1, f_log},
549 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550#endif
551#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200552 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200553#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200554 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200555 {"maparg", 1, 4, FEARG_1, f_maparg},
556 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
557 {"match", 2, 4, FEARG_1, f_match},
558 {"matchadd", 2, 5, FEARG_1, f_matchadd},
559 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
560 {"matcharg", 1, 1, FEARG_1, f_matcharg},
561 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
562 {"matchend", 2, 4, FEARG_1, f_matchend},
563 {"matchlist", 2, 4, FEARG_1, f_matchlist},
564 {"matchstr", 2, 4, FEARG_1, f_matchstr},
565 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200566 {"max", 1, 1, FEARG_1, f_max},
567 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200568 {"mkdir", 1, 3, FEARG_1, f_mkdir},
569 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200570#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200571 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200572#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200573 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
574 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200575 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200576 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200577#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200578 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200579#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200580#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200581 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
582 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200583 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200584 {"popup_close", 1, 2, FEARG_1, f_popup_close},
585 {"popup_create", 2, 2, FEARG_1, f_popup_create},
586 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200587 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
588 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200589 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
590 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200591 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
592 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
593 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200594 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200595 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
596 {"popup_move", 2, 2, FEARG_1, f_popup_move},
597 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
598 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
599 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
600 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200601#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200602#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200603 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200604#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200605 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200606 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200607#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200608 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
609 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
610 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200611#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100612#ifdef FEAT_TEXT_PROP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200613 {"prop_add", 3, 3, FEARG_1, f_prop_add},
614 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
615 {"prop_list", 1, 2, FEARG_1, f_prop_list},
616 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
617 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
618 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
619 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
620 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
621 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100622#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200623 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200624 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200626 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200627#endif
628#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200629 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200630#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100631#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200632 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100633#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200634 {"range", 1, 3, FEARG_1, f_range},
635 {"readdir", 1, 2, FEARG_1, f_readdir},
636 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200637 {"reg_executing", 0, 0, 0, f_reg_executing},
638 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200639 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200640#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200641 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200642#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200643 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
644 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
645 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
646 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
647 {"remote_read", 1, 2, FEARG_1, f_remote_read},
648 {"remote_send", 2, 3, FEARG_1, f_remote_send},
649 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200650 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200651 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200652 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200653 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200654 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200656 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100658#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200659 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100660#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200661 {"screenattr", 2, 2, FEARG_1, f_screenattr},
662 {"screenchar", 2, 2, FEARG_1, f_screenchar},
663 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200664 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200665 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200666 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200667 {"screenstring", 2, 2, FEARG_1, f_screenstring},
668 {"search", 1, 4, FEARG_1, f_search},
669 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200670 {"searchpair", 3, 7, 0, f_searchpair},
671 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200672 {"searchpos", 1, 4, FEARG_1, f_searchpos},
673 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200674 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200675 {"setbufline", 3, 3, FEARG_3, f_setbufline},
676 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
677 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
678 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
679 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200680 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200681 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200682 {"setloclist", 2, 4, FEARG_2, f_setloclist},
683 {"setmatches", 1, 2, FEARG_1, f_setmatches},
684 {"setpos", 2, 2, FEARG_2, f_setpos},
685 {"setqflist", 1, 3, FEARG_1, f_setqflist},
686 {"setreg", 2, 3, FEARG_2, f_setreg},
687 {"settabvar", 3, 3, FEARG_3, f_settabvar},
688 {"settabwinvar", 4, 4, FEARG_4, f_settabwinvar},
689 {"settagstack", 2, 3, FEARG_2, f_settagstack},
690 {"setwinvar", 3, 3, FEARG_3, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200691#ifdef FEAT_CRYPT
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200692 {"sha256", 1, 1, FEARG_1, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693#endif
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200694 {"shellescape", 1, 2, FEARG_1, f_shellescape},
695 {"shiftwidth", 0, 1, FEARG_1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100696#ifdef FEAT_SIGNS
Bram Moolenaar93476fd2019-09-06 22:00:54 +0200697 {"sign_define", 1, 2, FEARG_1, f_sign_define},
698 {"sign_getdefined", 0, 1, FEARG_1, f_sign_getdefined},
699 {"sign_getplaced", 0, 2, FEARG_1, f_sign_getplaced},
700 {"sign_jump", 3, 3, FEARG_1, f_sign_jump},
701 {"sign_place", 4, 5, FEARG_1, f_sign_place},
702 {"sign_placelist", 1, 1, FEARG_1, f_sign_placelist},
703 {"sign_undefine", 0, 1, FEARG_1, f_sign_undefine},
704 {"sign_unplace", 1, 2, FEARG_1, f_sign_unplace},
705 {"sign_unplacelist", 1, 2, FEARG_1, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100706#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200707 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200708#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200709 {"sin", 1, 1, FEARG_1, f_sin},
710 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200711#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200712 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200713#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200714 {"sound_clear", 0, 0, 0, f_sound_clear},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200715 {"sound_playevent", 1, 2, FEARG_1, f_sound_playevent},
716 {"sound_playfile", 1, 2, FEARG_1, f_sound_playfile},
717 {"sound_stop", 1, 1, FEARG_1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200718#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200719 {"soundfold", 1, 1, FEARG_1, f_soundfold},
720 {"spellbadword", 0, 1, FEARG_1, f_spellbadword},
721 {"spellsuggest", 1, 3, FEARG_1, f_spellsuggest},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200722 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200723#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200724 {"sqrt", 1, 1, FEARG_1, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200725#endif
726 {"state", 0, 1, FEARG_1, f_state},
727#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200728 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200729#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200730 {"str2list", 1, 2, FEARG_1, f_str2list},
Bram Moolenaar60a8de22019-09-15 14:33:22 +0200731 {"str2nr", 1, 3, FEARG_1, f_str2nr},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200732 {"strcharpart", 2, 3, FEARG_1, f_strcharpart},
733 {"strchars", 1, 2, FEARG_1, f_strchars},
734 {"strdisplaywidth", 1, 2, FEARG_1, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200735#ifdef HAVE_STRFTIME
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200736 {"strftime", 1, 2, FEARG_1, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200737#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200738 {"strgetchar", 2, 2, FEARG_1, f_strgetchar},
739 {"stridx", 2, 3, FEARG_1, f_stridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200740 {"string", 1, 1, FEARG_1, f_string},
741 {"strlen", 1, 1, FEARG_1, f_strlen},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200742 {"strpart", 2, 3, FEARG_1, f_strpart},
743 {"strridx", 2, 3, FEARG_1, f_strridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200744 {"strtrans", 1, 1, FEARG_1, f_strtrans},
745 {"strwidth", 1, 1, FEARG_1, f_strwidth},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200746 {"submatch", 1, 2, FEARG_1, f_submatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200747 {"substitute", 4, 4, FEARG_1, f_substitute},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200748 {"swapinfo", 1, 1, FEARG_1, f_swapinfo},
749 {"swapname", 1, 1, FEARG_1, f_swapname},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200750 {"synID", 3, 3, 0, f_synID},
751 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
752 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
753 {"synconcealed", 2, 2, 0, f_synconcealed},
754 {"synstack", 2, 2, 0, f_synstack},
755 {"system", 1, 2, FEARG_1, f_system},
756 {"systemlist", 1, 2, FEARG_1, f_systemlist},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200757 {"tabpagebuflist", 0, 1, FEARG_1, f_tabpagebuflist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200758 {"tabpagenr", 0, 1, 0, f_tabpagenr},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200759 {"tabpagewinnr", 1, 2, FEARG_1, f_tabpagewinnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200760 {"tagfiles", 0, 0, 0, f_tagfiles},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200761 {"taglist", 1, 2, FEARG_1, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200763 {"tan", 1, 1, FEARG_1, f_tan},
764 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200765#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200766 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200767#ifdef FEAT_TERMINAL
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200768 {"term_dumpdiff", 2, 3, FEARG_1, f_term_dumpdiff},
769 {"term_dumpload", 1, 2, FEARG_1, f_term_dumpload},
770 {"term_dumpwrite", 2, 3, FEARG_2, f_term_dumpwrite},
771 {"term_getaltscreen", 1, 1, FEARG_1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200772# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200773 {"term_getansicolors", 1, 1, FEARG_1, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200774# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200775 {"term_getattr", 2, 2, FEARG_1, f_term_getattr},
776 {"term_getcursor", 1, 1, FEARG_1, f_term_getcursor},
777 {"term_getjob", 1, 1, FEARG_1, f_term_getjob},
778 {"term_getline", 2, 2, FEARG_1, f_term_getline},
779 {"term_getscrolled", 1, 1, FEARG_1, f_term_getscrolled},
780 {"term_getsize", 1, 1, FEARG_1, f_term_getsize},
781 {"term_getstatus", 1, 1, FEARG_1, f_term_getstatus},
782 {"term_gettitle", 1, 1, FEARG_1, f_term_gettitle},
783 {"term_gettty", 1, 2, FEARG_1, f_term_gettty},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200784 {"term_list", 0, 0, 0, f_term_list},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200785 {"term_scrape", 2, 2, FEARG_1, f_term_scrape},
786 {"term_sendkeys", 2, 2, FEARG_1, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200787# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200788 {"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200789# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200790 {"term_setkill", 2, 2, FEARG_1, f_term_setkill},
791 {"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
792 {"term_setsize", 3, 3, FEARG_1, f_term_setsize},
793 {"term_start", 1, 2, FEARG_1, f_term_start},
794 {"term_wait", 1, 2, FEARG_1, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200795#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200796 {"test_alloc_fail", 3, 3, FEARG_1, f_test_alloc_fail},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200797 {"test_autochdir", 0, 0, 0, f_test_autochdir},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200798 {"test_feedinput", 1, 1, FEARG_1, f_test_feedinput},
799 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
800 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
801 {"test_getvalue", 1, 1, FEARG_1, f_test_getvalue},
802 {"test_ignore_error", 1, 1, FEARG_1, f_test_ignore_error},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200803 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200805 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200806#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200807 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200809 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200810#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200811 {"test_null_list", 0, 0, 0, f_test_null_list},
812 {"test_null_partial", 0, 0, 0, f_test_null_partial},
813 {"test_null_string", 0, 0, 0, f_test_null_string},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200814 {"test_option_not_set", 1, 1, FEARG_1, f_test_option_not_set},
815 {"test_override", 2, 2, FEARG_2, f_test_override},
816 {"test_refcount", 1, 1, FEARG_1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200817#ifdef FEAT_GUI
Bram Moolenaarce90e362019-09-08 18:58:44 +0200818 {"test_scrollbar", 3, 3, FEARG_2, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200819#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200820#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200821 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200822#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200823 {"test_settime", 1, 1, FEARG_1, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824#ifdef FEAT_TIMERS
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200825 {"timer_info", 0, 1, FEARG_1, f_timer_info},
826 {"timer_pause", 2, 2, FEARG_1, f_timer_pause},
827 {"timer_start", 2, 3, FEARG_1, f_timer_start},
828 {"timer_stop", 1, 1, FEARG_1, f_timer_stop},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200829 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200830#endif
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200831 {"tolower", 1, 1, FEARG_1, f_tolower},
832 {"toupper", 1, 1, FEARG_1, f_toupper},
833 {"tr", 3, 3, FEARG_1, f_tr},
834 {"trim", 1, 2, FEARG_1, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200835#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200836 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200837#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200838 {"type", 1, 1, FEARG_1, f_type},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200839 {"undofile", 1, 1, FEARG_1, f_undofile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200840 {"undotree", 0, 0, 0, f_undotree},
841 {"uniq", 1, 3, FEARG_1, f_uniq},
842 {"values", 1, 1, FEARG_1, f_values},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200843 {"virtcol", 1, 1, FEARG_1, f_virtcol},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200844 {"visualmode", 0, 1, 0, f_visualmode},
845 {"wildmenumode", 0, 0, 0, f_wildmenumode},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200846 {"win_execute", 2, 3, FEARG_2, f_win_execute},
847 {"win_findbuf", 1, 1, FEARG_1, f_win_findbuf},
848 {"win_getid", 0, 2, FEARG_1, f_win_getid},
849 {"win_gotoid", 1, 1, FEARG_1, f_win_gotoid},
850 {"win_id2tabwin", 1, 1, FEARG_1, f_win_id2tabwin},
851 {"win_id2win", 1, 1, FEARG_1, f_win_id2win},
852 {"win_screenpos", 1, 1, FEARG_1, f_win_screenpos},
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200853 {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200854 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200855 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200856 {"winheight", 1, 1, FEARG_1, f_winheight},
857 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200858 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200859 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200860 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200861 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200862 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200863 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200864 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200865 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200866 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200867};
868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200869/*
870 * Function given to ExpandGeneric() to obtain the list of internal
871 * or user defined function names.
872 */
873 char_u *
874get_function_name(expand_T *xp, int idx)
875{
876 static int intidx = -1;
877 char_u *name;
878
879 if (idx == 0)
880 intidx = -1;
881 if (intidx < 0)
882 {
883 name = get_user_func_name(xp, idx);
884 if (name != NULL)
885 return name;
886 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200887 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200889 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200890 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200891 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200892 STRCAT(IObuff, ")");
893 return IObuff;
894 }
895
896 return NULL;
897}
898
899/*
900 * Function given to ExpandGeneric() to obtain the list of internal or
901 * user defined variable or function names.
902 */
903 char_u *
904get_expr_name(expand_T *xp, int idx)
905{
906 static int intidx = -1;
907 char_u *name;
908
909 if (idx == 0)
910 intidx = -1;
911 if (intidx < 0)
912 {
913 name = get_function_name(xp, idx);
914 if (name != NULL)
915 return name;
916 }
917 return get_user_var_name(xp, ++intidx);
918}
919
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200921 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922 * Return index, or -1 if not found
923 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200924 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200925find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200926{
927 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200928 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200929 int cmp;
930 int x;
931
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200932 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200933
934 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200935 while (first <= last)
936 {
937 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200938 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200939 if (cmp < 0)
940 last = x - 1;
941 else if (cmp > 0)
942 first = x + 1;
943 else
944 return x;
945 }
946 return -1;
947}
948
949 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200950has_internal_func(char_u *name)
951{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200952 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200953}
954
955 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200956call_internal_func(
957 char_u *name,
958 int argcount,
959 typval_T *argvars,
960 typval_T *rettv)
961{
962 int i;
963
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200964 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200965 if (i < 0)
966 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200967 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200968 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200969 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200970 return ERROR_TOOMANY;
971 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200972 global_functions[i].f_func(argvars, rettv);
973 return ERROR_NONE;
974}
975
976/*
977 * Invoke a method for base->method().
978 */
979 int
980call_internal_method(
981 char_u *name,
982 int argcount,
983 typval_T *argvars,
984 typval_T *rettv,
985 typval_T *basetv)
986{
987 int i;
988 int fi;
989 typval_T argv[MAX_FUNC_ARGS + 1];
990
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200991 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +0200992 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200993 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +0200994 if (global_functions[fi].f_argtype == 0)
995 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200996 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200997 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200998 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200999 return ERROR_TOOMANY;
1000
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001001 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001002 {
1003 // base value goes last
1004 for (i = 0; i < argcount; ++i)
1005 argv[i] = argvars[i];
1006 argv[argcount] = *basetv;
1007 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001008 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001009 {
1010 // base value goes second
1011 argv[0] = argvars[0];
1012 argv[1] = *basetv;
1013 for (i = 1; i < argcount; ++i)
1014 argv[i + 1] = argvars[i];
1015 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001016 else if (global_functions[fi].f_argtype == FEARG_3)
1017 {
1018 // base value goes third
1019 argv[0] = argvars[0];
1020 argv[1] = argvars[1];
1021 argv[2] = *basetv;
1022 for (i = 2; i < argcount; ++i)
1023 argv[i + 1] = argvars[i];
1024 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001025 else if (global_functions[fi].f_argtype == FEARG_4)
1026 {
1027 // base value goes fourth
1028 argv[0] = argvars[0];
1029 argv[1] = argvars[1];
1030 argv[2] = argvars[2];
1031 argv[3] = *basetv;
1032 for (i = 3; i < argcount; ++i)
1033 argv[i + 1] = argvars[i];
1034 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001035 else
1036 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001037 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001038 argv[0] = *basetv;
1039 for (i = 0; i < argcount; ++i)
1040 argv[i + 1] = argvars[i];
1041 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001042 argv[argcount + 1].v_type = VAR_UNKNOWN;
1043
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001044 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001045 return ERROR_NONE;
1046}
1047
1048/*
1049 * Return TRUE for a non-zero Number and a non-empty String.
1050 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001051 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001052non_zero_arg(typval_T *argvars)
1053{
1054 return ((argvars[0].v_type == VAR_NUMBER
1055 && argvars[0].vval.v_number != 0)
1056 || (argvars[0].v_type == VAR_SPECIAL
1057 && argvars[0].vval.v_number == VVAL_TRUE)
1058 || (argvars[0].v_type == VAR_STRING
1059 && argvars[0].vval.v_string != NULL
1060 && *argvars[0].vval.v_string != NUL));
1061}
1062
1063/*
1064 * Get the lnum from the first argument.
1065 * Also accepts ".", "$", etc., but that only works for the current buffer.
1066 * Returns -1 on error.
1067 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001068 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001069tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001070{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001071 linenr_T lnum;
1072
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001073 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001074 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001075 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001076 int fnum;
1077 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1078
1079 if (fp != NULL)
1080 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001081 }
1082 return lnum;
1083}
1084
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001085/*
1086 * Get the lnum from the first argument.
1087 * Also accepts "$", then "buf" is used.
1088 * Returns 0 on error.
1089 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001090 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001091tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1092{
1093 if (argvars[0].v_type == VAR_STRING
1094 && argvars[0].vval.v_string != NULL
1095 && argvars[0].vval.v_string[0] == '$'
1096 && buf != NULL)
1097 return buf->b_ml.ml_line_count;
1098 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1099}
1100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001101#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001102/*
1103 * Get the float value of "argvars[0]" into "f".
1104 * Returns FAIL when the argument is not a Number or Float.
1105 */
1106 static int
1107get_float_arg(typval_T *argvars, float_T *f)
1108{
1109 if (argvars[0].v_type == VAR_FLOAT)
1110 {
1111 *f = argvars[0].vval.v_float;
1112 return OK;
1113 }
1114 if (argvars[0].v_type == VAR_NUMBER)
1115 {
1116 *f = (float_T)argvars[0].vval.v_number;
1117 return OK;
1118 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001119 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001120 return FAIL;
1121}
1122
1123/*
1124 * "abs(expr)" function
1125 */
1126 static void
1127f_abs(typval_T *argvars, typval_T *rettv)
1128{
1129 if (argvars[0].v_type == VAR_FLOAT)
1130 {
1131 rettv->v_type = VAR_FLOAT;
1132 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1133 }
1134 else
1135 {
1136 varnumber_T n;
1137 int error = FALSE;
1138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001139 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001140 if (error)
1141 rettv->vval.v_number = -1;
1142 else if (n > 0)
1143 rettv->vval.v_number = n;
1144 else
1145 rettv->vval.v_number = -n;
1146 }
1147}
1148
1149/*
1150 * "acos()" function
1151 */
1152 static void
1153f_acos(typval_T *argvars, typval_T *rettv)
1154{
1155 float_T f = 0.0;
1156
1157 rettv->v_type = VAR_FLOAT;
1158 if (get_float_arg(argvars, &f) == OK)
1159 rettv->vval.v_float = acos(f);
1160 else
1161 rettv->vval.v_float = 0.0;
1162}
1163#endif
1164
1165/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001166 * "and(expr, expr)" function
1167 */
1168 static void
1169f_and(typval_T *argvars, typval_T *rettv)
1170{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001171 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1172 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001173}
1174
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001175#ifdef FEAT_FLOAT
1176/*
1177 * "asin()" function
1178 */
1179 static void
1180f_asin(typval_T *argvars, typval_T *rettv)
1181{
1182 float_T f = 0.0;
1183
1184 rettv->v_type = VAR_FLOAT;
1185 if (get_float_arg(argvars, &f) == OK)
1186 rettv->vval.v_float = asin(f);
1187 else
1188 rettv->vval.v_float = 0.0;
1189}
1190
1191/*
1192 * "atan()" function
1193 */
1194 static void
1195f_atan(typval_T *argvars, typval_T *rettv)
1196{
1197 float_T f = 0.0;
1198
1199 rettv->v_type = VAR_FLOAT;
1200 if (get_float_arg(argvars, &f) == OK)
1201 rettv->vval.v_float = atan(f);
1202 else
1203 rettv->vval.v_float = 0.0;
1204}
1205
1206/*
1207 * "atan2()" function
1208 */
1209 static void
1210f_atan2(typval_T *argvars, typval_T *rettv)
1211{
1212 float_T fx = 0.0, fy = 0.0;
1213
1214 rettv->v_type = VAR_FLOAT;
1215 if (get_float_arg(argvars, &fx) == OK
1216 && get_float_arg(&argvars[1], &fy) == OK)
1217 rettv->vval.v_float = atan2(fx, fy);
1218 else
1219 rettv->vval.v_float = 0.0;
1220}
1221#endif
1222
1223/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001224 * "balloon_show()" function
1225 */
1226#ifdef FEAT_BEVAL
1227 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001228f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1229{
1230 rettv->v_type = VAR_STRING;
1231 if (balloonEval != NULL)
1232 {
1233 if (balloonEval->msg == NULL)
1234 rettv->vval.v_string = NULL;
1235 else
1236 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1237 }
1238}
1239
1240 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001241f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1242{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001243 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001244 {
1245 if (argvars[0].v_type == VAR_LIST
1246# ifdef FEAT_GUI
1247 && !gui.in_use
1248# endif
1249 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001250 {
1251 list_T *l = argvars[0].vval.v_list;
1252
1253 // empty list removes the balloon
1254 post_balloon(balloonEval, NULL,
1255 l == NULL || l->lv_len == 0 ? NULL : l);
1256 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001257 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001258 {
1259 char_u *mesg = tv_get_string_chk(&argvars[0]);
1260
1261 if (mesg != NULL)
1262 // empty string removes the balloon
1263 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1264 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001265 }
1266}
1267
Bram Moolenaar669a8282017-11-19 20:13:05 +01001268# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001269 static void
1270f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1271{
1272 if (rettv_list_alloc(rettv) == OK)
1273 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001274 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001275
1276 if (msg != NULL)
1277 {
1278 pumitem_T *array;
1279 int size = split_message(msg, &array);
1280 int i;
1281
1282 /* Skip the first and last item, they are always empty. */
1283 for (i = 1; i < size - 1; ++i)
1284 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001285 while (size > 0)
1286 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001287 vim_free(array);
1288 }
1289 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001290}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001291# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001292#endif
1293
1294/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 * Get buffer by number or pattern.
1296 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001297 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001298tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001299{
1300 char_u *name = tv->vval.v_string;
1301 buf_T *buf;
1302
1303 if (tv->v_type == VAR_NUMBER)
1304 return buflist_findnr((int)tv->vval.v_number);
1305 if (tv->v_type != VAR_STRING)
1306 return NULL;
1307 if (name == NULL || *name == NUL)
1308 return curbuf;
1309 if (name[0] == '$' && name[1] == NUL)
1310 return lastbuf;
1311
1312 buf = buflist_find_by_name(name, curtab_only);
1313
1314 /* If not found, try expanding the name, like done for bufexists(). */
1315 if (buf == NULL)
1316 buf = find_buffer(tv);
1317
1318 return buf;
1319}
1320
1321/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001322 * Get the buffer from "arg" and give an error and return NULL if it is not
1323 * valid.
1324 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001325 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001326get_buf_arg(typval_T *arg)
1327{
1328 buf_T *buf;
1329
1330 ++emsg_off;
1331 buf = tv_get_buf(arg, FALSE);
1332 --emsg_off;
1333 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001334 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001335 return buf;
1336}
1337
1338/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001339 * "byte2line(byte)" function
1340 */
1341 static void
1342f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1343{
1344#ifndef FEAT_BYTEOFF
1345 rettv->vval.v_number = -1;
1346#else
1347 long boff = 0;
1348
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001349 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001350 if (boff < 0)
1351 rettv->vval.v_number = -1;
1352 else
1353 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1354 (linenr_T)0, &boff);
1355#endif
1356}
1357
1358 static void
1359byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1360{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001361 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001362 char_u *str;
1363 varnumber_T idx;
1364
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001365 str = tv_get_string_chk(&argvars[0]);
1366 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001367 rettv->vval.v_number = -1;
1368 if (str == NULL || idx < 0)
1369 return;
1370
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001371 t = str;
1372 for ( ; idx > 0; idx--)
1373 {
1374 if (*t == NUL) /* EOL reached */
1375 return;
1376 if (enc_utf8 && comp)
1377 t += utf_ptr2len(t);
1378 else
1379 t += (*mb_ptr2len)(t);
1380 }
1381 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382}
1383
1384/*
1385 * "byteidx()" function
1386 */
1387 static void
1388f_byteidx(typval_T *argvars, typval_T *rettv)
1389{
1390 byteidx(argvars, rettv, FALSE);
1391}
1392
1393/*
1394 * "byteidxcomp()" function
1395 */
1396 static void
1397f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1398{
1399 byteidx(argvars, rettv, TRUE);
1400}
1401
1402/*
1403 * "call(func, arglist [, dict])" function
1404 */
1405 static void
1406f_call(typval_T *argvars, typval_T *rettv)
1407{
1408 char_u *func;
1409 partial_T *partial = NULL;
1410 dict_T *selfdict = NULL;
1411
1412 if (argvars[1].v_type != VAR_LIST)
1413 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001414 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001415 return;
1416 }
1417 if (argvars[1].vval.v_list == NULL)
1418 return;
1419
1420 if (argvars[0].v_type == VAR_FUNC)
1421 func = argvars[0].vval.v_string;
1422 else if (argvars[0].v_type == VAR_PARTIAL)
1423 {
1424 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001425 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001426 }
1427 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001428 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001429 if (*func == NUL)
1430 return; /* type error or empty name */
1431
1432 if (argvars[2].v_type != VAR_UNKNOWN)
1433 {
1434 if (argvars[2].v_type != VAR_DICT)
1435 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001436 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001437 return;
1438 }
1439 selfdict = argvars[2].vval.v_dict;
1440 }
1441
1442 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1443}
1444
1445#ifdef FEAT_FLOAT
1446/*
1447 * "ceil({float})" function
1448 */
1449 static void
1450f_ceil(typval_T *argvars, typval_T *rettv)
1451{
1452 float_T f = 0.0;
1453
1454 rettv->v_type = VAR_FLOAT;
1455 if (get_float_arg(argvars, &f) == OK)
1456 rettv->vval.v_float = ceil(f);
1457 else
1458 rettv->vval.v_float = 0.0;
1459}
1460#endif
1461
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001462/*
1463 * "changenr()" function
1464 */
1465 static void
1466f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1467{
1468 rettv->vval.v_number = curbuf->b_u_seq_cur;
1469}
1470
1471/*
1472 * "char2nr(string)" function
1473 */
1474 static void
1475f_char2nr(typval_T *argvars, typval_T *rettv)
1476{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001477 if (has_mbyte)
1478 {
1479 int utf8 = 0;
1480
1481 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001482 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483
1484 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001485 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001487 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001488 }
1489 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001490 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001491}
1492
1493/*
1494 * "cindent(lnum)" function
1495 */
1496 static void
1497f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1498{
1499#ifdef FEAT_CINDENT
1500 pos_T pos;
1501 linenr_T lnum;
1502
1503 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001504 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001505 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1506 {
1507 curwin->w_cursor.lnum = lnum;
1508 rettv->vval.v_number = get_c_indent();
1509 curwin->w_cursor = pos;
1510 }
1511 else
1512#endif
1513 rettv->vval.v_number = -1;
1514}
1515
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001516 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001517get_optional_window(typval_T *argvars, int idx)
1518{
1519 win_T *win = curwin;
1520
1521 if (argvars[idx].v_type != VAR_UNKNOWN)
1522 {
1523 win = find_win_by_nr_or_id(&argvars[idx]);
1524 if (win == NULL)
1525 {
1526 emsg(_(e_invalwindow));
1527 return NULL;
1528 }
1529 }
1530 return win;
1531}
1532
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001534 * "col(string)" function
1535 */
1536 static void
1537f_col(typval_T *argvars, typval_T *rettv)
1538{
1539 colnr_T col = 0;
1540 pos_T *fp;
1541 int fnum = curbuf->b_fnum;
1542
1543 fp = var2fpos(&argvars[0], FALSE, &fnum);
1544 if (fp != NULL && fnum == curbuf->b_fnum)
1545 {
1546 if (fp->col == MAXCOL)
1547 {
1548 /* '> can be MAXCOL, get the length of the line then */
1549 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1550 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1551 else
1552 col = MAXCOL;
1553 }
1554 else
1555 {
1556 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001557 /* col(".") when the cursor is on the NUL at the end of the line
1558 * because of "coladd" can be seen as an extra column. */
1559 if (virtual_active() && fp == &curwin->w_cursor)
1560 {
1561 char_u *p = ml_get_cursor();
1562
1563 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1564 curwin->w_virtcol - curwin->w_cursor.coladd))
1565 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001566 int l;
1567
1568 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1569 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 }
1571 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001572 }
1573 }
1574 rettv->vval.v_number = col;
1575}
1576
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001577/*
1578 * "confirm(message, buttons[, default [, type]])" function
1579 */
1580 static void
1581f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1582{
1583#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1584 char_u *message;
1585 char_u *buttons = NULL;
1586 char_u buf[NUMBUFLEN];
1587 char_u buf2[NUMBUFLEN];
1588 int def = 1;
1589 int type = VIM_GENERIC;
1590 char_u *typestr;
1591 int error = FALSE;
1592
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001593 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001594 if (message == NULL)
1595 error = TRUE;
1596 if (argvars[1].v_type != VAR_UNKNOWN)
1597 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001598 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001599 if (buttons == NULL)
1600 error = TRUE;
1601 if (argvars[2].v_type != VAR_UNKNOWN)
1602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001603 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001604 if (argvars[3].v_type != VAR_UNKNOWN)
1605 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001606 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607 if (typestr == NULL)
1608 error = TRUE;
1609 else
1610 {
1611 switch (TOUPPER_ASC(*typestr))
1612 {
1613 case 'E': type = VIM_ERROR; break;
1614 case 'Q': type = VIM_QUESTION; break;
1615 case 'I': type = VIM_INFO; break;
1616 case 'W': type = VIM_WARNING; break;
1617 case 'G': type = VIM_GENERIC; break;
1618 }
1619 }
1620 }
1621 }
1622 }
1623
1624 if (buttons == NULL || *buttons == NUL)
1625 buttons = (char_u *)_("&Ok");
1626
1627 if (!error)
1628 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1629 def, NULL, FALSE);
1630#endif
1631}
1632
1633/*
1634 * "copy()" function
1635 */
1636 static void
1637f_copy(typval_T *argvars, typval_T *rettv)
1638{
1639 item_copy(&argvars[0], rettv, FALSE, 0);
1640}
1641
1642#ifdef FEAT_FLOAT
1643/*
1644 * "cos()" function
1645 */
1646 static void
1647f_cos(typval_T *argvars, typval_T *rettv)
1648{
1649 float_T f = 0.0;
1650
1651 rettv->v_type = VAR_FLOAT;
1652 if (get_float_arg(argvars, &f) == OK)
1653 rettv->vval.v_float = cos(f);
1654 else
1655 rettv->vval.v_float = 0.0;
1656}
1657
1658/*
1659 * "cosh()" function
1660 */
1661 static void
1662f_cosh(typval_T *argvars, typval_T *rettv)
1663{
1664 float_T f = 0.0;
1665
1666 rettv->v_type = VAR_FLOAT;
1667 if (get_float_arg(argvars, &f) == OK)
1668 rettv->vval.v_float = cosh(f);
1669 else
1670 rettv->vval.v_float = 0.0;
1671}
1672#endif
1673
1674/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001675 * "cursor(lnum, col)" function, or
1676 * "cursor(list)"
1677 *
1678 * Moves the cursor to the specified line and column.
1679 * Returns 0 when the position could be set, -1 otherwise.
1680 */
1681 static void
1682f_cursor(typval_T *argvars, typval_T *rettv)
1683{
1684 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001686 int set_curswant = TRUE;
1687
1688 rettv->vval.v_number = -1;
1689 if (argvars[1].v_type == VAR_UNKNOWN)
1690 {
1691 pos_T pos;
1692 colnr_T curswant = -1;
1693
1694 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1695 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001696 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001697 return;
1698 }
1699 line = pos.lnum;
1700 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001701 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001702 if (curswant >= 0)
1703 {
1704 curwin->w_curswant = curswant - 1;
1705 set_curswant = FALSE;
1706 }
1707 }
1708 else
1709 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001710 line = tv_get_lnum(argvars);
1711 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001713 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001715 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 return; /* type error; errmsg already given */
1717 if (line > 0)
1718 curwin->w_cursor.lnum = line;
1719 if (col > 0)
1720 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001721 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001722
1723 /* Make sure the cursor is in a valid position. */
1724 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 /* Correct cursor for multi-byte character. */
1726 if (has_mbyte)
1727 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728
1729 curwin->w_set_curswant = set_curswant;
1730 rettv->vval.v_number = 0;
1731}
1732
Bram Moolenaar4f974752019-02-17 17:44:42 +01001733#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001734/*
1735 * "debugbreak()" function
1736 */
1737 static void
1738f_debugbreak(typval_T *argvars, typval_T *rettv)
1739{
1740 int pid;
1741
1742 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001743 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001744 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001745 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001746 else
1747 {
1748 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1749
1750 if (hProcess != NULL)
1751 {
1752 DebugBreakProcess(hProcess);
1753 CloseHandle(hProcess);
1754 rettv->vval.v_number = OK;
1755 }
1756 }
1757}
1758#endif
1759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001760/*
1761 * "deepcopy()" function
1762 */
1763 static void
1764f_deepcopy(typval_T *argvars, typval_T *rettv)
1765{
1766 int noref = 0;
1767 int copyID;
1768
1769 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001770 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001771 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001772 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001773 else
1774 {
1775 copyID = get_copyID();
1776 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1777 }
1778}
1779
1780/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001781 * "did_filetype()" function
1782 */
1783 static void
1784f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1785{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001786 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001787}
1788
1789/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001790 * "empty({expr})" function
1791 */
1792 static void
1793f_empty(typval_T *argvars, typval_T *rettv)
1794{
1795 int n = FALSE;
1796
1797 switch (argvars[0].v_type)
1798 {
1799 case VAR_STRING:
1800 case VAR_FUNC:
1801 n = argvars[0].vval.v_string == NULL
1802 || *argvars[0].vval.v_string == NUL;
1803 break;
1804 case VAR_PARTIAL:
1805 n = FALSE;
1806 break;
1807 case VAR_NUMBER:
1808 n = argvars[0].vval.v_number == 0;
1809 break;
1810 case VAR_FLOAT:
1811#ifdef FEAT_FLOAT
1812 n = argvars[0].vval.v_float == 0.0;
1813 break;
1814#endif
1815 case VAR_LIST:
1816 n = argvars[0].vval.v_list == NULL
1817 || argvars[0].vval.v_list->lv_first == NULL;
1818 break;
1819 case VAR_DICT:
1820 n = argvars[0].vval.v_dict == NULL
1821 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1822 break;
1823 case VAR_SPECIAL:
1824 n = argvars[0].vval.v_number != VVAL_TRUE;
1825 break;
1826
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001827 case VAR_BLOB:
1828 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001829 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1830 break;
1831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001832 case VAR_JOB:
1833#ifdef FEAT_JOB_CHANNEL
1834 n = argvars[0].vval.v_job == NULL
1835 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1836 break;
1837#endif
1838 case VAR_CHANNEL:
1839#ifdef FEAT_JOB_CHANNEL
1840 n = argvars[0].vval.v_channel == NULL
1841 || !channel_is_open(argvars[0].vval.v_channel);
1842 break;
1843#endif
1844 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001845 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001846 n = TRUE;
1847 break;
1848 }
1849
1850 rettv->vval.v_number = n;
1851}
1852
1853/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001854 * "environ()" function
1855 */
1856 static void
1857f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1858{
1859#if !defined(AMIGA)
1860 int i = 0;
1861 char_u *entry, *value;
1862# ifdef MSWIN
1863 extern wchar_t **_wenviron;
1864# else
1865 extern char **environ;
1866# endif
1867
1868 if (rettv_dict_alloc(rettv) != OK)
1869 return;
1870
1871# ifdef MSWIN
1872 if (*_wenviron == NULL)
1873 return;
1874# else
1875 if (*environ == NULL)
1876 return;
1877# endif
1878
1879 for (i = 0; ; ++i)
1880 {
1881# ifdef MSWIN
1882 short_u *p;
1883
1884 if ((p = (short_u *)_wenviron[i]) == NULL)
1885 return;
1886 entry = utf16_to_enc(p, NULL);
1887# else
1888 if ((entry = (char_u *)environ[i]) == NULL)
1889 return;
1890 entry = vim_strsave(entry);
1891# endif
1892 if (entry == NULL) // out of memory
1893 return;
1894 if ((value = vim_strchr(entry, '=')) == NULL)
1895 {
1896 vim_free(entry);
1897 continue;
1898 }
1899 *value++ = NUL;
1900 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1901 vim_free(entry);
1902 }
1903#endif
1904}
1905
1906/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001907 * "escape({string}, {chars})" function
1908 */
1909 static void
1910f_escape(typval_T *argvars, typval_T *rettv)
1911{
1912 char_u buf[NUMBUFLEN];
1913
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001914 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1915 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001916 rettv->v_type = VAR_STRING;
1917}
1918
1919/*
1920 * "eval()" function
1921 */
1922 static void
1923f_eval(typval_T *argvars, typval_T *rettv)
1924{
1925 char_u *s, *p;
1926
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001927 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 if (s != NULL)
1929 s = skipwhite(s);
1930
1931 p = s;
1932 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1933 {
1934 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001935 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001936 need_clr_eos = FALSE;
1937 rettv->v_type = VAR_NUMBER;
1938 rettv->vval.v_number = 0;
1939 }
1940 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001941 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001942}
1943
1944/*
1945 * "eventhandler()" function
1946 */
1947 static void
1948f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1949{
1950 rettv->vval.v_number = vgetc_busy;
1951}
1952
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001953static garray_T redir_execute_ga;
1954
1955/*
1956 * Append "value[value_len]" to the execute() output.
1957 */
1958 void
1959execute_redir_str(char_u *value, int value_len)
1960{
1961 int len;
1962
1963 if (value_len == -1)
1964 len = (int)STRLEN(value); /* Append the entire string */
1965 else
1966 len = value_len; /* Append only "value_len" characters */
1967 if (ga_grow(&redir_execute_ga, len) == OK)
1968 {
1969 mch_memmove((char *)redir_execute_ga.ga_data
1970 + redir_execute_ga.ga_len, value, len);
1971 redir_execute_ga.ga_len += len;
1972 }
1973}
1974
1975/*
1976 * Get next line from a list.
1977 * Called by do_cmdline() to get the next line.
1978 * Returns allocated string, or NULL for end of function.
1979 */
1980
1981 static char_u *
1982get_list_line(
1983 int c UNUSED,
1984 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001985 int indent UNUSED,
1986 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987{
1988 listitem_T **p = (listitem_T **)cookie;
1989 listitem_T *item = *p;
1990 char_u buf[NUMBUFLEN];
1991 char_u *s;
1992
1993 if (item == NULL)
1994 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001995 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001996 *p = item->li_next;
1997 return s == NULL ? NULL : vim_strsave(s);
1998}
1999
2000/*
2001 * "execute()" function
2002 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002003 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002004execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002005{
2006 char_u *cmd = NULL;
2007 list_T *list = NULL;
2008 int save_msg_silent = msg_silent;
2009 int save_emsg_silent = emsg_silent;
2010 int save_emsg_noredir = emsg_noredir;
2011 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002012 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002013 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002014 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002015 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002016
2017 rettv->vval.v_string = NULL;
2018 rettv->v_type = VAR_STRING;
2019
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002020 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002021 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002022 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002023 if (list == NULL || list->lv_first == NULL)
2024 /* empty list, no commands, empty output */
2025 return;
2026 ++list->lv_refcount;
2027 }
2028 else
2029 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002030 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002031 if (cmd == NULL)
2032 return;
2033 }
2034
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002035 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002036 {
2037 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002038 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039
2040 if (s == NULL)
2041 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002042 if (*s == NUL)
2043 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002044 if (STRNCMP(s, "silent", 6) == 0)
2045 ++msg_silent;
2046 if (STRCMP(s, "silent!") == 0)
2047 {
2048 emsg_silent = TRUE;
2049 emsg_noredir = TRUE;
2050 }
2051 }
2052 else
2053 ++msg_silent;
2054
2055 if (redir_execute)
2056 save_ga = redir_execute_ga;
2057 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2058 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002059 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002060 if (!echo_output)
2061 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002062
2063 if (cmd != NULL)
2064 do_cmdline_cmd(cmd);
2065 else
2066 {
2067 listitem_T *item = list->lv_first;
2068
2069 do_cmdline(NULL, get_list_line, (void *)&item,
2070 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2071 --list->lv_refcount;
2072 }
2073
Bram Moolenaard297f352017-01-29 20:31:21 +01002074 /* Need to append a NUL to the result. */
2075 if (ga_grow(&redir_execute_ga, 1) == OK)
2076 {
2077 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2078 rettv->vval.v_string = redir_execute_ga.ga_data;
2079 }
2080 else
2081 {
2082 ga_clear(&redir_execute_ga);
2083 rettv->vval.v_string = NULL;
2084 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002085 msg_silent = save_msg_silent;
2086 emsg_silent = save_emsg_silent;
2087 emsg_noredir = save_emsg_noredir;
2088
2089 redir_execute = save_redir_execute;
2090 if (redir_execute)
2091 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002092 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002094 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002095 if (echo_output)
2096 // When not working silently: put it in column zero. A following
2097 // "echon" will overwrite the message, unavoidably.
2098 msg_col = 0;
2099 else
2100 // When working silently: Put it back where it was, since nothing
2101 // should have been written.
2102 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002103}
2104
2105/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002106 * "execute()" function
2107 */
2108 static void
2109f_execute(typval_T *argvars, typval_T *rettv)
2110{
2111 execute_common(argvars, rettv, 0);
2112}
2113
2114/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002115 * "exists()" function
2116 */
2117 static void
2118f_exists(typval_T *argvars, typval_T *rettv)
2119{
2120 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002121 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002123 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002124 if (*p == '$') /* environment variable */
2125 {
2126 /* first try "normal" environment variables (fast) */
2127 if (mch_getenv(p + 1) != NULL)
2128 n = TRUE;
2129 else
2130 {
2131 /* try expanding things like $VIM and ${HOME} */
2132 p = expand_env_save(p);
2133 if (p != NULL && *p != '$')
2134 n = TRUE;
2135 vim_free(p);
2136 }
2137 }
2138 else if (*p == '&' || *p == '+') /* option */
2139 {
2140 n = (get_option_tv(&p, NULL, TRUE) == OK);
2141 if (*skipwhite(p) != NUL)
2142 n = FALSE; /* trailing garbage */
2143 }
2144 else if (*p == '*') /* internal or user defined function */
2145 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002146 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147 }
2148 else if (*p == ':')
2149 {
2150 n = cmd_exists(p + 1);
2151 }
2152 else if (*p == '#')
2153 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 if (p[1] == '#')
2155 n = autocmd_supported(p + 2);
2156 else
2157 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 }
2159 else /* internal variable */
2160 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002161 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002162 }
2163
2164 rettv->vval.v_number = n;
2165}
2166
2167#ifdef FEAT_FLOAT
2168/*
2169 * "exp()" function
2170 */
2171 static void
2172f_exp(typval_T *argvars, typval_T *rettv)
2173{
2174 float_T f = 0.0;
2175
2176 rettv->v_type = VAR_FLOAT;
2177 if (get_float_arg(argvars, &f) == OK)
2178 rettv->vval.v_float = exp(f);
2179 else
2180 rettv->vval.v_float = 0.0;
2181}
2182#endif
2183
2184/*
2185 * "expand()" function
2186 */
2187 static void
2188f_expand(typval_T *argvars, typval_T *rettv)
2189{
2190 char_u *s;
2191 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002192 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002193 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2194 expand_T xpc;
2195 int error = FALSE;
2196 char_u *result;
2197
2198 rettv->v_type = VAR_STRING;
2199 if (argvars[1].v_type != VAR_UNKNOWN
2200 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002201 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002202 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002203 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002205 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002206 if (*s == '%' || *s == '#' || *s == '<')
2207 {
2208 ++emsg_off;
2209 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2210 --emsg_off;
2211 if (rettv->v_type == VAR_LIST)
2212 {
2213 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2214 list_append_string(rettv->vval.v_list, result, -1);
2215 else
2216 vim_free(result);
2217 }
2218 else
2219 rettv->vval.v_string = result;
2220 }
2221 else
2222 {
2223 /* When the optional second argument is non-zero, don't remove matches
2224 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2225 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002226 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002227 options |= WILD_KEEP_ALL;
2228 if (!error)
2229 {
2230 ExpandInit(&xpc);
2231 xpc.xp_context = EXPAND_FILES;
2232 if (p_wic)
2233 options += WILD_ICASE;
2234 if (rettv->v_type == VAR_STRING)
2235 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2236 options, WILD_ALL);
2237 else if (rettv_list_alloc(rettv) != FAIL)
2238 {
2239 int i;
2240
2241 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2242 for (i = 0; i < xpc.xp_numfiles; i++)
2243 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2244 ExpandCleanup(&xpc);
2245 }
2246 }
2247 else
2248 rettv->vval.v_string = NULL;
2249 }
2250}
2251
2252/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002253 * "expandcmd()" function
2254 * Expand all the special characters in a command string.
2255 */
2256 static void
2257f_expandcmd(typval_T *argvars, typval_T *rettv)
2258{
2259 exarg_T eap;
2260 char_u *cmdstr;
2261 char *errormsg = NULL;
2262
2263 rettv->v_type = VAR_STRING;
2264 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2265
2266 memset(&eap, 0, sizeof(eap));
2267 eap.cmd = cmdstr;
2268 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002269 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002270 eap.usefilter = FALSE;
2271 eap.nextcmd = NULL;
2272 eap.cmdidx = CMD_USER;
2273
2274 expand_filename(&eap, &cmdstr, &errormsg);
2275 if (errormsg != NULL && *errormsg != NUL)
2276 emsg(errormsg);
2277
2278 rettv->vval.v_string = cmdstr;
2279}
2280
2281/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002282 * "feedkeys()" function
2283 */
2284 static void
2285f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2286{
2287 int remap = TRUE;
2288 int insert = FALSE;
2289 char_u *keys, *flags;
2290 char_u nbuf[NUMBUFLEN];
2291 int typed = FALSE;
2292 int execute = FALSE;
2293 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002294 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002295 char_u *keys_esc;
2296
2297 /* This is not allowed in the sandbox. If the commands would still be
2298 * executed in the sandbox it would be OK, but it probably happens later,
2299 * when "sandbox" is no longer set. */
2300 if (check_secure())
2301 return;
2302
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002303 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002304
2305 if (argvars[1].v_type != VAR_UNKNOWN)
2306 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002307 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002308 for ( ; *flags != NUL; ++flags)
2309 {
2310 switch (*flags)
2311 {
2312 case 'n': remap = FALSE; break;
2313 case 'm': remap = TRUE; break;
2314 case 't': typed = TRUE; break;
2315 case 'i': insert = TRUE; break;
2316 case 'x': execute = TRUE; break;
2317 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002318 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002319 }
2320 }
2321 }
2322
2323 if (*keys != NUL || execute)
2324 {
2325 /* Need to escape K_SPECIAL and CSI before putting the string in the
2326 * typeahead buffer. */
2327 keys_esc = vim_strsave_escape_csi(keys);
2328 if (keys_esc != NULL)
2329 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002330 if (lowlevel)
2331 {
2332#ifdef USE_INPUT_BUF
2333 add_to_input_buf(keys, (int)STRLEN(keys));
2334#else
2335 emsg(_("E980: lowlevel input not supported"));
2336#endif
2337 }
2338 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002339 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002340 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002341 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002342 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002343#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002344 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002345#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002346 )
2347 typebuf_was_filled = TRUE;
2348 }
2349 vim_free(keys_esc);
2350
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002351 if (execute)
2352 {
2353 int save_msg_scroll = msg_scroll;
2354
2355 /* Avoid a 1 second delay when the keys start Insert mode. */
2356 msg_scroll = FALSE;
2357
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002358 if (!dangerous)
2359 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002360 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002361 if (!dangerous)
2362 --ex_normal_busy;
2363
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 msg_scroll |= save_msg_scroll;
2365 }
2366 }
2367 }
2368}
2369
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002370#ifdef FEAT_FLOAT
2371/*
2372 * "float2nr({float})" function
2373 */
2374 static void
2375f_float2nr(typval_T *argvars, typval_T *rettv)
2376{
2377 float_T f = 0.0;
2378
2379 if (get_float_arg(argvars, &f) == OK)
2380 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002381 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002382 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002383 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002384 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002385 else
2386 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002387 }
2388}
2389
2390/*
2391 * "floor({float})" function
2392 */
2393 static void
2394f_floor(typval_T *argvars, typval_T *rettv)
2395{
2396 float_T f = 0.0;
2397
2398 rettv->v_type = VAR_FLOAT;
2399 if (get_float_arg(argvars, &f) == OK)
2400 rettv->vval.v_float = floor(f);
2401 else
2402 rettv->vval.v_float = 0.0;
2403}
2404
2405/*
2406 * "fmod()" function
2407 */
2408 static void
2409f_fmod(typval_T *argvars, typval_T *rettv)
2410{
2411 float_T fx = 0.0, fy = 0.0;
2412
2413 rettv->v_type = VAR_FLOAT;
2414 if (get_float_arg(argvars, &fx) == OK
2415 && get_float_arg(&argvars[1], &fy) == OK)
2416 rettv->vval.v_float = fmod(fx, fy);
2417 else
2418 rettv->vval.v_float = 0.0;
2419}
2420#endif
2421
2422/*
2423 * "fnameescape({string})" function
2424 */
2425 static void
2426f_fnameescape(typval_T *argvars, typval_T *rettv)
2427{
2428 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002429 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002430 rettv->v_type = VAR_STRING;
2431}
2432
2433/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002434 * "foreground()" function
2435 */
2436 static void
2437f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2438{
2439#ifdef FEAT_GUI
2440 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002441 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002442 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002443 return;
2444 }
2445#endif
2446#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448#endif
2449}
2450
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002451 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002452common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002453{
2454 char_u *s;
2455 char_u *name;
2456 int use_string = FALSE;
2457 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002458 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459
2460 if (argvars[0].v_type == VAR_FUNC)
2461 {
2462 /* function(MyFunc, [arg], dict) */
2463 s = argvars[0].vval.v_string;
2464 }
2465 else if (argvars[0].v_type == VAR_PARTIAL
2466 && argvars[0].vval.v_partial != NULL)
2467 {
2468 /* function(dict.MyFunc, [arg]) */
2469 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002470 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002471 }
2472 else
2473 {
2474 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002475 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002476 use_string = TRUE;
2477 }
2478
Bram Moolenaar843b8842016-08-21 14:36:15 +02002479 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002480 {
2481 name = s;
2482 trans_name = trans_function_name(&name, FALSE,
2483 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2484 if (*name != NUL)
2485 s = NULL;
2486 }
2487
Bram Moolenaar843b8842016-08-21 14:36:15 +02002488 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2489 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002490 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002491 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002492 else if (trans_name != NULL && (is_funcref
2493 ? find_func(trans_name) == NULL
2494 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002495 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002496 else
2497 {
2498 int dict_idx = 0;
2499 int arg_idx = 0;
2500 list_T *list = NULL;
2501
2502 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2503 {
2504 char sid_buf[25];
2505 int off = *s == 's' ? 2 : 5;
2506
2507 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2508 * also be called from another script. Using trans_function_name()
2509 * would also work, but some plugins depend on the name being
2510 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002511 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002512 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002513 if (name != NULL)
2514 {
2515 STRCPY(name, sid_buf);
2516 STRCAT(name, s + off);
2517 }
2518 }
2519 else
2520 name = vim_strsave(s);
2521
2522 if (argvars[1].v_type != VAR_UNKNOWN)
2523 {
2524 if (argvars[2].v_type != VAR_UNKNOWN)
2525 {
2526 /* function(name, [args], dict) */
2527 arg_idx = 1;
2528 dict_idx = 2;
2529 }
2530 else if (argvars[1].v_type == VAR_DICT)
2531 /* function(name, dict) */
2532 dict_idx = 1;
2533 else
2534 /* function(name, [args]) */
2535 arg_idx = 1;
2536 if (dict_idx > 0)
2537 {
2538 if (argvars[dict_idx].v_type != VAR_DICT)
2539 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002540 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002542 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002543 }
2544 if (argvars[dict_idx].vval.v_dict == NULL)
2545 dict_idx = 0;
2546 }
2547 if (arg_idx > 0)
2548 {
2549 if (argvars[arg_idx].v_type != VAR_LIST)
2550 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002551 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002552 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002553 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002554 }
2555 list = argvars[arg_idx].vval.v_list;
2556 if (list == NULL || list->lv_len == 0)
2557 arg_idx = 0;
2558 }
2559 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002560 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002561 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002562 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002563
2564 /* result is a VAR_PARTIAL */
2565 if (pt == NULL)
2566 vim_free(name);
2567 else
2568 {
2569 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2570 {
2571 listitem_T *li;
2572 int i = 0;
2573 int arg_len = 0;
2574 int lv_len = 0;
2575
2576 if (arg_pt != NULL)
2577 arg_len = arg_pt->pt_argc;
2578 if (list != NULL)
2579 lv_len = list->lv_len;
2580 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002581 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002582 if (pt->pt_argv == NULL)
2583 {
2584 vim_free(pt);
2585 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002586 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002588 for (i = 0; i < arg_len; i++)
2589 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2590 if (lv_len > 0)
2591 for (li = list->lv_first; li != NULL;
2592 li = li->li_next)
2593 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002594 }
2595
2596 /* For "function(dict.func, [], dict)" and "func" is a partial
2597 * use "dict". That is backwards compatible. */
2598 if (dict_idx > 0)
2599 {
2600 /* The dict is bound explicitly, pt_auto is FALSE. */
2601 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2602 ++pt->pt_dict->dv_refcount;
2603 }
2604 else if (arg_pt != NULL)
2605 {
2606 /* If the dict was bound automatically the result is also
2607 * bound automatically. */
2608 pt->pt_dict = arg_pt->pt_dict;
2609 pt->pt_auto = arg_pt->pt_auto;
2610 if (pt->pt_dict != NULL)
2611 ++pt->pt_dict->dv_refcount;
2612 }
2613
2614 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002615 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2616 {
2617 pt->pt_func = arg_pt->pt_func;
2618 func_ptr_ref(pt->pt_func);
2619 vim_free(name);
2620 }
2621 else if (is_funcref)
2622 {
2623 pt->pt_func = find_func(trans_name);
2624 func_ptr_ref(pt->pt_func);
2625 vim_free(name);
2626 }
2627 else
2628 {
2629 pt->pt_name = name;
2630 func_ref(name);
2631 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002632 }
2633 rettv->v_type = VAR_PARTIAL;
2634 rettv->vval.v_partial = pt;
2635 }
2636 else
2637 {
2638 /* result is a VAR_FUNC */
2639 rettv->v_type = VAR_FUNC;
2640 rettv->vval.v_string = name;
2641 func_ref(name);
2642 }
2643 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002644theend:
2645 vim_free(trans_name);
2646}
2647
2648/*
2649 * "funcref()" function
2650 */
2651 static void
2652f_funcref(typval_T *argvars, typval_T *rettv)
2653{
2654 common_function(argvars, rettv, TRUE);
2655}
2656
2657/*
2658 * "function()" function
2659 */
2660 static void
2661f_function(typval_T *argvars, typval_T *rettv)
2662{
2663 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002664}
2665
2666/*
2667 * "garbagecollect()" function
2668 */
2669 static void
2670f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2671{
2672 /* This is postponed until we are back at the toplevel, because we may be
2673 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2674 want_garbage_collect = TRUE;
2675
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002676 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 garbage_collect_at_exit = TRUE;
2678}
2679
2680/*
2681 * "get()" function
2682 */
2683 static void
2684f_get(typval_T *argvars, typval_T *rettv)
2685{
2686 listitem_T *li;
2687 list_T *l;
2688 dictitem_T *di;
2689 dict_T *d;
2690 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002691 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002692
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002693 if (argvars[0].v_type == VAR_BLOB)
2694 {
2695 int error = FALSE;
2696 int idx = tv_get_number_chk(&argvars[1], &error);
2697
2698 if (!error)
2699 {
2700 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002701 if (idx < 0)
2702 idx = blob_len(argvars[0].vval.v_blob) + idx;
2703 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2704 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002705 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002706 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002707 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002708 tv = rettv;
2709 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002710 }
2711 }
2712 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002713 {
2714 if ((l = argvars[0].vval.v_list) != NULL)
2715 {
2716 int error = FALSE;
2717
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002718 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719 if (!error && li != NULL)
2720 tv = &li->li_tv;
2721 }
2722 }
2723 else if (argvars[0].v_type == VAR_DICT)
2724 {
2725 if ((d = argvars[0].vval.v_dict) != NULL)
2726 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002727 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728 if (di != NULL)
2729 tv = &di->di_tv;
2730 }
2731 }
2732 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2733 {
2734 partial_T *pt;
2735 partial_T fref_pt;
2736
2737 if (argvars[0].v_type == VAR_PARTIAL)
2738 pt = argvars[0].vval.v_partial;
2739 else
2740 {
2741 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2742 fref_pt.pt_name = argvars[0].vval.v_string;
2743 pt = &fref_pt;
2744 }
2745
2746 if (pt != NULL)
2747 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002748 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002749 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002750
2751 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2752 {
2753 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002754 n = partial_name(pt);
2755 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002756 rettv->vval.v_string = NULL;
2757 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002758 {
2759 rettv->vval.v_string = vim_strsave(n);
2760 if (rettv->v_type == VAR_FUNC)
2761 func_ref(rettv->vval.v_string);
2762 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002763 }
2764 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002765 {
2766 what_is_dict = TRUE;
2767 if (pt->pt_dict != NULL)
2768 rettv_dict_set(rettv, pt->pt_dict);
2769 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002770 else if (STRCMP(what, "args") == 0)
2771 {
2772 rettv->v_type = VAR_LIST;
2773 if (rettv_list_alloc(rettv) == OK)
2774 {
2775 int i;
2776
2777 for (i = 0; i < pt->pt_argc; ++i)
2778 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2779 }
2780 }
2781 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002782 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002783
2784 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2785 // third argument
2786 if (!what_is_dict)
2787 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002788 }
2789 }
2790 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002791 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002792
2793 if (tv == NULL)
2794 {
2795 if (argvars[2].v_type != VAR_UNKNOWN)
2796 copy_tv(&argvars[2], rettv);
2797 }
2798 else
2799 copy_tv(tv, rettv);
2800}
2801
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002802/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002803 * "getchangelist()" function
2804 */
2805 static void
2806f_getchangelist(typval_T *argvars, typval_T *rettv)
2807{
2808#ifdef FEAT_JUMPLIST
2809 buf_T *buf;
2810 int i;
2811 list_T *l;
2812 dict_T *d;
2813#endif
2814
2815 if (rettv_list_alloc(rettv) != OK)
2816 return;
2817
2818#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002819 if (argvars[0].v_type == VAR_UNKNOWN)
2820 buf = curbuf;
2821 else
2822 {
2823 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2824 ++emsg_off;
2825 buf = tv_get_buf(&argvars[0], FALSE);
2826 --emsg_off;
2827 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002828 if (buf == NULL)
2829 return;
2830
2831 l = list_alloc();
2832 if (l == NULL)
2833 return;
2834
2835 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2836 return;
2837 /*
2838 * The current window change list index tracks only the position in the
2839 * current buffer change list. For other buffers, use the change list
2840 * length as the current index.
2841 */
2842 list_append_number(rettv->vval.v_list,
2843 (varnumber_T)((buf == curwin->w_buffer)
2844 ? curwin->w_changelistidx : buf->b_changelistlen));
2845
2846 for (i = 0; i < buf->b_changelistlen; ++i)
2847 {
2848 if (buf->b_changelist[i].lnum == 0)
2849 continue;
2850 if ((d = dict_alloc()) == NULL)
2851 return;
2852 if (list_append_dict(l, d) == FAIL)
2853 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002854 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2855 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002856 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002857 }
2858#endif
2859}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002860
2861/*
2862 * "getcharsearch()" function
2863 */
2864 static void
2865f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2866{
2867 if (rettv_dict_alloc(rettv) != FAIL)
2868 {
2869 dict_T *dict = rettv->vval.v_dict;
2870
Bram Moolenaare0be1672018-07-08 16:50:37 +02002871 dict_add_string(dict, "char", last_csearch());
2872 dict_add_number(dict, "forward", last_csearch_forward());
2873 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002874 }
2875}
2876
2877/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002878 * "getcmdwintype()" function
2879 */
2880 static void
2881f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2882{
2883 rettv->v_type = VAR_STRING;
2884 rettv->vval.v_string = NULL;
2885#ifdef FEAT_CMDWIN
2886 rettv->vval.v_string = alloc(2);
2887 if (rettv->vval.v_string != NULL)
2888 {
2889 rettv->vval.v_string[0] = cmdwin_type;
2890 rettv->vval.v_string[1] = NUL;
2891 }
2892#endif
2893}
2894
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002895/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002896 * "getenv()" function
2897 */
2898 static void
2899f_getenv(typval_T *argvars, typval_T *rettv)
2900{
2901 int mustfree = FALSE;
2902 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2903
2904 if (p == NULL)
2905 {
2906 rettv->v_type = VAR_SPECIAL;
2907 rettv->vval.v_number = VVAL_NULL;
2908 return;
2909 }
2910 if (!mustfree)
2911 p = vim_strsave(p);
2912 rettv->vval.v_string = p;
2913 rettv->v_type = VAR_STRING;
2914}
2915
2916/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002917 * "getfontname()" function
2918 */
2919 static void
2920f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2921{
2922 rettv->v_type = VAR_STRING;
2923 rettv->vval.v_string = NULL;
2924#ifdef FEAT_GUI
2925 if (gui.in_use)
2926 {
2927 GuiFont font;
2928 char_u *name = NULL;
2929
2930 if (argvars[0].v_type == VAR_UNKNOWN)
2931 {
2932 /* Get the "Normal" font. Either the name saved by
2933 * hl_set_font_name() or from the font ID. */
2934 font = gui.norm_font;
2935 name = hl_get_font_name();
2936 }
2937 else
2938 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002939 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940 if (STRCMP(name, "*") == 0) /* don't use font dialog */
2941 return;
2942 font = gui_mch_get_font(name, FALSE);
2943 if (font == NOFONT)
2944 return; /* Invalid font name, return empty string. */
2945 }
2946 rettv->vval.v_string = gui_mch_get_fontname(font, name);
2947 if (argvars[0].v_type != VAR_UNKNOWN)
2948 gui_mch_free_font(font);
2949 }
2950#endif
2951}
2952
2953/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01002954 * "getjumplist()" function
2955 */
2956 static void
2957f_getjumplist(typval_T *argvars, typval_T *rettv)
2958{
2959#ifdef FEAT_JUMPLIST
2960 win_T *wp;
2961 int i;
2962 list_T *l;
2963 dict_T *d;
2964#endif
2965
2966 if (rettv_list_alloc(rettv) != OK)
2967 return;
2968
2969#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02002970 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002971 if (wp == NULL)
2972 return;
2973
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01002974 cleanup_jumplist(wp, TRUE);
2975
Bram Moolenaar4f505882018-02-10 21:06:32 +01002976 l = list_alloc();
2977 if (l == NULL)
2978 return;
2979
2980 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2981 return;
2982 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
2983
2984 for (i = 0; i < wp->w_jumplistlen; ++i)
2985 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002986 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
2987 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01002988 if ((d = dict_alloc()) == NULL)
2989 return;
2990 if (list_append_dict(l, d) == FAIL)
2991 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002992 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
2993 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002994 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002995 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002996 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02002997 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002998 }
2999#endif
3000}
3001
3002/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003003 * "getpid()" function
3004 */
3005 static void
3006f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3007{
3008 rettv->vval.v_number = mch_get_pid();
3009}
3010
3011 static void
3012getpos_both(
3013 typval_T *argvars,
3014 typval_T *rettv,
3015 int getcurpos)
3016{
3017 pos_T *fp;
3018 list_T *l;
3019 int fnum = -1;
3020
3021 if (rettv_list_alloc(rettv) == OK)
3022 {
3023 l = rettv->vval.v_list;
3024 if (getcurpos)
3025 fp = &curwin->w_cursor;
3026 else
3027 fp = var2fpos(&argvars[0], TRUE, &fnum);
3028 if (fnum != -1)
3029 list_append_number(l, (varnumber_T)fnum);
3030 else
3031 list_append_number(l, (varnumber_T)0);
3032 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3033 : (varnumber_T)0);
3034 list_append_number(l, (fp != NULL)
3035 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3036 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003037 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038 (varnumber_T)0);
3039 if (getcurpos)
3040 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003041 int save_set_curswant = curwin->w_set_curswant;
3042 colnr_T save_curswant = curwin->w_curswant;
3043 colnr_T save_virtcol = curwin->w_virtcol;
3044
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003045 update_curswant();
3046 list_append_number(l, curwin->w_curswant == MAXCOL ?
3047 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003048
3049 // Do not change "curswant", as it is unexpected that a get
3050 // function has a side effect.
3051 if (save_set_curswant)
3052 {
3053 curwin->w_set_curswant = save_set_curswant;
3054 curwin->w_curswant = save_curswant;
3055 curwin->w_virtcol = save_virtcol;
3056 curwin->w_valid &= ~VALID_VIRTCOL;
3057 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 }
3059 }
3060 else
3061 rettv->vval.v_number = FALSE;
3062}
3063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003064/*
3065 * "getcurpos()" function
3066 */
3067 static void
3068f_getcurpos(typval_T *argvars, typval_T *rettv)
3069{
3070 getpos_both(argvars, rettv, TRUE);
3071}
3072
3073/*
3074 * "getpos(string)" function
3075 */
3076 static void
3077f_getpos(typval_T *argvars, typval_T *rettv)
3078{
3079 getpos_both(argvars, rettv, FALSE);
3080}
3081
3082/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003083 * "getreg()" function
3084 */
3085 static void
3086f_getreg(typval_T *argvars, typval_T *rettv)
3087{
3088 char_u *strregname;
3089 int regname;
3090 int arg2 = FALSE;
3091 int return_list = FALSE;
3092 int error = FALSE;
3093
3094 if (argvars[0].v_type != VAR_UNKNOWN)
3095 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003096 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003097 error = strregname == NULL;
3098 if (argvars[1].v_type != VAR_UNKNOWN)
3099 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003100 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003101 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003102 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003103 }
3104 }
3105 else
3106 strregname = get_vim_var_str(VV_REG);
3107
3108 if (error)
3109 return;
3110
3111 regname = (strregname == NULL ? '"' : *strregname);
3112 if (regname == 0)
3113 regname = '"';
3114
3115 if (return_list)
3116 {
3117 rettv->v_type = VAR_LIST;
3118 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3119 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3120 if (rettv->vval.v_list == NULL)
3121 (void)rettv_list_alloc(rettv);
3122 else
3123 ++rettv->vval.v_list->lv_refcount;
3124 }
3125 else
3126 {
3127 rettv->v_type = VAR_STRING;
3128 rettv->vval.v_string = get_reg_contents(regname,
3129 arg2 ? GREG_EXPR_SRC : 0);
3130 }
3131}
3132
3133/*
3134 * "getregtype()" function
3135 */
3136 static void
3137f_getregtype(typval_T *argvars, typval_T *rettv)
3138{
3139 char_u *strregname;
3140 int regname;
3141 char_u buf[NUMBUFLEN + 2];
3142 long reglen = 0;
3143
3144 if (argvars[0].v_type != VAR_UNKNOWN)
3145 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003146 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003147 if (strregname == NULL) /* type error; errmsg already given */
3148 {
3149 rettv->v_type = VAR_STRING;
3150 rettv->vval.v_string = NULL;
3151 return;
3152 }
3153 }
3154 else
3155 /* Default to v:register */
3156 strregname = get_vim_var_str(VV_REG);
3157
3158 regname = (strregname == NULL ? '"' : *strregname);
3159 if (regname == 0)
3160 regname = '"';
3161
3162 buf[0] = NUL;
3163 buf[1] = NUL;
3164 switch (get_reg_type(regname, &reglen))
3165 {
3166 case MLINE: buf[0] = 'V'; break;
3167 case MCHAR: buf[0] = 'v'; break;
3168 case MBLOCK:
3169 buf[0] = Ctrl_V;
3170 sprintf((char *)buf + 1, "%ld", reglen + 1);
3171 break;
3172 }
3173 rettv->v_type = VAR_STRING;
3174 rettv->vval.v_string = vim_strsave(buf);
3175}
3176
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003177/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003178 * "gettagstack()" function
3179 */
3180 static void
3181f_gettagstack(typval_T *argvars, typval_T *rettv)
3182{
3183 win_T *wp = curwin; // default is current window
3184
3185 if (rettv_dict_alloc(rettv) != OK)
3186 return;
3187
3188 if (argvars[0].v_type != VAR_UNKNOWN)
3189 {
3190 wp = find_win_by_nr_or_id(&argvars[0]);
3191 if (wp == NULL)
3192 return;
3193 }
3194
3195 get_tagstack(wp, rettv->vval.v_dict);
3196}
3197
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003198/* for VIM_VERSION_ defines */
3199#include "version.h"
3200
3201/*
3202 * "has()" function
3203 */
3204 static void
3205f_has(typval_T *argvars, typval_T *rettv)
3206{
3207 int i;
3208 char_u *name;
3209 int n = FALSE;
3210 static char *(has_list[]) =
3211 {
3212#ifdef AMIGA
3213 "amiga",
3214# ifdef FEAT_ARP
3215 "arp",
3216# endif
3217#endif
3218#ifdef __BEOS__
3219 "beos",
3220#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003221#if defined(BSD) && !defined(MACOS_X)
3222 "bsd",
3223#endif
3224#ifdef hpux
3225 "hpux",
3226#endif
3227#ifdef __linux__
3228 "linux",
3229#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003230#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003231 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3232 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003233# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003234 "macunix", /* Mac OS X, with the darwin feature */
3235 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003236# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003237#endif
3238#ifdef __QNX__
3239 "qnx",
3240#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003241#ifdef SUN_SYSTEM
3242 "sun",
3243#else
3244 "moon",
3245#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003246#ifdef UNIX
3247 "unix",
3248#endif
3249#ifdef VMS
3250 "vms",
3251#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003252#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003253 "win32",
3254#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003255#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003256 "win32unix",
3257#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003258#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003259 "win64",
3260#endif
3261#ifdef EBCDIC
3262 "ebcdic",
3263#endif
3264#ifndef CASE_INSENSITIVE_FILENAME
3265 "fname_case",
3266#endif
3267#ifdef HAVE_ACL
3268 "acl",
3269#endif
3270#ifdef FEAT_ARABIC
3271 "arabic",
3272#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003273 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003274#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003275 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003276#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003277#ifdef FEAT_AUTOSERVERNAME
3278 "autoservername",
3279#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003280#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003281 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003282# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003283 "balloon_multiline",
3284# endif
3285#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003286#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003287 "balloon_eval_term",
3288#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003289#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3290 "builtin_terms",
3291# ifdef ALL_BUILTIN_TCAPS
3292 "all_builtin_terms",
3293# endif
3294#endif
3295#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003296 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003297 || defined(FEAT_GUI_MOTIF))
3298 "browsefilter",
3299#endif
3300#ifdef FEAT_BYTEOFF
3301 "byte_offset",
3302#endif
3303#ifdef FEAT_JOB_CHANNEL
3304 "channel",
3305#endif
3306#ifdef FEAT_CINDENT
3307 "cindent",
3308#endif
3309#ifdef FEAT_CLIENTSERVER
3310 "clientserver",
3311#endif
3312#ifdef FEAT_CLIPBOARD
3313 "clipboard",
3314#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003315 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317#ifdef FEAT_COMMENTS
3318 "comments",
3319#endif
3320#ifdef FEAT_CONCEAL
3321 "conceal",
3322#endif
3323#ifdef FEAT_CRYPT
3324 "cryptv",
3325 "crypt-blowfish",
3326 "crypt-blowfish2",
3327#endif
3328#ifdef FEAT_CSCOPE
3329 "cscope",
3330#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003331 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003332#ifdef CURSOR_SHAPE
3333 "cursorshape",
3334#endif
3335#ifdef DEBUG
3336 "debug",
3337#endif
3338#ifdef FEAT_CON_DIALOG
3339 "dialog_con",
3340#endif
3341#ifdef FEAT_GUI_DIALOG
3342 "dialog_gui",
3343#endif
3344#ifdef FEAT_DIFF
3345 "diff",
3346#endif
3347#ifdef FEAT_DIGRAPHS
3348 "digraphs",
3349#endif
3350#ifdef FEAT_DIRECTX
3351 "directx",
3352#endif
3353#ifdef FEAT_DND
3354 "dnd",
3355#endif
3356#ifdef FEAT_EMACS_TAGS
3357 "emacs_tags",
3358#endif
3359 "eval", /* always present, of course! */
3360 "ex_extra", /* graduated feature */
3361#ifdef FEAT_SEARCH_EXTRA
3362 "extra_search",
3363#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003364#ifdef FEAT_SEARCHPATH
3365 "file_in_path",
3366#endif
3367#ifdef FEAT_FILTERPIPE
3368 "filterpipe",
3369#endif
3370#ifdef FEAT_FIND_ID
3371 "find_in_path",
3372#endif
3373#ifdef FEAT_FLOAT
3374 "float",
3375#endif
3376#ifdef FEAT_FOLDING
3377 "folding",
3378#endif
3379#ifdef FEAT_FOOTER
3380 "footer",
3381#endif
3382#if !defined(USE_SYSTEM) && defined(UNIX)
3383 "fork",
3384#endif
3385#ifdef FEAT_GETTEXT
3386 "gettext",
3387#endif
3388#ifdef FEAT_GUI
3389 "gui",
3390#endif
3391#ifdef FEAT_GUI_ATHENA
3392# ifdef FEAT_GUI_NEXTAW
3393 "gui_neXtaw",
3394# else
3395 "gui_athena",
3396# endif
3397#endif
3398#ifdef FEAT_GUI_GTK
3399 "gui_gtk",
3400# ifdef USE_GTK3
3401 "gui_gtk3",
3402# else
3403 "gui_gtk2",
3404# endif
3405#endif
3406#ifdef FEAT_GUI_GNOME
3407 "gui_gnome",
3408#endif
3409#ifdef FEAT_GUI_MAC
3410 "gui_mac",
3411#endif
3412#ifdef FEAT_GUI_MOTIF
3413 "gui_motif",
3414#endif
3415#ifdef FEAT_GUI_PHOTON
3416 "gui_photon",
3417#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003418#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003419 "gui_win32",
3420#endif
3421#ifdef FEAT_HANGULIN
3422 "hangul_input",
3423#endif
3424#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3425 "iconv",
3426#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003427 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003428#ifdef FEAT_JOB_CHANNEL
3429 "job",
3430#endif
3431#ifdef FEAT_JUMPLIST
3432 "jumplist",
3433#endif
3434#ifdef FEAT_KEYMAP
3435 "keymap",
3436#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003437 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003438#ifdef FEAT_LANGMAP
3439 "langmap",
3440#endif
3441#ifdef FEAT_LIBCALL
3442 "libcall",
3443#endif
3444#ifdef FEAT_LINEBREAK
3445 "linebreak",
3446#endif
3447#ifdef FEAT_LISP
3448 "lispindent",
3449#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003450 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003451 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003452#ifdef FEAT_LUA
3453# ifndef DYNAMIC_LUA
3454 "lua",
3455# endif
3456#endif
3457#ifdef FEAT_MENU
3458 "menu",
3459#endif
3460#ifdef FEAT_SESSION
3461 "mksession",
3462#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003463 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003464#ifdef FEAT_MOUSE
3465 "mouse",
3466#endif
3467#ifdef FEAT_MOUSESHAPE
3468 "mouseshape",
3469#endif
3470#if defined(UNIX) || defined(VMS)
3471# ifdef FEAT_MOUSE_DEC
3472 "mouse_dec",
3473# endif
3474# ifdef FEAT_MOUSE_GPM
3475 "mouse_gpm",
3476# endif
3477# ifdef FEAT_MOUSE_JSB
3478 "mouse_jsbterm",
3479# endif
3480# ifdef FEAT_MOUSE_NET
3481 "mouse_netterm",
3482# endif
3483# ifdef FEAT_MOUSE_PTERM
3484 "mouse_pterm",
3485# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003486# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003487 "mouse_sgr",
3488# endif
3489# ifdef FEAT_SYSMOUSE
3490 "mouse_sysmouse",
3491# endif
3492# ifdef FEAT_MOUSE_URXVT
3493 "mouse_urxvt",
3494# endif
3495# ifdef FEAT_MOUSE_XTERM
3496 "mouse_xterm",
3497# endif
3498#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003499 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003500#ifdef FEAT_MBYTE_IME
3501 "multi_byte_ime",
3502#endif
3503#ifdef FEAT_MULTI_LANG
3504 "multi_lang",
3505#endif
3506#ifdef FEAT_MZSCHEME
3507#ifndef DYNAMIC_MZSCHEME
3508 "mzscheme",
3509#endif
3510#endif
3511#ifdef FEAT_NUM64
3512 "num64",
3513#endif
3514#ifdef FEAT_OLE
3515 "ole",
3516#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003517#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003518 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003519#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520#ifdef FEAT_PATH_EXTRA
3521 "path_extra",
3522#endif
3523#ifdef FEAT_PERL
3524#ifndef DYNAMIC_PERL
3525 "perl",
3526#endif
3527#endif
3528#ifdef FEAT_PERSISTENT_UNDO
3529 "persistent_undo",
3530#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003531#if defined(FEAT_PYTHON)
3532 "python_compiled",
3533# if defined(DYNAMIC_PYTHON)
3534 "python_dynamic",
3535# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003536 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003537 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003538# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003539#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003540#if defined(FEAT_PYTHON3)
3541 "python3_compiled",
3542# if defined(DYNAMIC_PYTHON3)
3543 "python3_dynamic",
3544# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003545 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003546 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003547# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003548#endif
3549#ifdef FEAT_POSTSCRIPT
3550 "postscript",
3551#endif
3552#ifdef FEAT_PRINTER
3553 "printer",
3554#endif
3555#ifdef FEAT_PROFILE
3556 "profile",
3557#endif
3558#ifdef FEAT_RELTIME
3559 "reltime",
3560#endif
3561#ifdef FEAT_QUICKFIX
3562 "quickfix",
3563#endif
3564#ifdef FEAT_RIGHTLEFT
3565 "rightleft",
3566#endif
3567#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3568 "ruby",
3569#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003570 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003571#ifdef FEAT_CMDL_INFO
3572 "showcmd",
3573 "cmdline_info",
3574#endif
3575#ifdef FEAT_SIGNS
3576 "signs",
3577#endif
3578#ifdef FEAT_SMARTINDENT
3579 "smartindent",
3580#endif
3581#ifdef STARTUPTIME
3582 "startuptime",
3583#endif
3584#ifdef FEAT_STL_OPT
3585 "statusline",
3586#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003587#ifdef FEAT_NETBEANS_INTG
3588 "netbeans_intg",
3589#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003590#ifdef FEAT_SOUND
3591 "sound",
3592#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003593#ifdef FEAT_SPELL
3594 "spell",
3595#endif
3596#ifdef FEAT_SYN_HL
3597 "syntax",
3598#endif
3599#if defined(USE_SYSTEM) || !defined(UNIX)
3600 "system",
3601#endif
3602#ifdef FEAT_TAG_BINS
3603 "tag_binary",
3604#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003605#ifdef FEAT_TCL
3606# ifndef DYNAMIC_TCL
3607 "tcl",
3608# endif
3609#endif
3610#ifdef FEAT_TERMGUICOLORS
3611 "termguicolors",
3612#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003613#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003614 "terminal",
3615#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003616#ifdef TERMINFO
3617 "terminfo",
3618#endif
3619#ifdef FEAT_TERMRESPONSE
3620 "termresponse",
3621#endif
3622#ifdef FEAT_TEXTOBJ
3623 "textobjects",
3624#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003625#ifdef FEAT_TEXT_PROP
3626 "textprop",
3627#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003628#ifdef HAVE_TGETENT
3629 "tgetent",
3630#endif
3631#ifdef FEAT_TIMERS
3632 "timers",
3633#endif
3634#ifdef FEAT_TITLE
3635 "title",
3636#endif
3637#ifdef FEAT_TOOLBAR
3638 "toolbar",
3639#endif
3640#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3641 "unnamedplus",
3642#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643 "user-commands", /* was accidentally included in 5.4 */
3644 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003645#ifdef FEAT_VARTABS
3646 "vartabs",
3647#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003648 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649#ifdef FEAT_VIMINFO
3650 "viminfo",
3651#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003652 "vimscript-1",
3653 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003654 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003655 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003656 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003657 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003658 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003659 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003660#ifdef FEAT_VTP
3661 "vtp",
3662#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003663#ifdef FEAT_WILDIGN
3664 "wildignore",
3665#endif
3666#ifdef FEAT_WILDMENU
3667 "wildmenu",
3668#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003669 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003670#ifdef FEAT_WAK
3671 "winaltkeys",
3672#endif
3673#ifdef FEAT_WRITEBACKUP
3674 "writebackup",
3675#endif
3676#ifdef FEAT_XIM
3677 "xim",
3678#endif
3679#ifdef FEAT_XFONTSET
3680 "xfontset",
3681#endif
3682#ifdef FEAT_XPM_W32
3683 "xpm",
3684 "xpm_w32", /* for backward compatibility */
3685#else
3686# if defined(HAVE_XPM)
3687 "xpm",
3688# endif
3689#endif
3690#ifdef USE_XSMP
3691 "xsmp",
3692#endif
3693#ifdef USE_XSMP_INTERACT
3694 "xsmp_interact",
3695#endif
3696#ifdef FEAT_XCLIPBOARD
3697 "xterm_clipboard",
3698#endif
3699#ifdef FEAT_XTERM_SAVE
3700 "xterm_save",
3701#endif
3702#if defined(UNIX) && defined(FEAT_X11)
3703 "X11",
3704#endif
3705 NULL
3706 };
3707
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003708 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003709 for (i = 0; has_list[i] != NULL; ++i)
3710 if (STRICMP(name, has_list[i]) == 0)
3711 {
3712 n = TRUE;
3713 break;
3714 }
3715
3716 if (n == FALSE)
3717 {
3718 if (STRNICMP(name, "patch", 5) == 0)
3719 {
3720 if (name[5] == '-'
3721 && STRLEN(name) >= 11
3722 && vim_isdigit(name[6])
3723 && vim_isdigit(name[8])
3724 && vim_isdigit(name[10]))
3725 {
3726 int major = atoi((char *)name + 6);
3727 int minor = atoi((char *)name + 8);
3728
3729 /* Expect "patch-9.9.01234". */
3730 n = (major < VIM_VERSION_MAJOR
3731 || (major == VIM_VERSION_MAJOR
3732 && (minor < VIM_VERSION_MINOR
3733 || (minor == VIM_VERSION_MINOR
3734 && has_patch(atoi((char *)name + 10))))));
3735 }
3736 else
3737 n = has_patch(atoi((char *)name + 5));
3738 }
3739 else if (STRICMP(name, "vim_starting") == 0)
3740 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003741 else if (STRICMP(name, "ttyin") == 0)
3742 n = mch_input_isatty();
3743 else if (STRICMP(name, "ttyout") == 0)
3744 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003745 else if (STRICMP(name, "multi_byte_encoding") == 0)
3746 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003747#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003748 else if (STRICMP(name, "balloon_multiline") == 0)
3749 n = multiline_balloon_available();
3750#endif
3751#ifdef DYNAMIC_TCL
3752 else if (STRICMP(name, "tcl") == 0)
3753 n = tcl_enabled(FALSE);
3754#endif
3755#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3756 else if (STRICMP(name, "iconv") == 0)
3757 n = iconv_enabled(FALSE);
3758#endif
3759#ifdef DYNAMIC_LUA
3760 else if (STRICMP(name, "lua") == 0)
3761 n = lua_enabled(FALSE);
3762#endif
3763#ifdef DYNAMIC_MZSCHEME
3764 else if (STRICMP(name, "mzscheme") == 0)
3765 n = mzscheme_enabled(FALSE);
3766#endif
3767#ifdef DYNAMIC_RUBY
3768 else if (STRICMP(name, "ruby") == 0)
3769 n = ruby_enabled(FALSE);
3770#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003771#ifdef DYNAMIC_PYTHON
3772 else if (STRICMP(name, "python") == 0)
3773 n = python_enabled(FALSE);
3774#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775#ifdef DYNAMIC_PYTHON3
3776 else if (STRICMP(name, "python3") == 0)
3777 n = python3_enabled(FALSE);
3778#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003779#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3780 else if (STRICMP(name, "pythonx") == 0)
3781 {
3782# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3783 if (p_pyx == 0)
3784 n = python3_enabled(FALSE) || python_enabled(FALSE);
3785 else if (p_pyx == 3)
3786 n = python3_enabled(FALSE);
3787 else if (p_pyx == 2)
3788 n = python_enabled(FALSE);
3789# elif defined(DYNAMIC_PYTHON)
3790 n = python_enabled(FALSE);
3791# elif defined(DYNAMIC_PYTHON3)
3792 n = python3_enabled(FALSE);
3793# endif
3794 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003795#endif
3796#ifdef DYNAMIC_PERL
3797 else if (STRICMP(name, "perl") == 0)
3798 n = perl_enabled(FALSE);
3799#endif
3800#ifdef FEAT_GUI
3801 else if (STRICMP(name, "gui_running") == 0)
3802 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003803# ifdef FEAT_BROWSE
3804 else if (STRICMP(name, "browse") == 0)
3805 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3806# endif
3807#endif
3808#ifdef FEAT_SYN_HL
3809 else if (STRICMP(name, "syntax_items") == 0)
3810 n = syntax_present(curwin);
3811#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003812#ifdef FEAT_VTP
3813 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003814 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003815#endif
3816#ifdef FEAT_NETBEANS_INTG
3817 else if (STRICMP(name, "netbeans_enabled") == 0)
3818 n = netbeans_active();
3819#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003820#ifdef FEAT_MOUSE_GPM
3821 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3822 n = gpm_enabled();
3823#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003824#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003825 else if (STRICMP(name, "terminal") == 0)
3826 n = terminal_enabled();
3827#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003828#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003829 else if (STRICMP(name, "conpty") == 0)
3830 n = use_conpty();
3831#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003832#ifdef FEAT_CLIPBOARD
3833 else if (STRICMP(name, "clipboard_working") == 0)
3834 n = clip_star.available;
3835#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003836 }
3837
3838 rettv->vval.v_number = n;
3839}
3840
3841/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003842 * "haslocaldir()" function
3843 */
3844 static void
3845f_haslocaldir(typval_T *argvars, typval_T *rettv)
3846{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003847 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003848 win_T *wp = NULL;
3849
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003850 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3851
3852 // Check for window-local and tab-local directories
3853 if (wp != NULL && wp->w_localdir != NULL)
3854 rettv->vval.v_number = 1;
3855 else if (tp != NULL && tp->tp_localdir != NULL)
3856 rettv->vval.v_number = 2;
3857 else
3858 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003859}
3860
3861/*
3862 * "hasmapto()" function
3863 */
3864 static void
3865f_hasmapto(typval_T *argvars, typval_T *rettv)
3866{
3867 char_u *name;
3868 char_u *mode;
3869 char_u buf[NUMBUFLEN];
3870 int abbr = FALSE;
3871
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003872 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003873 if (argvars[1].v_type == VAR_UNKNOWN)
3874 mode = (char_u *)"nvo";
3875 else
3876 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003877 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003878 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003879 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003880 }
3881
3882 if (map_to_exists(name, mode, abbr))
3883 rettv->vval.v_number = TRUE;
3884 else
3885 rettv->vval.v_number = FALSE;
3886}
3887
3888/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003889 * "highlightID(name)" function
3890 */
3891 static void
3892f_hlID(typval_T *argvars, typval_T *rettv)
3893{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003894 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003895}
3896
3897/*
3898 * "highlight_exists()" function
3899 */
3900 static void
3901f_hlexists(typval_T *argvars, typval_T *rettv)
3902{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003903 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003904}
3905
3906/*
3907 * "hostname()" function
3908 */
3909 static void
3910f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3911{
3912 char_u hostname[256];
3913
3914 mch_get_host_name(hostname, 256);
3915 rettv->v_type = VAR_STRING;
3916 rettv->vval.v_string = vim_strsave(hostname);
3917}
3918
3919/*
3920 * iconv() function
3921 */
3922 static void
3923f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3924{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003925 char_u buf1[NUMBUFLEN];
3926 char_u buf2[NUMBUFLEN];
3927 char_u *from, *to, *str;
3928 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003929
3930 rettv->v_type = VAR_STRING;
3931 rettv->vval.v_string = NULL;
3932
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003933 str = tv_get_string(&argvars[0]);
3934 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3935 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003936 vimconv.vc_type = CONV_NONE;
3937 convert_setup(&vimconv, from, to);
3938
3939 /* If the encodings are equal, no conversion needed. */
3940 if (vimconv.vc_type == CONV_NONE)
3941 rettv->vval.v_string = vim_strsave(str);
3942 else
3943 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
3944
3945 convert_setup(&vimconv, NULL, NULL);
3946 vim_free(from);
3947 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003948}
3949
3950/*
3951 * "indent()" function
3952 */
3953 static void
3954f_indent(typval_T *argvars, typval_T *rettv)
3955{
3956 linenr_T lnum;
3957
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003958 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003959 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3960 rettv->vval.v_number = get_indent_lnum(lnum);
3961 else
3962 rettv->vval.v_number = -1;
3963}
3964
3965/*
3966 * "index()" function
3967 */
3968 static void
3969f_index(typval_T *argvars, typval_T *rettv)
3970{
3971 list_T *l;
3972 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003973 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003974 long idx = 0;
3975 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003976 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003977
3978 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003979 if (argvars[0].v_type == VAR_BLOB)
3980 {
3981 typval_T tv;
3982 int start = 0;
3983
3984 if (argvars[2].v_type != VAR_UNKNOWN)
3985 {
3986 start = tv_get_number_chk(&argvars[2], &error);
3987 if (error)
3988 return;
3989 }
3990 b = argvars[0].vval.v_blob;
3991 if (b == NULL)
3992 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01003993 if (start < 0)
3994 {
3995 start = blob_len(b) + start;
3996 if (start < 0)
3997 start = 0;
3998 }
3999
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004000 for (idx = start; idx < blob_len(b); ++idx)
4001 {
4002 tv.v_type = VAR_NUMBER;
4003 tv.vval.v_number = blob_get(b, idx);
4004 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4005 {
4006 rettv->vval.v_number = idx;
4007 return;
4008 }
4009 }
4010 return;
4011 }
4012 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004014 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004015 return;
4016 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004017
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004018 l = argvars[0].vval.v_list;
4019 if (l != NULL)
4020 {
4021 item = l->lv_first;
4022 if (argvars[2].v_type != VAR_UNKNOWN)
4023 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004024 /* Start at specified item. Use the cached index that list_find()
4025 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004026 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004027 idx = l->lv_idx;
4028 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004029 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004030 if (error)
4031 item = NULL;
4032 }
4033
4034 for ( ; item != NULL; item = item->li_next, ++idx)
4035 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4036 {
4037 rettv->vval.v_number = idx;
4038 break;
4039 }
4040 }
4041}
4042
4043static int inputsecret_flag = 0;
4044
4045/*
4046 * "input()" function
4047 * Also handles inputsecret() when inputsecret is set.
4048 */
4049 static void
4050f_input(typval_T *argvars, typval_T *rettv)
4051{
4052 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4053}
4054
4055/*
4056 * "inputdialog()" function
4057 */
4058 static void
4059f_inputdialog(typval_T *argvars, typval_T *rettv)
4060{
4061#if defined(FEAT_GUI_TEXTDIALOG)
4062 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4063 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4064 {
4065 char_u *message;
4066 char_u buf[NUMBUFLEN];
4067 char_u *defstr = (char_u *)"";
4068
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004069 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004071 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004072 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4073 else
4074 IObuff[0] = NUL;
4075 if (message != NULL && defstr != NULL
4076 && do_dialog(VIM_QUESTION, NULL, message,
4077 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4078 rettv->vval.v_string = vim_strsave(IObuff);
4079 else
4080 {
4081 if (message != NULL && defstr != NULL
4082 && argvars[1].v_type != VAR_UNKNOWN
4083 && argvars[2].v_type != VAR_UNKNOWN)
4084 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004085 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004086 else
4087 rettv->vval.v_string = NULL;
4088 }
4089 rettv->v_type = VAR_STRING;
4090 }
4091 else
4092#endif
4093 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4094}
4095
4096/*
4097 * "inputlist()" function
4098 */
4099 static void
4100f_inputlist(typval_T *argvars, typval_T *rettv)
4101{
4102 listitem_T *li;
4103 int selected;
4104 int mouse_used;
4105
4106#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004107 /* While starting up, there is no place to enter text. When running tests
4108 * with --not-a-term we assume feedkeys() will be used. */
4109 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004110 return;
4111#endif
4112 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4113 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004114 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004115 return;
4116 }
4117
4118 msg_start();
4119 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4120 lines_left = Rows; /* avoid more prompt */
4121 msg_scroll = TRUE;
4122 msg_clr_eos();
4123
4124 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4125 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004126 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004127 msg_putchar('\n');
4128 }
4129
4130 /* Ask for choice. */
4131 selected = prompt_for_number(&mouse_used);
4132 if (mouse_used)
4133 selected -= lines_left;
4134
4135 rettv->vval.v_number = selected;
4136}
4137
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004138static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4139
4140/*
4141 * "inputrestore()" function
4142 */
4143 static void
4144f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4145{
4146 if (ga_userinput.ga_len > 0)
4147 {
4148 --ga_userinput.ga_len;
4149 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4150 + ga_userinput.ga_len);
4151 /* default return is zero == OK */
4152 }
4153 else if (p_verbose > 1)
4154 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004155 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156 rettv->vval.v_number = 1; /* Failed */
4157 }
4158}
4159
4160/*
4161 * "inputsave()" function
4162 */
4163 static void
4164f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4165{
4166 /* Add an entry to the stack of typeahead storage. */
4167 if (ga_grow(&ga_userinput, 1) == OK)
4168 {
4169 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4170 + ga_userinput.ga_len);
4171 ++ga_userinput.ga_len;
4172 /* default return is zero == OK */
4173 }
4174 else
4175 rettv->vval.v_number = 1; /* Failed */
4176}
4177
4178/*
4179 * "inputsecret()" function
4180 */
4181 static void
4182f_inputsecret(typval_T *argvars, typval_T *rettv)
4183{
4184 ++cmdline_star;
4185 ++inputsecret_flag;
4186 f_input(argvars, rettv);
4187 --cmdline_star;
4188 --inputsecret_flag;
4189}
4190
4191/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004192 * "invert(expr)" function
4193 */
4194 static void
4195f_invert(typval_T *argvars, typval_T *rettv)
4196{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004197 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004198}
4199
4200/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004201 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4202 * or it refers to a List or Dictionary that is locked.
4203 */
4204 static int
4205tv_islocked(typval_T *tv)
4206{
4207 return (tv->v_lock & VAR_LOCKED)
4208 || (tv->v_type == VAR_LIST
4209 && tv->vval.v_list != NULL
4210 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4211 || (tv->v_type == VAR_DICT
4212 && tv->vval.v_dict != NULL
4213 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4214}
4215
4216/*
4217 * "islocked()" function
4218 */
4219 static void
4220f_islocked(typval_T *argvars, typval_T *rettv)
4221{
4222 lval_T lv;
4223 char_u *end;
4224 dictitem_T *di;
4225
4226 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004227 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004228 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004229 if (end != NULL && lv.ll_name != NULL)
4230 {
4231 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004232 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004233 else
4234 {
4235 if (lv.ll_tv == NULL)
4236 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004237 di = find_var(lv.ll_name, NULL, TRUE);
4238 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004239 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004240 /* Consider a variable locked when:
4241 * 1. the variable itself is locked
4242 * 2. the value of the variable is locked.
4243 * 3. the List or Dict value is locked.
4244 */
4245 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4246 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247 }
4248 }
4249 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004250 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004251 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004252 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004253 else if (lv.ll_list != NULL)
4254 /* List item. */
4255 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4256 else
4257 /* Dictionary item. */
4258 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4259 }
4260 }
4261
4262 clear_lval(&lv);
4263}
4264
4265#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4266/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004267 * "isinf()" function
4268 */
4269 static void
4270f_isinf(typval_T *argvars, typval_T *rettv)
4271{
4272 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4273 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4274}
4275
4276/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004277 * "isnan()" function
4278 */
4279 static void
4280f_isnan(typval_T *argvars, typval_T *rettv)
4281{
4282 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4283 && isnan(argvars[0].vval.v_float);
4284}
4285#endif
4286
4287/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004288 * "last_buffer_nr()" function.
4289 */
4290 static void
4291f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4292{
4293 int n = 0;
4294 buf_T *buf;
4295
Bram Moolenaar29323592016-07-24 22:04:11 +02004296 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004297 if (n < buf->b_fnum)
4298 n = buf->b_fnum;
4299
4300 rettv->vval.v_number = n;
4301}
4302
4303/*
4304 * "len()" function
4305 */
4306 static void
4307f_len(typval_T *argvars, typval_T *rettv)
4308{
4309 switch (argvars[0].v_type)
4310 {
4311 case VAR_STRING:
4312 case VAR_NUMBER:
4313 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004314 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004315 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004316 case VAR_BLOB:
4317 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4318 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004319 case VAR_LIST:
4320 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4321 break;
4322 case VAR_DICT:
4323 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4324 break;
4325 case VAR_UNKNOWN:
4326 case VAR_SPECIAL:
4327 case VAR_FLOAT:
4328 case VAR_FUNC:
4329 case VAR_PARTIAL:
4330 case VAR_JOB:
4331 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004332 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004333 break;
4334 }
4335}
4336
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004337 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004338libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004339{
4340#ifdef FEAT_LIBCALL
4341 char_u *string_in;
4342 char_u **string_result;
4343 int nr_result;
4344#endif
4345
4346 rettv->v_type = type;
4347 if (type != VAR_NUMBER)
4348 rettv->vval.v_string = NULL;
4349
4350 if (check_restricted() || check_secure())
4351 return;
4352
4353#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004354 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004355 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4356 {
4357 string_in = NULL;
4358 if (argvars[2].v_type == VAR_STRING)
4359 string_in = argvars[2].vval.v_string;
4360 if (type == VAR_NUMBER)
4361 string_result = NULL;
4362 else
4363 string_result = &rettv->vval.v_string;
4364 if (mch_libcall(argvars[0].vval.v_string,
4365 argvars[1].vval.v_string,
4366 string_in,
4367 argvars[2].vval.v_number,
4368 string_result,
4369 &nr_result) == OK
4370 && type == VAR_NUMBER)
4371 rettv->vval.v_number = nr_result;
4372 }
4373#endif
4374}
4375
4376/*
4377 * "libcall()" function
4378 */
4379 static void
4380f_libcall(typval_T *argvars, typval_T *rettv)
4381{
4382 libcall_common(argvars, rettv, VAR_STRING);
4383}
4384
4385/*
4386 * "libcallnr()" function
4387 */
4388 static void
4389f_libcallnr(typval_T *argvars, typval_T *rettv)
4390{
4391 libcall_common(argvars, rettv, VAR_NUMBER);
4392}
4393
4394/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004395 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004396 */
4397 static void
4398f_line(typval_T *argvars, typval_T *rettv)
4399{
4400 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004401 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004402 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004403 int id;
4404 tabpage_T *tp;
4405 win_T *wp;
4406 win_T *save_curwin;
4407 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004408
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004409 if (argvars[1].v_type != VAR_UNKNOWN)
4410 {
4411 // use window specified in the second argument
4412 id = (int)tv_get_number(&argvars[1]);
4413 wp = win_id2wp_tp(id, &tp);
4414 if (wp != NULL && tp != NULL)
4415 {
4416 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4417 == OK)
4418 {
4419 check_cursor();
4420 fp = var2fpos(&argvars[0], TRUE, &fnum);
4421 }
4422 restore_win_noblock(save_curwin, save_curtab, TRUE);
4423 }
4424 }
4425 else
4426 // use current window
4427 fp = var2fpos(&argvars[0], TRUE, &fnum);
4428
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004429 if (fp != NULL)
4430 lnum = fp->lnum;
4431 rettv->vval.v_number = lnum;
4432}
4433
4434/*
4435 * "line2byte(lnum)" function
4436 */
4437 static void
4438f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4439{
4440#ifndef FEAT_BYTEOFF
4441 rettv->vval.v_number = -1;
4442#else
4443 linenr_T lnum;
4444
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004445 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004446 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4447 rettv->vval.v_number = -1;
4448 else
4449 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4450 if (rettv->vval.v_number >= 0)
4451 ++rettv->vval.v_number;
4452#endif
4453}
4454
4455/*
4456 * "lispindent(lnum)" function
4457 */
4458 static void
4459f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
4460{
4461#ifdef FEAT_LISP
4462 pos_T pos;
4463 linenr_T lnum;
4464
4465 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004466 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004467 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4468 {
4469 curwin->w_cursor.lnum = lnum;
4470 rettv->vval.v_number = get_lisp_indent();
4471 curwin->w_cursor = pos;
4472 }
4473 else
4474#endif
4475 rettv->vval.v_number = -1;
4476}
4477
4478/*
4479 * "localtime()" function
4480 */
4481 static void
4482f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4483{
4484 rettv->vval.v_number = (varnumber_T)time(NULL);
4485}
4486
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004487#ifdef FEAT_FLOAT
4488/*
4489 * "log()" function
4490 */
4491 static void
4492f_log(typval_T *argvars, typval_T *rettv)
4493{
4494 float_T f = 0.0;
4495
4496 rettv->v_type = VAR_FLOAT;
4497 if (get_float_arg(argvars, &f) == OK)
4498 rettv->vval.v_float = log(f);
4499 else
4500 rettv->vval.v_float = 0.0;
4501}
4502
4503/*
4504 * "log10()" function
4505 */
4506 static void
4507f_log10(typval_T *argvars, typval_T *rettv)
4508{
4509 float_T f = 0.0;
4510
4511 rettv->v_type = VAR_FLOAT;
4512 if (get_float_arg(argvars, &f) == OK)
4513 rettv->vval.v_float = log10(f);
4514 else
4515 rettv->vval.v_float = 0.0;
4516}
4517#endif
4518
4519#ifdef FEAT_LUA
4520/*
4521 * "luaeval()" function
4522 */
4523 static void
4524f_luaeval(typval_T *argvars, typval_T *rettv)
4525{
4526 char_u *str;
4527 char_u buf[NUMBUFLEN];
4528
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004529 if (check_restricted() || check_secure())
4530 return;
4531
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004532 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004533 do_luaeval(str, argvars + 1, rettv);
4534}
4535#endif
4536
4537/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004538 * "maparg()" function
4539 */
4540 static void
4541f_maparg(typval_T *argvars, typval_T *rettv)
4542{
4543 get_maparg(argvars, rettv, TRUE);
4544}
4545
4546/*
4547 * "mapcheck()" function
4548 */
4549 static void
4550f_mapcheck(typval_T *argvars, typval_T *rettv)
4551{
4552 get_maparg(argvars, rettv, FALSE);
4553}
4554
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004555typedef enum
4556{
4557 MATCH_END, /* matchend() */
4558 MATCH_MATCH, /* match() */
4559 MATCH_STR, /* matchstr() */
4560 MATCH_LIST, /* matchlist() */
4561 MATCH_POS /* matchstrpos() */
4562} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004563
4564 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004565find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004566{
4567 char_u *str = NULL;
4568 long len = 0;
4569 char_u *expr = NULL;
4570 char_u *pat;
4571 regmatch_T regmatch;
4572 char_u patbuf[NUMBUFLEN];
4573 char_u strbuf[NUMBUFLEN];
4574 char_u *save_cpo;
4575 long start = 0;
4576 long nth = 1;
4577 colnr_T startcol = 0;
4578 int match = 0;
4579 list_T *l = NULL;
4580 listitem_T *li = NULL;
4581 long idx = 0;
4582 char_u *tofree = NULL;
4583
4584 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4585 save_cpo = p_cpo;
4586 p_cpo = (char_u *)"";
4587
4588 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004589 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004590 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004591 /* type MATCH_LIST: return empty list when there are no matches.
4592 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004593 if (rettv_list_alloc(rettv) == FAIL)
4594 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004595 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004596 && (list_append_string(rettv->vval.v_list,
4597 (char_u *)"", 0) == FAIL
4598 || list_append_number(rettv->vval.v_list,
4599 (varnumber_T)-1) == FAIL
4600 || list_append_number(rettv->vval.v_list,
4601 (varnumber_T)-1) == FAIL
4602 || list_append_number(rettv->vval.v_list,
4603 (varnumber_T)-1) == FAIL))
4604 {
4605 list_free(rettv->vval.v_list);
4606 rettv->vval.v_list = NULL;
4607 goto theend;
4608 }
4609 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004610 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004611 {
4612 rettv->v_type = VAR_STRING;
4613 rettv->vval.v_string = NULL;
4614 }
4615
4616 if (argvars[0].v_type == VAR_LIST)
4617 {
4618 if ((l = argvars[0].vval.v_list) == NULL)
4619 goto theend;
4620 li = l->lv_first;
4621 }
4622 else
4623 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004624 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004625 len = (long)STRLEN(str);
4626 }
4627
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004628 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004629 if (pat == NULL)
4630 goto theend;
4631
4632 if (argvars[2].v_type != VAR_UNKNOWN)
4633 {
4634 int error = FALSE;
4635
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004636 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004637 if (error)
4638 goto theend;
4639 if (l != NULL)
4640 {
4641 li = list_find(l, start);
4642 if (li == NULL)
4643 goto theend;
4644 idx = l->lv_idx; /* use the cached index */
4645 }
4646 else
4647 {
4648 if (start < 0)
4649 start = 0;
4650 if (start > len)
4651 goto theend;
4652 /* When "count" argument is there ignore matches before "start",
4653 * otherwise skip part of the string. Differs when pattern is "^"
4654 * or "\<". */
4655 if (argvars[3].v_type != VAR_UNKNOWN)
4656 startcol = start;
4657 else
4658 {
4659 str += start;
4660 len -= start;
4661 }
4662 }
4663
4664 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004665 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004666 if (error)
4667 goto theend;
4668 }
4669
4670 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4671 if (regmatch.regprog != NULL)
4672 {
4673 regmatch.rm_ic = p_ic;
4674
4675 for (;;)
4676 {
4677 if (l != NULL)
4678 {
4679 if (li == NULL)
4680 {
4681 match = FALSE;
4682 break;
4683 }
4684 vim_free(tofree);
4685 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4686 if (str == NULL)
4687 break;
4688 }
4689
4690 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4691
4692 if (match && --nth <= 0)
4693 break;
4694 if (l == NULL && !match)
4695 break;
4696
4697 /* Advance to just after the match. */
4698 if (l != NULL)
4699 {
4700 li = li->li_next;
4701 ++idx;
4702 }
4703 else
4704 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004705 startcol = (colnr_T)(regmatch.startp[0]
4706 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004707 if (startcol > (colnr_T)len
4708 || str + startcol <= regmatch.startp[0])
4709 {
4710 match = FALSE;
4711 break;
4712 }
4713 }
4714 }
4715
4716 if (match)
4717 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004718 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719 {
4720 listitem_T *li1 = rettv->vval.v_list->lv_first;
4721 listitem_T *li2 = li1->li_next;
4722 listitem_T *li3 = li2->li_next;
4723 listitem_T *li4 = li3->li_next;
4724
4725 vim_free(li1->li_tv.vval.v_string);
4726 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4727 (int)(regmatch.endp[0] - regmatch.startp[0]));
4728 li3->li_tv.vval.v_number =
4729 (varnumber_T)(regmatch.startp[0] - expr);
4730 li4->li_tv.vval.v_number =
4731 (varnumber_T)(regmatch.endp[0] - expr);
4732 if (l != NULL)
4733 li2->li_tv.vval.v_number = (varnumber_T)idx;
4734 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004735 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004736 {
4737 int i;
4738
4739 /* return list with matched string and submatches */
4740 for (i = 0; i < NSUBEXP; ++i)
4741 {
4742 if (regmatch.endp[i] == NULL)
4743 {
4744 if (list_append_string(rettv->vval.v_list,
4745 (char_u *)"", 0) == FAIL)
4746 break;
4747 }
4748 else if (list_append_string(rettv->vval.v_list,
4749 regmatch.startp[i],
4750 (int)(regmatch.endp[i] - regmatch.startp[i]))
4751 == FAIL)
4752 break;
4753 }
4754 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004755 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004756 {
4757 /* return matched string */
4758 if (l != NULL)
4759 copy_tv(&li->li_tv, rettv);
4760 else
4761 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4762 (int)(regmatch.endp[0] - regmatch.startp[0]));
4763 }
4764 else if (l != NULL)
4765 rettv->vval.v_number = idx;
4766 else
4767 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004768 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004769 rettv->vval.v_number =
4770 (varnumber_T)(regmatch.startp[0] - str);
4771 else
4772 rettv->vval.v_number =
4773 (varnumber_T)(regmatch.endp[0] - str);
4774 rettv->vval.v_number += (varnumber_T)(str - expr);
4775 }
4776 }
4777 vim_regfree(regmatch.regprog);
4778 }
4779
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004780theend:
4781 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004782 /* matchstrpos() without a list: drop the second item. */
4783 listitem_remove(rettv->vval.v_list,
4784 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004785 vim_free(tofree);
4786 p_cpo = save_cpo;
4787}
4788
4789/*
4790 * "match()" function
4791 */
4792 static void
4793f_match(typval_T *argvars, typval_T *rettv)
4794{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004795 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796}
4797
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004798/*
4799 * "matchend()" function
4800 */
4801 static void
4802f_matchend(typval_T *argvars, typval_T *rettv)
4803{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004804 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004805}
4806
4807/*
4808 * "matchlist()" function
4809 */
4810 static void
4811f_matchlist(typval_T *argvars, typval_T *rettv)
4812{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004813 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004814}
4815
4816/*
4817 * "matchstr()" function
4818 */
4819 static void
4820f_matchstr(typval_T *argvars, typval_T *rettv)
4821{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004822 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004823}
4824
4825/*
4826 * "matchstrpos()" function
4827 */
4828 static void
4829f_matchstrpos(typval_T *argvars, typval_T *rettv)
4830{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004831 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004832}
4833
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004834 static void
4835max_min(typval_T *argvars, typval_T *rettv, int domax)
4836{
4837 varnumber_T n = 0;
4838 varnumber_T i;
4839 int error = FALSE;
4840
4841 if (argvars[0].v_type == VAR_LIST)
4842 {
4843 list_T *l;
4844 listitem_T *li;
4845
4846 l = argvars[0].vval.v_list;
4847 if (l != NULL)
4848 {
4849 li = l->lv_first;
4850 if (li != NULL)
4851 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004852 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853 for (;;)
4854 {
4855 li = li->li_next;
4856 if (li == NULL)
4857 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004858 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859 if (domax ? i > n : i < n)
4860 n = i;
4861 }
4862 }
4863 }
4864 }
4865 else if (argvars[0].v_type == VAR_DICT)
4866 {
4867 dict_T *d;
4868 int first = TRUE;
4869 hashitem_T *hi;
4870 int todo;
4871
4872 d = argvars[0].vval.v_dict;
4873 if (d != NULL)
4874 {
4875 todo = (int)d->dv_hashtab.ht_used;
4876 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4877 {
4878 if (!HASHITEM_EMPTY(hi))
4879 {
4880 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004881 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004882 if (first)
4883 {
4884 n = i;
4885 first = FALSE;
4886 }
4887 else if (domax ? i > n : i < n)
4888 n = i;
4889 }
4890 }
4891 }
4892 }
4893 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004894 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004895 rettv->vval.v_number = error ? 0 : n;
4896}
4897
4898/*
4899 * "max()" function
4900 */
4901 static void
4902f_max(typval_T *argvars, typval_T *rettv)
4903{
4904 max_min(argvars, rettv, TRUE);
4905}
4906
4907/*
4908 * "min()" function
4909 */
4910 static void
4911f_min(typval_T *argvars, typval_T *rettv)
4912{
4913 max_min(argvars, rettv, FALSE);
4914}
4915
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004916#if defined(FEAT_MZSCHEME) || defined(PROTO)
4917/*
4918 * "mzeval()" function
4919 */
4920 static void
4921f_mzeval(typval_T *argvars, typval_T *rettv)
4922{
4923 char_u *str;
4924 char_u buf[NUMBUFLEN];
4925
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004926 if (check_restricted() || check_secure())
4927 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004928 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004929 do_mzeval(str, rettv);
4930}
4931
4932 void
4933mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4934{
4935 typval_T argvars[3];
4936
4937 argvars[0].v_type = VAR_STRING;
4938 argvars[0].vval.v_string = name;
4939 copy_tv(args, &argvars[1]);
4940 argvars[2].v_type = VAR_UNKNOWN;
4941 f_call(argvars, rettv);
4942 clear_tv(&argvars[1]);
4943}
4944#endif
4945
4946/*
4947 * "nextnonblank()" function
4948 */
4949 static void
4950f_nextnonblank(typval_T *argvars, typval_T *rettv)
4951{
4952 linenr_T lnum;
4953
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004954 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955 {
4956 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
4957 {
4958 lnum = 0;
4959 break;
4960 }
4961 if (*skipwhite(ml_get(lnum)) != NUL)
4962 break;
4963 }
4964 rettv->vval.v_number = lnum;
4965}
4966
4967/*
4968 * "nr2char()" function
4969 */
4970 static void
4971f_nr2char(typval_T *argvars, typval_T *rettv)
4972{
4973 char_u buf[NUMBUFLEN];
4974
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004975 if (has_mbyte)
4976 {
4977 int utf8 = 0;
4978
4979 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004980 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004981 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01004982 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004983 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004984 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004985 }
4986 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004987 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004988 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004989 buf[1] = NUL;
4990 }
4991 rettv->v_type = VAR_STRING;
4992 rettv->vval.v_string = vim_strsave(buf);
4993}
4994
4995/*
4996 * "or(expr, expr)" function
4997 */
4998 static void
4999f_or(typval_T *argvars, typval_T *rettv)
5000{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005001 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5002 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005003}
5004
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005005#ifdef FEAT_PERL
5006/*
5007 * "perleval()" function
5008 */
5009 static void
5010f_perleval(typval_T *argvars, typval_T *rettv)
5011{
5012 char_u *str;
5013 char_u buf[NUMBUFLEN];
5014
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005015 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005016 do_perleval(str, rettv);
5017}
5018#endif
5019
5020#ifdef FEAT_FLOAT
5021/*
5022 * "pow()" function
5023 */
5024 static void
5025f_pow(typval_T *argvars, typval_T *rettv)
5026{
5027 float_T fx = 0.0, fy = 0.0;
5028
5029 rettv->v_type = VAR_FLOAT;
5030 if (get_float_arg(argvars, &fx) == OK
5031 && get_float_arg(&argvars[1], &fy) == OK)
5032 rettv->vval.v_float = pow(fx, fy);
5033 else
5034 rettv->vval.v_float = 0.0;
5035}
5036#endif
5037
5038/*
5039 * "prevnonblank()" function
5040 */
5041 static void
5042f_prevnonblank(typval_T *argvars, typval_T *rettv)
5043{
5044 linenr_T lnum;
5045
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005046 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005047 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5048 lnum = 0;
5049 else
5050 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5051 --lnum;
5052 rettv->vval.v_number = lnum;
5053}
5054
5055/* This dummy va_list is here because:
5056 * - passing a NULL pointer doesn't work when va_list isn't a pointer
5057 * - locally in the function results in a "used before set" warning
5058 * - using va_start() to initialize it gives "function with fixed args" error */
5059static va_list ap;
5060
5061/*
5062 * "printf()" function
5063 */
5064 static void
5065f_printf(typval_T *argvars, typval_T *rettv)
5066{
5067 char_u buf[NUMBUFLEN];
5068 int len;
5069 char_u *s;
5070 int saved_did_emsg = did_emsg;
5071 char *fmt;
5072
5073 rettv->v_type = VAR_STRING;
5074 rettv->vval.v_string = NULL;
5075
5076 /* Get the required length, allocate the buffer and do it for real. */
5077 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005078 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005079 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005080 if (!did_emsg)
5081 {
5082 s = alloc(len + 1);
5083 if (s != NULL)
5084 {
5085 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005086 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5087 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005088 }
5089 }
5090 did_emsg |= saved_did_emsg;
5091}
5092
5093/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005094 * "pum_getpos()" function
5095 */
5096 static void
5097f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5098{
5099 if (rettv_dict_alloc(rettv) != OK)
5100 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005101 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005102}
5103
5104/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 * "pumvisible()" function
5106 */
5107 static void
5108f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5109{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110 if (pum_visible())
5111 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005112}
5113
5114#ifdef FEAT_PYTHON3
5115/*
5116 * "py3eval()" function
5117 */
5118 static void
5119f_py3eval(typval_T *argvars, typval_T *rettv)
5120{
5121 char_u *str;
5122 char_u buf[NUMBUFLEN];
5123
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005124 if (check_restricted() || check_secure())
5125 return;
5126
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005127 if (p_pyx == 0)
5128 p_pyx = 3;
5129
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005130 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005131 do_py3eval(str, rettv);
5132}
5133#endif
5134
5135#ifdef FEAT_PYTHON
5136/*
5137 * "pyeval()" function
5138 */
5139 static void
5140f_pyeval(typval_T *argvars, typval_T *rettv)
5141{
5142 char_u *str;
5143 char_u buf[NUMBUFLEN];
5144
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005145 if (check_restricted() || check_secure())
5146 return;
5147
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005148 if (p_pyx == 0)
5149 p_pyx = 2;
5150
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005151 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005152 do_pyeval(str, rettv);
5153}
5154#endif
5155
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005156#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5157/*
5158 * "pyxeval()" function
5159 */
5160 static void
5161f_pyxeval(typval_T *argvars, typval_T *rettv)
5162{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005163 if (check_restricted() || check_secure())
5164 return;
5165
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005166# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5167 init_pyxversion();
5168 if (p_pyx == 2)
5169 f_pyeval(argvars, rettv);
5170 else
5171 f_py3eval(argvars, rettv);
5172# elif defined(FEAT_PYTHON)
5173 f_pyeval(argvars, rettv);
5174# elif defined(FEAT_PYTHON3)
5175 f_py3eval(argvars, rettv);
5176# endif
5177}
5178#endif
5179
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005180/*
5181 * "range()" function
5182 */
5183 static void
5184f_range(typval_T *argvars, typval_T *rettv)
5185{
5186 varnumber_T start;
5187 varnumber_T end;
5188 varnumber_T stride = 1;
5189 varnumber_T i;
5190 int error = FALSE;
5191
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005192 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005193 if (argvars[1].v_type == VAR_UNKNOWN)
5194 {
5195 end = start - 1;
5196 start = 0;
5197 }
5198 else
5199 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005200 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005202 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203 }
5204
5205 if (error)
5206 return; /* type error; errmsg already given */
5207 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005208 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005209 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005210 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005211 else
5212 {
5213 if (rettv_list_alloc(rettv) == OK)
5214 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5215 if (list_append_number(rettv->vval.v_list,
5216 (varnumber_T)i) == FAIL)
5217 break;
5218 }
5219}
5220
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005221 static void
5222return_register(int regname, typval_T *rettv)
5223{
5224 char_u buf[2] = {0, 0};
5225
5226 buf[0] = (char_u)regname;
5227 rettv->v_type = VAR_STRING;
5228 rettv->vval.v_string = vim_strsave(buf);
5229}
5230
5231/*
5232 * "reg_executing()" function
5233 */
5234 static void
5235f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5236{
5237 return_register(reg_executing, rettv);
5238}
5239
5240/*
5241 * "reg_recording()" function
5242 */
5243 static void
5244f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5245{
5246 return_register(reg_recording, rettv);
5247}
5248
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005249#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005250/*
5251 * Convert a List to proftime_T.
5252 * Return FAIL when there is something wrong.
5253 */
5254 static int
5255list2proftime(typval_T *arg, proftime_T *tm)
5256{
5257 long n1, n2;
5258 int error = FALSE;
5259
5260 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5261 || arg->vval.v_list->lv_len != 2)
5262 return FAIL;
5263 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5264 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005265# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005266 tm->HighPart = n1;
5267 tm->LowPart = n2;
5268# else
5269 tm->tv_sec = n1;
5270 tm->tv_usec = n2;
5271# endif
5272 return error ? FAIL : OK;
5273}
5274#endif /* FEAT_RELTIME */
5275
5276/*
5277 * "reltime()" function
5278 */
5279 static void
5280f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5281{
5282#ifdef FEAT_RELTIME
5283 proftime_T res;
5284 proftime_T start;
5285
5286 if (argvars[0].v_type == VAR_UNKNOWN)
5287 {
5288 /* No arguments: get current time. */
5289 profile_start(&res);
5290 }
5291 else if (argvars[1].v_type == VAR_UNKNOWN)
5292 {
5293 if (list2proftime(&argvars[0], &res) == FAIL)
5294 return;
5295 profile_end(&res);
5296 }
5297 else
5298 {
5299 /* Two arguments: compute the difference. */
5300 if (list2proftime(&argvars[0], &start) == FAIL
5301 || list2proftime(&argvars[1], &res) == FAIL)
5302 return;
5303 profile_sub(&res, &start);
5304 }
5305
5306 if (rettv_list_alloc(rettv) == OK)
5307 {
5308 long n1, n2;
5309
Bram Moolenaar4f974752019-02-17 17:44:42 +01005310# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005311 n1 = res.HighPart;
5312 n2 = res.LowPart;
5313# else
5314 n1 = res.tv_sec;
5315 n2 = res.tv_usec;
5316# endif
5317 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5318 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5319 }
5320#endif
5321}
5322
5323#ifdef FEAT_FLOAT
5324/*
5325 * "reltimefloat()" function
5326 */
5327 static void
5328f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5329{
5330# ifdef FEAT_RELTIME
5331 proftime_T tm;
5332# endif
5333
5334 rettv->v_type = VAR_FLOAT;
5335 rettv->vval.v_float = 0;
5336# ifdef FEAT_RELTIME
5337 if (list2proftime(&argvars[0], &tm) == OK)
5338 rettv->vval.v_float = profile_float(&tm);
5339# endif
5340}
5341#endif
5342
5343/*
5344 * "reltimestr()" function
5345 */
5346 static void
5347f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5348{
5349#ifdef FEAT_RELTIME
5350 proftime_T tm;
5351#endif
5352
5353 rettv->v_type = VAR_STRING;
5354 rettv->vval.v_string = NULL;
5355#ifdef FEAT_RELTIME
5356 if (list2proftime(&argvars[0], &tm) == OK)
5357 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5358#endif
5359}
5360
5361#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005362 static void
5363make_connection(void)
5364{
5365 if (X_DISPLAY == NULL
5366# ifdef FEAT_GUI
5367 && !gui.in_use
5368# endif
5369 )
5370 {
5371 x_force_connect = TRUE;
5372 setup_term_clip();
5373 x_force_connect = FALSE;
5374 }
5375}
5376
5377 static int
5378check_connection(void)
5379{
5380 make_connection();
5381 if (X_DISPLAY == NULL)
5382 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005383 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005384 return FAIL;
5385 }
5386 return OK;
5387}
5388#endif
5389
5390#ifdef FEAT_CLIENTSERVER
5391 static void
5392remote_common(typval_T *argvars, typval_T *rettv, int expr)
5393{
5394 char_u *server_name;
5395 char_u *keys;
5396 char_u *r = NULL;
5397 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005398 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005399# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005400 HWND w;
5401# else
5402 Window w;
5403# endif
5404
5405 if (check_restricted() || check_secure())
5406 return;
5407
5408# ifdef FEAT_X11
5409 if (check_connection() == FAIL)
5410 return;
5411# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005412 if (argvars[2].v_type != VAR_UNKNOWN
5413 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005414 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005415
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005416 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005417 if (server_name == NULL)
5418 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005419 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005420# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005421 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005422# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005423 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5424 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005425# endif
5426 {
5427 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005428 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005429 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005430 vim_free(r);
5431 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005432 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005433 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005434 return;
5435 }
5436
5437 rettv->vval.v_string = r;
5438
5439 if (argvars[2].v_type != VAR_UNKNOWN)
5440 {
5441 dictitem_T v;
5442 char_u str[30];
5443 char_u *idvar;
5444
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005445 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005446 if (idvar != NULL && *idvar != NUL)
5447 {
5448 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5449 v.di_tv.v_type = VAR_STRING;
5450 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005451 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005452 vim_free(v.di_tv.vval.v_string);
5453 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005454 }
5455}
5456#endif
5457
5458/*
5459 * "remote_expr()" function
5460 */
5461 static void
5462f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5463{
5464 rettv->v_type = VAR_STRING;
5465 rettv->vval.v_string = NULL;
5466#ifdef FEAT_CLIENTSERVER
5467 remote_common(argvars, rettv, TRUE);
5468#endif
5469}
5470
5471/*
5472 * "remote_foreground()" function
5473 */
5474 static void
5475f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5476{
5477#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005478# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005479 /* On Win32 it's done in this application. */
5480 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005481 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005482
5483 if (server_name != NULL)
5484 serverForeground(server_name);
5485 }
5486# else
5487 /* Send a foreground() expression to the server. */
5488 argvars[1].v_type = VAR_STRING;
5489 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5490 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005491 rettv->v_type = VAR_STRING;
5492 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005493 remote_common(argvars, rettv, TRUE);
5494 vim_free(argvars[1].vval.v_string);
5495# endif
5496#endif
5497}
5498
5499 static void
5500f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5501{
5502#ifdef FEAT_CLIENTSERVER
5503 dictitem_T v;
5504 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005505# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005506 long_u n = 0;
5507# endif
5508 char_u *serverid;
5509
5510 if (check_restricted() || check_secure())
5511 {
5512 rettv->vval.v_number = -1;
5513 return;
5514 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005515 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005516 if (serverid == NULL)
5517 {
5518 rettv->vval.v_number = -1;
5519 return; /* type error; errmsg already given */
5520 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005521# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005522 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5523 if (n == 0)
5524 rettv->vval.v_number = -1;
5525 else
5526 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005527 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005528 rettv->vval.v_number = (s != NULL);
5529 }
5530# else
5531 if (check_connection() == FAIL)
5532 return;
5533
5534 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5535 serverStrToWin(serverid), &s);
5536# endif
5537
5538 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5539 {
5540 char_u *retvar;
5541
5542 v.di_tv.v_type = VAR_STRING;
5543 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005544 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005545 if (retvar != NULL)
5546 set_var(retvar, &v.di_tv, FALSE);
5547 vim_free(v.di_tv.vval.v_string);
5548 }
5549#else
5550 rettv->vval.v_number = -1;
5551#endif
5552}
5553
5554 static void
5555f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5556{
5557 char_u *r = NULL;
5558
5559#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005560 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005561
5562 if (serverid != NULL && !check_restricted() && !check_secure())
5563 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005564 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005565# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005566 /* The server's HWND is encoded in the 'id' parameter */
5567 long_u n = 0;
5568# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005569
5570 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005571 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005572
Bram Moolenaar4f974752019-02-17 17:44:42 +01005573# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005574 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5575 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005576 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577 if (r == NULL)
5578# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005579 if (check_connection() == FAIL
5580 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5581 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005582# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005583 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005584 }
5585#endif
5586 rettv->v_type = VAR_STRING;
5587 rettv->vval.v_string = r;
5588}
5589
5590/*
5591 * "remote_send()" function
5592 */
5593 static void
5594f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5595{
5596 rettv->v_type = VAR_STRING;
5597 rettv->vval.v_string = NULL;
5598#ifdef FEAT_CLIENTSERVER
5599 remote_common(argvars, rettv, FALSE);
5600#endif
5601}
5602
5603/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005604 * "remote_startserver()" function
5605 */
5606 static void
5607f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5608{
5609#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005610 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005611
5612 if (server == NULL)
5613 return; /* type error; errmsg already given */
5614 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005615 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005616 else
5617 {
5618# ifdef FEAT_X11
5619 if (check_connection() == OK)
5620 serverRegisterName(X_DISPLAY, server);
5621# else
5622 serverSetName(server);
5623# endif
5624 }
5625#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005626 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005627#endif
5628}
5629
5630/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005631 * "rename({from}, {to})" function
5632 */
5633 static void
5634f_rename(typval_T *argvars, typval_T *rettv)
5635{
5636 char_u buf[NUMBUFLEN];
5637
5638 if (check_restricted() || check_secure())
5639 rettv->vval.v_number = -1;
5640 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005641 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5642 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005643}
5644
5645/*
5646 * "repeat()" function
5647 */
5648 static void
5649f_repeat(typval_T *argvars, typval_T *rettv)
5650{
5651 char_u *p;
5652 int n;
5653 int slen;
5654 int len;
5655 char_u *r;
5656 int i;
5657
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005658 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005659 if (argvars[0].v_type == VAR_LIST)
5660 {
5661 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5662 while (n-- > 0)
5663 if (list_extend(rettv->vval.v_list,
5664 argvars[0].vval.v_list, NULL) == FAIL)
5665 break;
5666 }
5667 else
5668 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005669 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005670 rettv->v_type = VAR_STRING;
5671 rettv->vval.v_string = NULL;
5672
5673 slen = (int)STRLEN(p);
5674 len = slen * n;
5675 if (len <= 0)
5676 return;
5677
5678 r = alloc(len + 1);
5679 if (r != NULL)
5680 {
5681 for (i = 0; i < n; i++)
5682 mch_memmove(r + i * slen, p, (size_t)slen);
5683 r[len] = NUL;
5684 }
5685
5686 rettv->vval.v_string = r;
5687 }
5688}
5689
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005690#define SP_NOMOVE 0x01 /* don't move cursor */
5691#define SP_REPEAT 0x02 /* repeat to find outer pair */
5692#define SP_RETCOUNT 0x04 /* return matchcount */
5693#define SP_SETPCMARK 0x08 /* set previous context mark */
5694#define SP_START 0x10 /* accept match at start position */
5695#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5696#define SP_END 0x40 /* leave cursor at end of match */
5697#define SP_COLUMN 0x80 /* start at cursor column */
5698
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005699/*
5700 * Get flags for a search function.
5701 * Possibly sets "p_ws".
5702 * Returns BACKWARD, FORWARD or zero (for an error).
5703 */
5704 static int
5705get_search_arg(typval_T *varp, int *flagsp)
5706{
5707 int dir = FORWARD;
5708 char_u *flags;
5709 char_u nbuf[NUMBUFLEN];
5710 int mask;
5711
5712 if (varp->v_type != VAR_UNKNOWN)
5713 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005714 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005715 if (flags == NULL)
5716 return 0; /* type error; errmsg already given */
5717 while (*flags != NUL)
5718 {
5719 switch (*flags)
5720 {
5721 case 'b': dir = BACKWARD; break;
5722 case 'w': p_ws = TRUE; break;
5723 case 'W': p_ws = FALSE; break;
5724 default: mask = 0;
5725 if (flagsp != NULL)
5726 switch (*flags)
5727 {
5728 case 'c': mask = SP_START; break;
5729 case 'e': mask = SP_END; break;
5730 case 'm': mask = SP_RETCOUNT; break;
5731 case 'n': mask = SP_NOMOVE; break;
5732 case 'p': mask = SP_SUBPAT; break;
5733 case 'r': mask = SP_REPEAT; break;
5734 case 's': mask = SP_SETPCMARK; break;
5735 case 'z': mask = SP_COLUMN; break;
5736 }
5737 if (mask == 0)
5738 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005739 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005740 dir = 0;
5741 }
5742 else
5743 *flagsp |= mask;
5744 }
5745 if (dir == 0)
5746 break;
5747 ++flags;
5748 }
5749 }
5750 return dir;
5751}
5752
5753/*
5754 * Shared by search() and searchpos() functions.
5755 */
5756 static int
5757search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5758{
5759 int flags;
5760 char_u *pat;
5761 pos_T pos;
5762 pos_T save_cursor;
5763 int save_p_ws = p_ws;
5764 int dir;
5765 int retval = 0; /* default: FAIL */
5766 long lnum_stop = 0;
5767 proftime_T tm;
5768#ifdef FEAT_RELTIME
5769 long time_limit = 0;
5770#endif
5771 int options = SEARCH_KEEP;
5772 int subpatnum;
5773
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005774 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005775 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5776 if (dir == 0)
5777 goto theend;
5778 flags = *flagsp;
5779 if (flags & SP_START)
5780 options |= SEARCH_START;
5781 if (flags & SP_END)
5782 options |= SEARCH_END;
5783 if (flags & SP_COLUMN)
5784 options |= SEARCH_COL;
5785
5786 /* Optional arguments: line number to stop searching and timeout. */
5787 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5788 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005789 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005790 if (lnum_stop < 0)
5791 goto theend;
5792#ifdef FEAT_RELTIME
5793 if (argvars[3].v_type != VAR_UNKNOWN)
5794 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005795 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005796 if (time_limit < 0)
5797 goto theend;
5798 }
5799#endif
5800 }
5801
5802#ifdef FEAT_RELTIME
5803 /* Set the time limit, if there is one. */
5804 profile_setlimit(time_limit, &tm);
5805#endif
5806
5807 /*
5808 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5809 * Check to make sure only those flags are set.
5810 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5811 * flags cannot be set. Check for that condition also.
5812 */
5813 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5814 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5815 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005816 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005817 goto theend;
5818 }
5819
5820 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005821 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02005822 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005823 if (subpatnum != FAIL)
5824 {
5825 if (flags & SP_SUBPAT)
5826 retval = subpatnum;
5827 else
5828 retval = pos.lnum;
5829 if (flags & SP_SETPCMARK)
5830 setpcmark();
5831 curwin->w_cursor = pos;
5832 if (match_pos != NULL)
5833 {
5834 /* Store the match cursor position */
5835 match_pos->lnum = pos.lnum;
5836 match_pos->col = pos.col + 1;
5837 }
5838 /* "/$" will put the cursor after the end of the line, may need to
5839 * correct that here */
5840 check_cursor();
5841 }
5842
5843 /* If 'n' flag is used: restore cursor position. */
5844 if (flags & SP_NOMOVE)
5845 curwin->w_cursor = save_cursor;
5846 else
5847 curwin->w_set_curswant = TRUE;
5848theend:
5849 p_ws = save_p_ws;
5850
5851 return retval;
5852}
5853
5854#ifdef FEAT_FLOAT
5855
5856/*
5857 * round() is not in C90, use ceil() or floor() instead.
5858 */
5859 float_T
5860vim_round(float_T f)
5861{
5862 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
5863}
5864
5865/*
5866 * "round({float})" function
5867 */
5868 static void
5869f_round(typval_T *argvars, typval_T *rettv)
5870{
5871 float_T f = 0.0;
5872
5873 rettv->v_type = VAR_FLOAT;
5874 if (get_float_arg(argvars, &f) == OK)
5875 rettv->vval.v_float = vim_round(f);
5876 else
5877 rettv->vval.v_float = 0.0;
5878}
5879#endif
5880
Bram Moolenaare99be0e2019-03-26 22:51:09 +01005881#ifdef FEAT_RUBY
5882/*
5883 * "rubyeval()" function
5884 */
5885 static void
5886f_rubyeval(typval_T *argvars, typval_T *rettv)
5887{
5888 char_u *str;
5889 char_u buf[NUMBUFLEN];
5890
5891 str = tv_get_string_buf(&argvars[0], buf);
5892 do_rubyeval(str, rettv);
5893}
5894#endif
5895
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005896/*
5897 * "screenattr()" function
5898 */
5899 static void
5900f_screenattr(typval_T *argvars, typval_T *rettv)
5901{
5902 int row;
5903 int col;
5904 int c;
5905
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005906 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5907 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005908 if (row < 0 || row >= screen_Rows
5909 || col < 0 || col >= screen_Columns)
5910 c = -1;
5911 else
5912 c = ScreenAttrs[LineOffset[row] + col];
5913 rettv->vval.v_number = c;
5914}
5915
5916/*
5917 * "screenchar()" function
5918 */
5919 static void
5920f_screenchar(typval_T *argvars, typval_T *rettv)
5921{
5922 int row;
5923 int col;
5924 int off;
5925 int c;
5926
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005927 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5928 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005929 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005930 c = -1;
5931 else
5932 {
5933 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005934 if (enc_utf8 && ScreenLinesUC[off] != 0)
5935 c = ScreenLinesUC[off];
5936 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005937 c = ScreenLines[off];
5938 }
5939 rettv->vval.v_number = c;
5940}
5941
5942/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005943 * "screenchars()" function
5944 */
5945 static void
5946f_screenchars(typval_T *argvars, typval_T *rettv)
5947{
5948 int row;
5949 int col;
5950 int off;
5951 int c;
5952 int i;
5953
5954 if (rettv_list_alloc(rettv) == FAIL)
5955 return;
5956 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5957 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5958 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5959 return;
5960
5961 off = LineOffset[row] + col;
5962 if (enc_utf8 && ScreenLinesUC[off] != 0)
5963 c = ScreenLinesUC[off];
5964 else
5965 c = ScreenLines[off];
5966 list_append_number(rettv->vval.v_list, (varnumber_T)c);
5967
5968 if (enc_utf8)
5969
5970 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
5971 list_append_number(rettv->vval.v_list,
5972 (varnumber_T)ScreenLinesC[i][off]);
5973}
5974
5975/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976 * "screencol()" function
5977 *
5978 * First column is 1 to be consistent with virtcol().
5979 */
5980 static void
5981f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
5982{
5983 rettv->vval.v_number = screen_screencol() + 1;
5984}
5985
5986/*
5987 * "screenrow()" function
5988 */
5989 static void
5990f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
5991{
5992 rettv->vval.v_number = screen_screenrow() + 1;
5993}
5994
5995/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005996 * "screenstring()" function
5997 */
5998 static void
5999f_screenstring(typval_T *argvars, typval_T *rettv)
6000{
6001 int row;
6002 int col;
6003 int off;
6004 int c;
6005 int i;
6006 char_u buf[MB_MAXBYTES + 1];
6007 int buflen = 0;
6008
6009 rettv->vval.v_string = NULL;
6010 rettv->v_type = VAR_STRING;
6011
6012 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6013 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6014 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6015 return;
6016
6017 off = LineOffset[row] + col;
6018 if (enc_utf8 && ScreenLinesUC[off] != 0)
6019 c = ScreenLinesUC[off];
6020 else
6021 c = ScreenLines[off];
6022 buflen += mb_char2bytes(c, buf);
6023
6024 if (enc_utf8)
6025 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6026 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6027
6028 buf[buflen] = NUL;
6029 rettv->vval.v_string = vim_strsave(buf);
6030}
6031
6032/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006033 * "search()" function
6034 */
6035 static void
6036f_search(typval_T *argvars, typval_T *rettv)
6037{
6038 int flags = 0;
6039
6040 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6041}
6042
6043/*
6044 * "searchdecl()" function
6045 */
6046 static void
6047f_searchdecl(typval_T *argvars, typval_T *rettv)
6048{
6049 int locally = 1;
6050 int thisblock = 0;
6051 int error = FALSE;
6052 char_u *name;
6053
6054 rettv->vval.v_number = 1; /* default: FAIL */
6055
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006056 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006057 if (argvars[1].v_type != VAR_UNKNOWN)
6058 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006059 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006060 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006061 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006062 }
6063 if (!error && name != NULL)
6064 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6065 locally, thisblock, SEARCH_KEEP) == FAIL;
6066}
6067
6068/*
6069 * Used by searchpair() and searchpairpos()
6070 */
6071 static int
6072searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6073{
6074 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006075 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006076 int save_p_ws = p_ws;
6077 int dir;
6078 int flags = 0;
6079 char_u nbuf1[NUMBUFLEN];
6080 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081 int retval = 0; /* default: FAIL */
6082 long lnum_stop = 0;
6083 long time_limit = 0;
6084
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006085 /* Get the three pattern arguments: start, middle, end. Will result in an
6086 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006087 spat = tv_get_string_chk(&argvars[0]);
6088 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6089 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006090 if (spat == NULL || mpat == NULL || epat == NULL)
6091 goto theend; /* type error */
6092
6093 /* Handle the optional fourth argument: flags */
6094 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6095 if (dir == 0)
6096 goto theend;
6097
6098 /* Don't accept SP_END or SP_SUBPAT.
6099 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6100 */
6101 if ((flags & (SP_END | SP_SUBPAT)) != 0
6102 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6103 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006104 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006105 goto theend;
6106 }
6107
6108 /* Using 'r' implies 'W', otherwise it doesn't work. */
6109 if (flags & SP_REPEAT)
6110 p_ws = FALSE;
6111
6112 /* Optional fifth argument: skip expression */
6113 if (argvars[3].v_type == VAR_UNKNOWN
6114 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006115 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006116 else
6117 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006118 skip = &argvars[4];
6119 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6120 && skip->v_type != VAR_STRING)
6121 {
6122 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006123 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006124 goto theend;
6125 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006126 if (argvars[5].v_type != VAR_UNKNOWN)
6127 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006128 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006129 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006130 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006131 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006132 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006133 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006134#ifdef FEAT_RELTIME
6135 if (argvars[6].v_type != VAR_UNKNOWN)
6136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006137 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006138 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006139 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006140 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006141 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006142 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143 }
6144#endif
6145 }
6146 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006147
6148 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6149 match_pos, lnum_stop, time_limit);
6150
6151theend:
6152 p_ws = save_p_ws;
6153
6154 return retval;
6155}
6156
6157/*
6158 * "searchpair()" function
6159 */
6160 static void
6161f_searchpair(typval_T *argvars, typval_T *rettv)
6162{
6163 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6164}
6165
6166/*
6167 * "searchpairpos()" function
6168 */
6169 static void
6170f_searchpairpos(typval_T *argvars, typval_T *rettv)
6171{
6172 pos_T match_pos;
6173 int lnum = 0;
6174 int col = 0;
6175
6176 if (rettv_list_alloc(rettv) == FAIL)
6177 return;
6178
6179 if (searchpair_cmn(argvars, &match_pos) > 0)
6180 {
6181 lnum = match_pos.lnum;
6182 col = match_pos.col;
6183 }
6184
6185 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6186 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6187}
6188
6189/*
6190 * Search for a start/middle/end thing.
6191 * Used by searchpair(), see its documentation for the details.
6192 * Returns 0 or -1 for no match,
6193 */
6194 long
6195do_searchpair(
6196 char_u *spat, /* start pattern */
6197 char_u *mpat, /* middle pattern */
6198 char_u *epat, /* end pattern */
6199 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006200 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006201 int flags, /* SP_SETPCMARK and other SP_ values */
6202 pos_T *match_pos,
6203 linenr_T lnum_stop, /* stop at this line if not zero */
6204 long time_limit UNUSED) /* stop after this many msec */
6205{
6206 char_u *save_cpo;
6207 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6208 long retval = 0;
6209 pos_T pos;
6210 pos_T firstpos;
6211 pos_T foundpos;
6212 pos_T save_cursor;
6213 pos_T save_pos;
6214 int n;
6215 int r;
6216 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006217 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006218 int err;
6219 int options = SEARCH_KEEP;
6220 proftime_T tm;
6221
6222 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6223 save_cpo = p_cpo;
6224 p_cpo = empty_option;
6225
6226#ifdef FEAT_RELTIME
6227 /* Set the time limit, if there is one. */
6228 profile_setlimit(time_limit, &tm);
6229#endif
6230
6231 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6232 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006233 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6234 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006235 if (pat2 == NULL || pat3 == NULL)
6236 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006237 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006238 if (*mpat == NUL)
6239 STRCPY(pat3, pat2);
6240 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006241 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006242 spat, epat, mpat);
6243 if (flags & SP_START)
6244 options |= SEARCH_START;
6245
Bram Moolenaar48570482017-10-30 21:48:41 +01006246 if (skip != NULL)
6247 {
6248 /* Empty string means to not use the skip expression. */
6249 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6250 use_skip = skip->vval.v_string != NULL
6251 && *skip->vval.v_string != NUL;
6252 }
6253
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006254 save_cursor = curwin->w_cursor;
6255 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006256 CLEAR_POS(&firstpos);
6257 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006258 pat = pat3;
6259 for (;;)
6260 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006261 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006262 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006263 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006264 /* didn't find it or found the first match again: FAIL */
6265 break;
6266
6267 if (firstpos.lnum == 0)
6268 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006269 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 {
6271 /* Found the same position again. Can happen with a pattern that
6272 * has "\zs" at the end and searching backwards. Advance one
6273 * character and try again. */
6274 if (dir == BACKWARD)
6275 decl(&pos);
6276 else
6277 incl(&pos);
6278 }
6279 foundpos = pos;
6280
6281 /* clear the start flag to avoid getting stuck here */
6282 options &= ~SEARCH_START;
6283
6284 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006285 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006286 {
6287 save_pos = curwin->w_cursor;
6288 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006289 err = FALSE;
6290 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006291 curwin->w_cursor = save_pos;
6292 if (err)
6293 {
6294 /* Evaluating {skip} caused an error, break here. */
6295 curwin->w_cursor = save_cursor;
6296 retval = -1;
6297 break;
6298 }
6299 if (r)
6300 continue;
6301 }
6302
6303 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6304 {
6305 /* Found end when searching backwards or start when searching
6306 * forward: nested pair. */
6307 ++nest;
6308 pat = pat2; /* nested, don't search for middle */
6309 }
6310 else
6311 {
6312 /* Found end when searching forward or start when searching
6313 * backward: end of (nested) pair; or found middle in outer pair. */
6314 if (--nest == 1)
6315 pat = pat3; /* outer level, search for middle */
6316 }
6317
6318 if (nest == 0)
6319 {
6320 /* Found the match: return matchcount or line number. */
6321 if (flags & SP_RETCOUNT)
6322 ++retval;
6323 else
6324 retval = pos.lnum;
6325 if (flags & SP_SETPCMARK)
6326 setpcmark();
6327 curwin->w_cursor = pos;
6328 if (!(flags & SP_REPEAT))
6329 break;
6330 nest = 1; /* search for next unmatched */
6331 }
6332 }
6333
6334 if (match_pos != NULL)
6335 {
6336 /* Store the match cursor position */
6337 match_pos->lnum = curwin->w_cursor.lnum;
6338 match_pos->col = curwin->w_cursor.col + 1;
6339 }
6340
6341 /* If 'n' flag is used or search failed: restore cursor position. */
6342 if ((flags & SP_NOMOVE) || retval == 0)
6343 curwin->w_cursor = save_cursor;
6344
6345theend:
6346 vim_free(pat2);
6347 vim_free(pat3);
6348 if (p_cpo == empty_option)
6349 p_cpo = save_cpo;
6350 else
6351 /* Darn, evaluating the {skip} expression changed the value. */
6352 free_string_option(save_cpo);
6353
6354 return retval;
6355}
6356
6357/*
6358 * "searchpos()" function
6359 */
6360 static void
6361f_searchpos(typval_T *argvars, typval_T *rettv)
6362{
6363 pos_T match_pos;
6364 int lnum = 0;
6365 int col = 0;
6366 int n;
6367 int flags = 0;
6368
6369 if (rettv_list_alloc(rettv) == FAIL)
6370 return;
6371
6372 n = search_cmn(argvars, &match_pos, &flags);
6373 if (n > 0)
6374 {
6375 lnum = match_pos.lnum;
6376 col = match_pos.col;
6377 }
6378
6379 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6380 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6381 if (flags & SP_SUBPAT)
6382 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6383}
6384
6385 static void
6386f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6387{
6388#ifdef FEAT_CLIENTSERVER
6389 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006390 char_u *server = tv_get_string_chk(&argvars[0]);
6391 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006392
6393 rettv->vval.v_number = -1;
6394 if (server == NULL || reply == NULL)
6395 return;
6396 if (check_restricted() || check_secure())
6397 return;
6398# ifdef FEAT_X11
6399 if (check_connection() == FAIL)
6400 return;
6401# endif
6402
6403 if (serverSendReply(server, reply) < 0)
6404 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006405 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006406 return;
6407 }
6408 rettv->vval.v_number = 0;
6409#else
6410 rettv->vval.v_number = -1;
6411#endif
6412}
6413
6414 static void
6415f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6416{
6417 char_u *r = NULL;
6418
6419#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006420# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421 r = serverGetVimNames();
6422# else
6423 make_connection();
6424 if (X_DISPLAY != NULL)
6425 r = serverGetVimNames(X_DISPLAY);
6426# endif
6427#endif
6428 rettv->v_type = VAR_STRING;
6429 rettv->vval.v_string = r;
6430}
6431
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006432 static void
6433f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6434{
6435 dict_T *d;
6436 dictitem_T *di;
6437 char_u *csearch;
6438
6439 if (argvars[0].v_type != VAR_DICT)
6440 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006441 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442 return;
6443 }
6444
6445 if ((d = argvars[0].vval.v_dict) != NULL)
6446 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006447 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006448 if (csearch != NULL)
6449 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006450 if (enc_utf8)
6451 {
6452 int pcc[MAX_MCO];
6453 int c = utfc_ptr2char(csearch, pcc);
6454
6455 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6456 }
6457 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006458 set_last_csearch(PTR2CHAR(csearch),
6459 csearch, MB_PTR2LEN(csearch));
6460 }
6461
6462 di = dict_find(d, (char_u *)"forward", -1);
6463 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006464 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465 ? FORWARD : BACKWARD);
6466
6467 di = dict_find(d, (char_u *)"until", -1);
6468 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006469 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006470 }
6471}
6472
6473/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006474 * "setenv()" function
6475 */
6476 static void
6477f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6478{
6479 char_u namebuf[NUMBUFLEN];
6480 char_u valbuf[NUMBUFLEN];
6481 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6482
6483 if (argvars[1].v_type == VAR_SPECIAL
6484 && argvars[1].vval.v_number == VVAL_NULL)
6485 vim_unsetenv(name);
6486 else
6487 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6488}
6489
6490/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006491 * "setfperm({fname}, {mode})" function
6492 */
6493 static void
6494f_setfperm(typval_T *argvars, typval_T *rettv)
6495{
6496 char_u *fname;
6497 char_u modebuf[NUMBUFLEN];
6498 char_u *mode_str;
6499 int i;
6500 int mask;
6501 int mode = 0;
6502
6503 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006504 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505 if (fname == NULL)
6506 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006507 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508 if (mode_str == NULL)
6509 return;
6510 if (STRLEN(mode_str) != 9)
6511 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006512 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006513 return;
6514 }
6515
6516 mask = 1;
6517 for (i = 8; i >= 0; --i)
6518 {
6519 if (mode_str[i] != '-')
6520 mode |= mask;
6521 mask = mask << 1;
6522 }
6523 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6524}
6525
6526/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006527 * "setpos()" function
6528 */
6529 static void
6530f_setpos(typval_T *argvars, typval_T *rettv)
6531{
6532 pos_T pos;
6533 int fnum;
6534 char_u *name;
6535 colnr_T curswant = -1;
6536
6537 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006538 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 if (name != NULL)
6540 {
6541 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6542 {
6543 if (--pos.col < 0)
6544 pos.col = 0;
6545 if (name[0] == '.' && name[1] == NUL)
6546 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006547 /* set cursor; "fnum" is ignored */
6548 curwin->w_cursor = pos;
6549 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006550 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006551 curwin->w_curswant = curswant - 1;
6552 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006553 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006554 check_cursor();
6555 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006556 }
6557 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6558 {
6559 /* set mark */
6560 if (setmark_pos(name[1], &pos, fnum) == OK)
6561 rettv->vval.v_number = 0;
6562 }
6563 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006564 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006565 }
6566 }
6567}
6568
6569/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 * "setreg()" function
6571 */
6572 static void
6573f_setreg(typval_T *argvars, typval_T *rettv)
6574{
6575 int regname;
6576 char_u *strregname;
6577 char_u *stropt;
6578 char_u *strval;
6579 int append;
6580 char_u yank_type;
6581 long block_len;
6582
6583 block_len = -1;
6584 yank_type = MAUTO;
6585 append = FALSE;
6586
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006587 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 rettv->vval.v_number = 1; /* FAIL is default */
6589
6590 if (strregname == NULL)
6591 return; /* type error; errmsg already given */
6592 regname = *strregname;
6593 if (regname == 0 || regname == '@')
6594 regname = '"';
6595
6596 if (argvars[2].v_type != VAR_UNKNOWN)
6597 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006598 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006599 if (stropt == NULL)
6600 return; /* type error */
6601 for (; *stropt != NUL; ++stropt)
6602 switch (*stropt)
6603 {
6604 case 'a': case 'A': /* append */
6605 append = TRUE;
6606 break;
6607 case 'v': case 'c': /* character-wise selection */
6608 yank_type = MCHAR;
6609 break;
6610 case 'V': case 'l': /* line-wise selection */
6611 yank_type = MLINE;
6612 break;
6613 case 'b': case Ctrl_V: /* block-wise selection */
6614 yank_type = MBLOCK;
6615 if (VIM_ISDIGIT(stropt[1]))
6616 {
6617 ++stropt;
6618 block_len = getdigits(&stropt) - 1;
6619 --stropt;
6620 }
6621 break;
6622 }
6623 }
6624
6625 if (argvars[1].v_type == VAR_LIST)
6626 {
6627 char_u **lstval;
6628 char_u **allocval;
6629 char_u buf[NUMBUFLEN];
6630 char_u **curval;
6631 char_u **curallocval;
6632 list_T *ll = argvars[1].vval.v_list;
6633 listitem_T *li;
6634 int len;
6635
6636 /* If the list is NULL handle like an empty list. */
6637 len = ll == NULL ? 0 : ll->lv_len;
6638
6639 /* First half: use for pointers to result lines; second half: use for
6640 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006641 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006642 if (lstval == NULL)
6643 return;
6644 curval = lstval;
6645 allocval = lstval + len + 2;
6646 curallocval = allocval;
6647
6648 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6649 li = li->li_next)
6650 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006651 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006652 if (strval == NULL)
6653 goto free_lstval;
6654 if (strval == buf)
6655 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006656 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006657 * overwrite the string. */
6658 strval = vim_strsave(buf);
6659 if (strval == NULL)
6660 goto free_lstval;
6661 *curallocval++ = strval;
6662 }
6663 *curval++ = strval;
6664 }
6665 *curval++ = NULL;
6666
6667 write_reg_contents_lst(regname, lstval, -1,
6668 append, yank_type, block_len);
6669free_lstval:
6670 while (curallocval > allocval)
6671 vim_free(*--curallocval);
6672 vim_free(lstval);
6673 }
6674 else
6675 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006676 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006677 if (strval == NULL)
6678 return;
6679 write_reg_contents_ex(regname, strval, -1,
6680 append, yank_type, block_len);
6681 }
6682 rettv->vval.v_number = 0;
6683}
6684
6685/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006686 * "settagstack()" function
6687 */
6688 static void
6689f_settagstack(typval_T *argvars, typval_T *rettv)
6690{
6691 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6692 win_T *wp;
6693 dict_T *d;
6694 int action = 'r';
6695
6696 rettv->vval.v_number = -1;
6697
6698 // first argument: window number or id
6699 wp = find_win_by_nr_or_id(&argvars[0]);
6700 if (wp == NULL)
6701 return;
6702
6703 // second argument: dict with items to set in the tag stack
6704 if (argvars[1].v_type != VAR_DICT)
6705 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006706 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006707 return;
6708 }
6709 d = argvars[1].vval.v_dict;
6710 if (d == NULL)
6711 return;
6712
6713 // third argument: action - 'a' for append and 'r' for replace.
6714 // default is to replace the stack.
6715 if (argvars[2].v_type == VAR_UNKNOWN)
6716 action = 'r';
6717 else if (argvars[2].v_type == VAR_STRING)
6718 {
6719 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006720 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006721 if (actstr == NULL)
6722 return;
6723 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6724 action = *actstr;
6725 else
6726 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006727 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006728 return;
6729 }
6730 }
6731 else
6732 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006733 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006734 return;
6735 }
6736
6737 if (set_tagstack(wp, d, action) == OK)
6738 rettv->vval.v_number = 0;
6739}
6740
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741#ifdef FEAT_CRYPT
6742/*
6743 * "sha256({string})" function
6744 */
6745 static void
6746f_sha256(typval_T *argvars, typval_T *rettv)
6747{
6748 char_u *p;
6749
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006750 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006751 rettv->vval.v_string = vim_strsave(
6752 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6753 rettv->v_type = VAR_STRING;
6754}
6755#endif /* FEAT_CRYPT */
6756
6757/*
6758 * "shellescape({string})" function
6759 */
6760 static void
6761f_shellescape(typval_T *argvars, typval_T *rettv)
6762{
Bram Moolenaar20615522017-06-05 18:46:26 +02006763 int do_special = non_zero_arg(&argvars[1]);
6764
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006765 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006766 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006767 rettv->v_type = VAR_STRING;
6768}
6769
6770/*
6771 * shiftwidth() function
6772 */
6773 static void
6774f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6775{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006776 rettv->vval.v_number = 0;
6777
6778 if (argvars[0].v_type != VAR_UNKNOWN)
6779 {
6780 long col;
6781
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006782 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006783 if (col < 0)
6784 return; // type error; errmsg already given
6785#ifdef FEAT_VARTABS
6786 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6787 return;
6788#endif
6789 }
6790
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006791 rettv->vval.v_number = get_sw_value(curbuf);
6792}
6793
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794#ifdef FEAT_FLOAT
6795/*
6796 * "sin()" function
6797 */
6798 static void
6799f_sin(typval_T *argvars, typval_T *rettv)
6800{
6801 float_T f = 0.0;
6802
6803 rettv->v_type = VAR_FLOAT;
6804 if (get_float_arg(argvars, &f) == OK)
6805 rettv->vval.v_float = sin(f);
6806 else
6807 rettv->vval.v_float = 0.0;
6808}
6809
6810/*
6811 * "sinh()" function
6812 */
6813 static void
6814f_sinh(typval_T *argvars, typval_T *rettv)
6815{
6816 float_T f = 0.0;
6817
6818 rettv->v_type = VAR_FLOAT;
6819 if (get_float_arg(argvars, &f) == OK)
6820 rettv->vval.v_float = sinh(f);
6821 else
6822 rettv->vval.v_float = 0.0;
6823}
6824#endif
6825
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006826/*
6827 * "soundfold({word})" function
6828 */
6829 static void
6830f_soundfold(typval_T *argvars, typval_T *rettv)
6831{
6832 char_u *s;
6833
6834 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006835 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836#ifdef FEAT_SPELL
6837 rettv->vval.v_string = eval_soundfold(s);
6838#else
6839 rettv->vval.v_string = vim_strsave(s);
6840#endif
6841}
6842
6843/*
6844 * "spellbadword()" function
6845 */
6846 static void
6847f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6848{
6849 char_u *word = (char_u *)"";
6850 hlf_T attr = HLF_COUNT;
6851 int len = 0;
6852
6853 if (rettv_list_alloc(rettv) == FAIL)
6854 return;
6855
6856#ifdef FEAT_SPELL
6857 if (argvars[0].v_type == VAR_UNKNOWN)
6858 {
6859 /* Find the start and length of the badly spelled word. */
6860 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
6861 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006862 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006863 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006864 curwin->w_set_curswant = TRUE;
6865 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 }
6867 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
6868 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006869 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006870 int capcol = -1;
6871
6872 if (str != NULL)
6873 {
6874 /* Check the argument for spelling. */
6875 while (*str != NUL)
6876 {
6877 len = spell_check(curwin, str, &attr, &capcol, FALSE);
6878 if (attr != HLF_COUNT)
6879 {
6880 word = str;
6881 break;
6882 }
6883 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02006884 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02006885 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006886 }
6887 }
6888 }
6889#endif
6890
6891 list_append_string(rettv->vval.v_list, word, len);
6892 list_append_string(rettv->vval.v_list, (char_u *)(
6893 attr == HLF_SPB ? "bad" :
6894 attr == HLF_SPR ? "rare" :
6895 attr == HLF_SPL ? "local" :
6896 attr == HLF_SPC ? "caps" :
6897 ""), -1);
6898}
6899
6900/*
6901 * "spellsuggest()" function
6902 */
6903 static void
6904f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
6905{
6906#ifdef FEAT_SPELL
6907 char_u *str;
6908 int typeerr = FALSE;
6909 int maxcount;
6910 garray_T ga;
6911 int i;
6912 listitem_T *li;
6913 int need_capital = FALSE;
6914#endif
6915
6916 if (rettv_list_alloc(rettv) == FAIL)
6917 return;
6918
6919#ifdef FEAT_SPELL
6920 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
6921 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006922 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006923 if (argvars[1].v_type != VAR_UNKNOWN)
6924 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006925 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006926 if (maxcount <= 0)
6927 return;
6928 if (argvars[2].v_type != VAR_UNKNOWN)
6929 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006930 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006931 if (typeerr)
6932 return;
6933 }
6934 }
6935 else
6936 maxcount = 25;
6937
6938 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
6939
6940 for (i = 0; i < ga.ga_len; ++i)
6941 {
6942 str = ((char_u **)ga.ga_data)[i];
6943
6944 li = listitem_alloc();
6945 if (li == NULL)
6946 vim_free(str);
6947 else
6948 {
6949 li->li_tv.v_type = VAR_STRING;
6950 li->li_tv.v_lock = 0;
6951 li->li_tv.vval.v_string = str;
6952 list_append(rettv->vval.v_list, li);
6953 }
6954 }
6955 ga_clear(&ga);
6956 }
6957#endif
6958}
6959
6960 static void
6961f_split(typval_T *argvars, typval_T *rettv)
6962{
6963 char_u *str;
6964 char_u *end;
6965 char_u *pat = NULL;
6966 regmatch_T regmatch;
6967 char_u patbuf[NUMBUFLEN];
6968 char_u *save_cpo;
6969 int match;
6970 colnr_T col = 0;
6971 int keepempty = FALSE;
6972 int typeerr = FALSE;
6973
6974 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6975 save_cpo = p_cpo;
6976 p_cpo = (char_u *)"";
6977
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006978 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006979 if (argvars[1].v_type != VAR_UNKNOWN)
6980 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006981 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006982 if (pat == NULL)
6983 typeerr = TRUE;
6984 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006985 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006986 }
6987 if (pat == NULL || *pat == NUL)
6988 pat = (char_u *)"[\\x01- ]\\+";
6989
6990 if (rettv_list_alloc(rettv) == FAIL)
6991 return;
6992 if (typeerr)
6993 return;
6994
6995 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6996 if (regmatch.regprog != NULL)
6997 {
6998 regmatch.rm_ic = FALSE;
6999 while (*str != NUL || keepempty)
7000 {
7001 if (*str == NUL)
7002 match = FALSE; /* empty item at the end */
7003 else
7004 match = vim_regexec_nl(&regmatch, str, col);
7005 if (match)
7006 end = regmatch.startp[0];
7007 else
7008 end = str + STRLEN(str);
7009 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7010 && *str != NUL && match && end < regmatch.endp[0]))
7011 {
7012 if (list_append_string(rettv->vval.v_list, str,
7013 (int)(end - str)) == FAIL)
7014 break;
7015 }
7016 if (!match)
7017 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007018 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007019 if (regmatch.endp[0] > str)
7020 col = 0;
7021 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007022 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007023 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024 str = regmatch.endp[0];
7025 }
7026
7027 vim_regfree(regmatch.regprog);
7028 }
7029
7030 p_cpo = save_cpo;
7031}
7032
7033#ifdef FEAT_FLOAT
7034/*
7035 * "sqrt()" function
7036 */
7037 static void
7038f_sqrt(typval_T *argvars, typval_T *rettv)
7039{
7040 float_T f = 0.0;
7041
7042 rettv->v_type = VAR_FLOAT;
7043 if (get_float_arg(argvars, &f) == OK)
7044 rettv->vval.v_float = sqrt(f);
7045 else
7046 rettv->vval.v_float = 0.0;
7047}
7048
7049/*
7050 * "str2float()" function
7051 */
7052 static void
7053f_str2float(typval_T *argvars, typval_T *rettv)
7054{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007055 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007056 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007057
Bram Moolenaar08243d22017-01-10 16:12:29 +01007058 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007059 p = skipwhite(p + 1);
7060 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007061 if (isneg)
7062 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007063 rettv->v_type = VAR_FLOAT;
7064}
7065#endif
7066
7067/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007068 * "str2list()" function
7069 */
7070 static void
7071f_str2list(typval_T *argvars, typval_T *rettv)
7072{
7073 char_u *p;
7074 int utf8 = FALSE;
7075
7076 if (rettv_list_alloc(rettv) == FAIL)
7077 return;
7078
7079 if (argvars[1].v_type != VAR_UNKNOWN)
7080 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7081
7082 p = tv_get_string(&argvars[0]);
7083
7084 if (has_mbyte || utf8)
7085 {
7086 int (*ptr2len)(char_u *);
7087 int (*ptr2char)(char_u *);
7088
7089 if (utf8 || enc_utf8)
7090 {
7091 ptr2len = utf_ptr2len;
7092 ptr2char = utf_ptr2char;
7093 }
7094 else
7095 {
7096 ptr2len = mb_ptr2len;
7097 ptr2char = mb_ptr2char;
7098 }
7099
7100 for ( ; *p != NUL; p += (*ptr2len)(p))
7101 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7102 }
7103 else
7104 for ( ; *p != NUL; ++p)
7105 list_append_number(rettv->vval.v_list, *p);
7106}
7107
7108/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007109 * "str2nr()" function
7110 */
7111 static void
7112f_str2nr(typval_T *argvars, typval_T *rettv)
7113{
7114 int base = 10;
7115 char_u *p;
7116 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007117 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007118 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007119
7120 if (argvars[1].v_type != VAR_UNKNOWN)
7121 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007122 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007123 if (base != 2 && base != 8 && base != 10 && base != 16)
7124 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007125 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007126 return;
7127 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007128 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7129 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007130 }
7131
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007132 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007133 isneg = (*p == '-');
7134 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007135 p = skipwhite(p + 1);
7136 switch (base)
7137 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007138 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7139 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7140 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007141 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007142 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7143 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007144 if (isneg)
7145 rettv->vval.v_number = -n;
7146 else
7147 rettv->vval.v_number = n;
7148
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007149}
7150
7151#ifdef HAVE_STRFTIME
7152/*
7153 * "strftime({format}[, {time}])" function
7154 */
7155 static void
7156f_strftime(typval_T *argvars, typval_T *rettv)
7157{
7158 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007159 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007160 struct tm *curtime;
7161 time_t seconds;
7162 char_u *p;
7163
7164 rettv->v_type = VAR_STRING;
7165
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007166 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007167 if (argvars[1].v_type == VAR_UNKNOWN)
7168 seconds = time(NULL);
7169 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007170 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007171 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007172 /* MSVC returns NULL for an invalid value of seconds. */
7173 if (curtime == NULL)
7174 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7175 else
7176 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007177 vimconv_T conv;
7178 char_u *enc;
7179
7180 conv.vc_type = CONV_NONE;
7181 enc = enc_locale();
7182 convert_setup(&conv, p_enc, enc);
7183 if (conv.vc_type != CONV_NONE)
7184 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007185 if (p != NULL)
7186 (void)strftime((char *)result_buf, sizeof(result_buf),
7187 (char *)p, curtime);
7188 else
7189 result_buf[0] = NUL;
7190
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007191 if (conv.vc_type != CONV_NONE)
7192 vim_free(p);
7193 convert_setup(&conv, enc, p_enc);
7194 if (conv.vc_type != CONV_NONE)
7195 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7196 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197 rettv->vval.v_string = vim_strsave(result_buf);
7198
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007199 /* Release conversion descriptors */
7200 convert_setup(&conv, NULL, NULL);
7201 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007202 }
7203}
7204#endif
7205
7206/*
7207 * "strgetchar()" function
7208 */
7209 static void
7210f_strgetchar(typval_T *argvars, typval_T *rettv)
7211{
7212 char_u *str;
7213 int len;
7214 int error = FALSE;
7215 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007216 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007217
7218 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007219 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007220 if (str == NULL)
7221 return;
7222 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007223 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007224 if (error)
7225 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007226
Bram Moolenaar13505972019-01-24 15:04:48 +01007227 while (charidx >= 0 && byteidx < len)
7228 {
7229 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007231 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7232 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007234 --charidx;
7235 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007236 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007237}
7238
7239/*
7240 * "stridx()" function
7241 */
7242 static void
7243f_stridx(typval_T *argvars, typval_T *rettv)
7244{
7245 char_u buf[NUMBUFLEN];
7246 char_u *needle;
7247 char_u *haystack;
7248 char_u *save_haystack;
7249 char_u *pos;
7250 int start_idx;
7251
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007252 needle = tv_get_string_chk(&argvars[1]);
7253 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254 rettv->vval.v_number = -1;
7255 if (needle == NULL || haystack == NULL)
7256 return; /* type error; errmsg already given */
7257
7258 if (argvars[2].v_type != VAR_UNKNOWN)
7259 {
7260 int error = FALSE;
7261
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007262 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007263 if (error || start_idx >= (int)STRLEN(haystack))
7264 return;
7265 if (start_idx >= 0)
7266 haystack += start_idx;
7267 }
7268
7269 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7270 if (pos != NULL)
7271 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7272}
7273
7274/*
7275 * "string()" function
7276 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007277 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007278f_string(typval_T *argvars, typval_T *rettv)
7279{
7280 char_u *tofree;
7281 char_u numbuf[NUMBUFLEN];
7282
7283 rettv->v_type = VAR_STRING;
7284 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7285 get_copyID());
7286 /* Make a copy if we have a value but it's not in allocated memory. */
7287 if (rettv->vval.v_string != NULL && tofree == NULL)
7288 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7289}
7290
7291/*
7292 * "strlen()" function
7293 */
7294 static void
7295f_strlen(typval_T *argvars, typval_T *rettv)
7296{
7297 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007298 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007299}
7300
7301/*
7302 * "strchars()" function
7303 */
7304 static void
7305f_strchars(typval_T *argvars, typval_T *rettv)
7306{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007307 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007308 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007309 varnumber_T len = 0;
7310 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007311
7312 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007313 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007314 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007315 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007316 else
7317 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007318 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7319 while (*s != NUL)
7320 {
7321 func_mb_ptr2char_adv(&s);
7322 ++len;
7323 }
7324 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007325 }
7326}
7327
7328/*
7329 * "strdisplaywidth()" function
7330 */
7331 static void
7332f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7333{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007334 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007335 int col = 0;
7336
7337 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007338 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007339
7340 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7341}
7342
7343/*
7344 * "strwidth()" function
7345 */
7346 static void
7347f_strwidth(typval_T *argvars, typval_T *rettv)
7348{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007349 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350
Bram Moolenaar13505972019-01-24 15:04:48 +01007351 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007352}
7353
7354/*
7355 * "strcharpart()" function
7356 */
7357 static void
7358f_strcharpart(typval_T *argvars, typval_T *rettv)
7359{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007360 char_u *p;
7361 int nchar;
7362 int nbyte = 0;
7363 int charlen;
7364 int len = 0;
7365 int slen;
7366 int error = FALSE;
7367
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007368 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007369 slen = (int)STRLEN(p);
7370
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007371 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007372 if (!error)
7373 {
7374 if (nchar > 0)
7375 while (nchar > 0 && nbyte < slen)
7376 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007377 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007378 --nchar;
7379 }
7380 else
7381 nbyte = nchar;
7382 if (argvars[2].v_type != VAR_UNKNOWN)
7383 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007384 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007385 while (charlen > 0 && nbyte + len < slen)
7386 {
7387 int off = nbyte + len;
7388
7389 if (off < 0)
7390 len += 1;
7391 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007392 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007393 --charlen;
7394 }
7395 }
7396 else
7397 len = slen - nbyte; /* default: all bytes that are available. */
7398 }
7399
7400 /*
7401 * Only return the overlap between the specified part and the actual
7402 * string.
7403 */
7404 if (nbyte < 0)
7405 {
7406 len += nbyte;
7407 nbyte = 0;
7408 }
7409 else if (nbyte > slen)
7410 nbyte = slen;
7411 if (len < 0)
7412 len = 0;
7413 else if (nbyte + len > slen)
7414 len = slen - nbyte;
7415
7416 rettv->v_type = VAR_STRING;
7417 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007418}
7419
7420/*
7421 * "strpart()" function
7422 */
7423 static void
7424f_strpart(typval_T *argvars, typval_T *rettv)
7425{
7426 char_u *p;
7427 int n;
7428 int len;
7429 int slen;
7430 int error = FALSE;
7431
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007432 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007433 slen = (int)STRLEN(p);
7434
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007435 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007436 if (error)
7437 len = 0;
7438 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007439 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007440 else
7441 len = slen - n; /* default len: all bytes that are available. */
7442
7443 /*
7444 * Only return the overlap between the specified part and the actual
7445 * string.
7446 */
7447 if (n < 0)
7448 {
7449 len += n;
7450 n = 0;
7451 }
7452 else if (n > slen)
7453 n = slen;
7454 if (len < 0)
7455 len = 0;
7456 else if (n + len > slen)
7457 len = slen - n;
7458
7459 rettv->v_type = VAR_STRING;
7460 rettv->vval.v_string = vim_strnsave(p + n, len);
7461}
7462
7463/*
7464 * "strridx()" function
7465 */
7466 static void
7467f_strridx(typval_T *argvars, typval_T *rettv)
7468{
7469 char_u buf[NUMBUFLEN];
7470 char_u *needle;
7471 char_u *haystack;
7472 char_u *rest;
7473 char_u *lastmatch = NULL;
7474 int haystack_len, end_idx;
7475
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007476 needle = tv_get_string_chk(&argvars[1]);
7477 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478
7479 rettv->vval.v_number = -1;
7480 if (needle == NULL || haystack == NULL)
7481 return; /* type error; errmsg already given */
7482
7483 haystack_len = (int)STRLEN(haystack);
7484 if (argvars[2].v_type != VAR_UNKNOWN)
7485 {
7486 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007487 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488 if (end_idx < 0)
7489 return; /* can never find a match */
7490 }
7491 else
7492 end_idx = haystack_len;
7493
7494 if (*needle == NUL)
7495 {
7496 /* Empty string matches past the end. */
7497 lastmatch = haystack + end_idx;
7498 }
7499 else
7500 {
7501 for (rest = haystack; *rest != '\0'; ++rest)
7502 {
7503 rest = (char_u *)strstr((char *)rest, (char *)needle);
7504 if (rest == NULL || rest > haystack + end_idx)
7505 break;
7506 lastmatch = rest;
7507 }
7508 }
7509
7510 if (lastmatch == NULL)
7511 rettv->vval.v_number = -1;
7512 else
7513 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7514}
7515
7516/*
7517 * "strtrans()" function
7518 */
7519 static void
7520f_strtrans(typval_T *argvars, typval_T *rettv)
7521{
7522 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007523 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524}
7525
7526/*
7527 * "submatch()" function
7528 */
7529 static void
7530f_submatch(typval_T *argvars, typval_T *rettv)
7531{
7532 int error = FALSE;
7533 int no;
7534 int retList = 0;
7535
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007536 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007537 if (error)
7538 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007539 if (no < 0 || no >= NSUBEXP)
7540 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007541 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007542 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007543 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007544 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007545 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 if (error)
7547 return;
7548
7549 if (retList == 0)
7550 {
7551 rettv->v_type = VAR_STRING;
7552 rettv->vval.v_string = reg_submatch(no);
7553 }
7554 else
7555 {
7556 rettv->v_type = VAR_LIST;
7557 rettv->vval.v_list = reg_submatch_list(no);
7558 }
7559}
7560
7561/*
7562 * "substitute()" function
7563 */
7564 static void
7565f_substitute(typval_T *argvars, typval_T *rettv)
7566{
7567 char_u patbuf[NUMBUFLEN];
7568 char_u subbuf[NUMBUFLEN];
7569 char_u flagsbuf[NUMBUFLEN];
7570
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007571 char_u *str = tv_get_string_chk(&argvars[0]);
7572 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007573 char_u *sub = NULL;
7574 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007575 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007576
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007577 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7578 expr = &argvars[2];
7579 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007580 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007581
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007582 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007583 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7584 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007585 rettv->vval.v_string = NULL;
7586 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007587 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007588}
7589
7590/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007591 * "swapinfo(swap_filename)" function
7592 */
7593 static void
7594f_swapinfo(typval_T *argvars, typval_T *rettv)
7595{
7596 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007597 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007598}
7599
7600/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007601 * "swapname(expr)" function
7602 */
7603 static void
7604f_swapname(typval_T *argvars, typval_T *rettv)
7605{
7606 buf_T *buf;
7607
7608 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007609 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007610 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7611 || buf->b_ml.ml_mfp->mf_fname == NULL)
7612 rettv->vval.v_string = NULL;
7613 else
7614 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7615}
7616
7617/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007618 * "synID(lnum, col, trans)" function
7619 */
7620 static void
7621f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7622{
7623 int id = 0;
7624#ifdef FEAT_SYN_HL
7625 linenr_T lnum;
7626 colnr_T col;
7627 int trans;
7628 int transerr = FALSE;
7629
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007630 lnum = tv_get_lnum(argvars); /* -1 on type error */
7631 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7632 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633
7634 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7635 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7636 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7637#endif
7638
7639 rettv->vval.v_number = id;
7640}
7641
7642/*
7643 * "synIDattr(id, what [, mode])" function
7644 */
7645 static void
7646f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7647{
7648 char_u *p = NULL;
7649#ifdef FEAT_SYN_HL
7650 int id;
7651 char_u *what;
7652 char_u *mode;
7653 char_u modebuf[NUMBUFLEN];
7654 int modec;
7655
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007656 id = (int)tv_get_number(&argvars[0]);
7657 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007658 if (argvars[2].v_type != VAR_UNKNOWN)
7659 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007660 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007661 modec = TOLOWER_ASC(mode[0]);
7662 if (modec != 't' && modec != 'c' && modec != 'g')
7663 modec = 0; /* replace invalid with current */
7664 }
7665 else
7666 {
7667#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7668 if (USE_24BIT)
7669 modec = 'g';
7670 else
7671#endif
7672 if (t_colors > 1)
7673 modec = 'c';
7674 else
7675 modec = 't';
7676 }
7677
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678 switch (TOLOWER_ASC(what[0]))
7679 {
7680 case 'b':
7681 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7682 p = highlight_color(id, what, modec);
7683 else /* bold */
7684 p = highlight_has_attr(id, HL_BOLD, modec);
7685 break;
7686
7687 case 'f': /* fg[#] or font */
7688 p = highlight_color(id, what, modec);
7689 break;
7690
7691 case 'i':
7692 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7693 p = highlight_has_attr(id, HL_INVERSE, modec);
7694 else /* italic */
7695 p = highlight_has_attr(id, HL_ITALIC, modec);
7696 break;
7697
7698 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007699 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007700 break;
7701
7702 case 'r': /* reverse */
7703 p = highlight_has_attr(id, HL_INVERSE, modec);
7704 break;
7705
7706 case 's':
7707 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7708 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007709 /* strikeout */
7710 else if (TOLOWER_ASC(what[1]) == 't' &&
7711 TOLOWER_ASC(what[2]) == 'r')
7712 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007713 else /* standout */
7714 p = highlight_has_attr(id, HL_STANDOUT, modec);
7715 break;
7716
7717 case 'u':
7718 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7719 /* underline */
7720 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7721 else
7722 /* undercurl */
7723 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7724 break;
7725 }
7726
7727 if (p != NULL)
7728 p = vim_strsave(p);
7729#endif
7730 rettv->v_type = VAR_STRING;
7731 rettv->vval.v_string = p;
7732}
7733
7734/*
7735 * "synIDtrans(id)" function
7736 */
7737 static void
7738f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7739{
7740 int id;
7741
7742#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007743 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744
7745 if (id > 0)
7746 id = syn_get_final_id(id);
7747 else
7748#endif
7749 id = 0;
7750
7751 rettv->vval.v_number = id;
7752}
7753
7754/*
7755 * "synconcealed(lnum, col)" function
7756 */
7757 static void
7758f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7759{
7760#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7761 linenr_T lnum;
7762 colnr_T col;
7763 int syntax_flags = 0;
7764 int cchar;
7765 int matchid = 0;
7766 char_u str[NUMBUFLEN];
7767#endif
7768
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007769 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770
7771#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007772 lnum = tv_get_lnum(argvars); /* -1 on type error */
7773 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007774
7775 vim_memset(str, NUL, sizeof(str));
7776
7777 if (rettv_list_alloc(rettv) != FAIL)
7778 {
7779 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7780 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7781 && curwin->w_p_cole > 0)
7782 {
7783 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7784 syntax_flags = get_syntax_info(&matchid);
7785
7786 /* get the conceal character */
7787 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7788 {
7789 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007790 if (cchar == NUL && curwin->w_p_cole == 1)
7791 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007792 if (cchar != NUL)
7793 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007794 if (has_mbyte)
7795 (*mb_char2bytes)(cchar, str);
7796 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007797 str[0] = cchar;
7798 }
7799 }
7800 }
7801
7802 list_append_number(rettv->vval.v_list,
7803 (syntax_flags & HL_CONCEAL) != 0);
7804 /* -1 to auto-determine strlen */
7805 list_append_string(rettv->vval.v_list, str, -1);
7806 list_append_number(rettv->vval.v_list, matchid);
7807 }
7808#endif
7809}
7810
7811/*
7812 * "synstack(lnum, col)" function
7813 */
7814 static void
7815f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7816{
7817#ifdef FEAT_SYN_HL
7818 linenr_T lnum;
7819 colnr_T col;
7820 int i;
7821 int id;
7822#endif
7823
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007824 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007825
7826#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007827 lnum = tv_get_lnum(argvars); /* -1 on type error */
7828 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007829
7830 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7831 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7832 && rettv_list_alloc(rettv) != FAIL)
7833 {
7834 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
7835 for (i = 0; ; ++i)
7836 {
7837 id = syn_get_stack_item(i);
7838 if (id < 0)
7839 break;
7840 if (list_append_number(rettv->vval.v_list, id) == FAIL)
7841 break;
7842 }
7843 }
7844#endif
7845}
7846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007847/*
7848 * "tabpagebuflist()" function
7849 */
7850 static void
7851f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7852{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007853 tabpage_T *tp;
7854 win_T *wp = NULL;
7855
7856 if (argvars[0].v_type == VAR_UNKNOWN)
7857 wp = firstwin;
7858 else
7859 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007860 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 if (tp != NULL)
7862 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
7863 }
7864 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
7865 {
7866 for (; wp != NULL; wp = wp->w_next)
7867 if (list_append_number(rettv->vval.v_list,
7868 wp->w_buffer->b_fnum) == FAIL)
7869 break;
7870 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007871}
7872
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007873/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874 * "tagfiles()" function
7875 */
7876 static void
7877f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
7878{
7879 char_u *fname;
7880 tagname_T tn;
7881 int first;
7882
7883 if (rettv_list_alloc(rettv) == FAIL)
7884 return;
7885 fname = alloc(MAXPATHL);
7886 if (fname == NULL)
7887 return;
7888
7889 for (first = TRUE; ; first = FALSE)
7890 if (get_tagfname(&tn, first, fname) == FAIL
7891 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
7892 break;
7893 tagname_free(&tn);
7894 vim_free(fname);
7895}
7896
7897/*
7898 * "taglist()" function
7899 */
7900 static void
7901f_taglist(typval_T *argvars, typval_T *rettv)
7902{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007903 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 char_u *tag_pattern;
7905
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007906 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007907
7908 rettv->vval.v_number = FALSE;
7909 if (*tag_pattern == NUL)
7910 return;
7911
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007912 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007913 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007915 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007916}
7917
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918#ifdef FEAT_FLOAT
7919/*
7920 * "tan()" function
7921 */
7922 static void
7923f_tan(typval_T *argvars, typval_T *rettv)
7924{
7925 float_T f = 0.0;
7926
7927 rettv->v_type = VAR_FLOAT;
7928 if (get_float_arg(argvars, &f) == OK)
7929 rettv->vval.v_float = tan(f);
7930 else
7931 rettv->vval.v_float = 0.0;
7932}
7933
7934/*
7935 * "tanh()" function
7936 */
7937 static void
7938f_tanh(typval_T *argvars, typval_T *rettv)
7939{
7940 float_T f = 0.0;
7941
7942 rettv->v_type = VAR_FLOAT;
7943 if (get_float_arg(argvars, &f) == OK)
7944 rettv->vval.v_float = tanh(f);
7945 else
7946 rettv->vval.v_float = 0.0;
7947}
7948#endif
7949
7950/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951 * "tolower(string)" function
7952 */
7953 static void
7954f_tolower(typval_T *argvars, typval_T *rettv)
7955{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007956 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007957 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007958}
7959
7960/*
7961 * "toupper(string)" function
7962 */
7963 static void
7964f_toupper(typval_T *argvars, typval_T *rettv)
7965{
7966 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007967 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007968}
7969
7970/*
7971 * "tr(string, fromstr, tostr)" function
7972 */
7973 static void
7974f_tr(typval_T *argvars, typval_T *rettv)
7975{
7976 char_u *in_str;
7977 char_u *fromstr;
7978 char_u *tostr;
7979 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007980 int inlen;
7981 int fromlen;
7982 int tolen;
7983 int idx;
7984 char_u *cpstr;
7985 int cplen;
7986 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987 char_u buf[NUMBUFLEN];
7988 char_u buf2[NUMBUFLEN];
7989 garray_T ga;
7990
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007991 in_str = tv_get_string(&argvars[0]);
7992 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
7993 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007994
7995 /* Default return value: empty string. */
7996 rettv->v_type = VAR_STRING;
7997 rettv->vval.v_string = NULL;
7998 if (fromstr == NULL || tostr == NULL)
7999 return; /* type error; errmsg already given */
8000 ga_init2(&ga, (int)sizeof(char), 80);
8001
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008002 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003 /* not multi-byte: fromstr and tostr must be the same length */
8004 if (STRLEN(fromstr) != STRLEN(tostr))
8005 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008006error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008007 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008 ga_clear(&ga);
8009 return;
8010 }
8011
8012 /* fromstr and tostr have to contain the same number of chars */
8013 while (*in_str != NUL)
8014 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008015 if (has_mbyte)
8016 {
8017 inlen = (*mb_ptr2len)(in_str);
8018 cpstr = in_str;
8019 cplen = inlen;
8020 idx = 0;
8021 for (p = fromstr; *p != NUL; p += fromlen)
8022 {
8023 fromlen = (*mb_ptr2len)(p);
8024 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8025 {
8026 for (p = tostr; *p != NUL; p += tolen)
8027 {
8028 tolen = (*mb_ptr2len)(p);
8029 if (idx-- == 0)
8030 {
8031 cplen = tolen;
8032 cpstr = p;
8033 break;
8034 }
8035 }
8036 if (*p == NUL) /* tostr is shorter than fromstr */
8037 goto error;
8038 break;
8039 }
8040 ++idx;
8041 }
8042
8043 if (first && cpstr == in_str)
8044 {
8045 /* Check that fromstr and tostr have the same number of
8046 * (multi-byte) characters. Done only once when a character
8047 * of in_str doesn't appear in fromstr. */
8048 first = FALSE;
8049 for (p = tostr; *p != NUL; p += tolen)
8050 {
8051 tolen = (*mb_ptr2len)(p);
8052 --idx;
8053 }
8054 if (idx != 0)
8055 goto error;
8056 }
8057
8058 (void)ga_grow(&ga, cplen);
8059 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8060 ga.ga_len += cplen;
8061
8062 in_str += inlen;
8063 }
8064 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008065 {
8066 /* When not using multi-byte chars we can do it faster. */
8067 p = vim_strchr(fromstr, *in_str);
8068 if (p != NULL)
8069 ga_append(&ga, tostr[p - fromstr]);
8070 else
8071 ga_append(&ga, *in_str);
8072 ++in_str;
8073 }
8074 }
8075
8076 /* add a terminating NUL */
8077 (void)ga_grow(&ga, 1);
8078 ga_append(&ga, NUL);
8079
8080 rettv->vval.v_string = ga.ga_data;
8081}
8082
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008083/*
8084 * "trim({expr})" function
8085 */
8086 static void
8087f_trim(typval_T *argvars, typval_T *rettv)
8088{
8089 char_u buf1[NUMBUFLEN];
8090 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008091 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008092 char_u *mask = NULL;
8093 char_u *tail;
8094 char_u *prev;
8095 char_u *p;
8096 int c1;
8097
8098 rettv->v_type = VAR_STRING;
8099 if (head == NULL)
8100 {
8101 rettv->vval.v_string = NULL;
8102 return;
8103 }
8104
8105 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008106 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008107
8108 while (*head != NUL)
8109 {
8110 c1 = PTR2CHAR(head);
8111 if (mask == NULL)
8112 {
8113 if (c1 > ' ' && c1 != 0xa0)
8114 break;
8115 }
8116 else
8117 {
8118 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8119 if (c1 == PTR2CHAR(p))
8120 break;
8121 if (*p == NUL)
8122 break;
8123 }
8124 MB_PTR_ADV(head);
8125 }
8126
8127 for (tail = head + STRLEN(head); tail > head; tail = prev)
8128 {
8129 prev = tail;
8130 MB_PTR_BACK(head, prev);
8131 c1 = PTR2CHAR(prev);
8132 if (mask == NULL)
8133 {
8134 if (c1 > ' ' && c1 != 0xa0)
8135 break;
8136 }
8137 else
8138 {
8139 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8140 if (c1 == PTR2CHAR(p))
8141 break;
8142 if (*p == NUL)
8143 break;
8144 }
8145 }
8146 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8147}
8148
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008149#ifdef FEAT_FLOAT
8150/*
8151 * "trunc({float})" function
8152 */
8153 static void
8154f_trunc(typval_T *argvars, typval_T *rettv)
8155{
8156 float_T f = 0.0;
8157
8158 rettv->v_type = VAR_FLOAT;
8159 if (get_float_arg(argvars, &f) == OK)
8160 /* trunc() is not in C90, use floor() or ceil() instead. */
8161 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8162 else
8163 rettv->vval.v_float = 0.0;
8164}
8165#endif
8166
8167/*
8168 * "type(expr)" function
8169 */
8170 static void
8171f_type(typval_T *argvars, typval_T *rettv)
8172{
8173 int n = -1;
8174
8175 switch (argvars[0].v_type)
8176 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008177 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8178 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008179 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008180 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8181 case VAR_LIST: n = VAR_TYPE_LIST; break;
8182 case VAR_DICT: n = VAR_TYPE_DICT; break;
8183 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008184 case VAR_SPECIAL:
8185 if (argvars[0].vval.v_number == VVAL_FALSE
8186 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008187 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008189 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008190 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008191 case VAR_JOB: n = VAR_TYPE_JOB; break;
8192 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008193 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008194 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008195 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008196 n = -1;
8197 break;
8198 }
8199 rettv->vval.v_number = n;
8200}
8201
8202/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008203 * "virtcol(string)" function
8204 */
8205 static void
8206f_virtcol(typval_T *argvars, typval_T *rettv)
8207{
8208 colnr_T vcol = 0;
8209 pos_T *fp;
8210 int fnum = curbuf->b_fnum;
8211
8212 fp = var2fpos(&argvars[0], FALSE, &fnum);
8213 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8214 && fnum == curbuf->b_fnum)
8215 {
8216 getvvcol(curwin, fp, NULL, NULL, &vcol);
8217 ++vcol;
8218 }
8219
8220 rettv->vval.v_number = vcol;
8221}
8222
8223/*
8224 * "visualmode()" function
8225 */
8226 static void
8227f_visualmode(typval_T *argvars, typval_T *rettv)
8228{
8229 char_u str[2];
8230
8231 rettv->v_type = VAR_STRING;
8232 str[0] = curbuf->b_visual_mode_eval;
8233 str[1] = NUL;
8234 rettv->vval.v_string = vim_strsave(str);
8235
8236 /* A non-zero number or non-empty string argument: reset mode. */
8237 if (non_zero_arg(&argvars[0]))
8238 curbuf->b_visual_mode_eval = NUL;
8239}
8240
8241/*
8242 * "wildmenumode()" function
8243 */
8244 static void
8245f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8246{
8247#ifdef FEAT_WILDMENU
8248 if (wild_menu_showing)
8249 rettv->vval.v_number = 1;
8250#endif
8251}
8252
8253/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008254 * "wordcount()" function
8255 */
8256 static void
8257f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8258{
8259 if (rettv_dict_alloc(rettv) == FAIL)
8260 return;
8261 cursor_pos_info(rettv->vval.v_dict);
8262}
8263
8264/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008265 * "xor(expr, expr)" function
8266 */
8267 static void
8268f_xor(typval_T *argvars, typval_T *rettv)
8269{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008270 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8271 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008272}
8273
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008274#endif /* FEAT_EVAL */