blob: 962c6c49bbb8c4d4e5a0831e660c802c9458d354 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaard0573012017-10-28 21:11:06 +020023#ifdef MACOS_X
Bram Moolenaar8d71b542019-08-30 15:46:30 +020024# include <time.h> // for time_t
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020025#endif
26
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027#ifdef FEAT_FLOAT
28static void f_abs(typval_T *argvars, typval_T *rettv);
29static void f_acos(typval_T *argvars, typval_T *rettv);
30#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020031static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020032#ifdef FEAT_FLOAT
33static void f_asin(typval_T *argvars, typval_T *rettv);
34static void f_atan(typval_T *argvars, typval_T *rettv);
35static void f_atan2(typval_T *argvars, typval_T *rettv);
36#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010037#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020038static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010039static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010040# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010041static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_byte2line(typval_T *argvars, typval_T *rettv);
45static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
46static void f_byteidx(typval_T *argvars, typval_T *rettv);
47static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
48static void f_call(typval_T *argvars, typval_T *rettv);
49#ifdef FEAT_FLOAT
50static void f_ceil(typval_T *argvars, typval_T *rettv);
51#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_changenr(typval_T *argvars, typval_T *rettv);
53static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020054static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_confirm(typval_T *argvars, typval_T *rettv);
56static void f_copy(typval_T *argvars, typval_T *rettv);
57#ifdef FEAT_FLOAT
58static void f_cos(typval_T *argvars, typval_T *rettv);
59static void f_cosh(typval_T *argvars, typval_T *rettv);
60#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020061static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010062#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020063static void f_debugbreak(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020065static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020068static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_escape(typval_T *argvars, typval_T *rettv);
70static void f_eval(typval_T *argvars, typval_T *rettv);
71static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_exists(typval_T *argvars, typval_T *rettv);
74#ifdef FEAT_FLOAT
75static void f_exp(typval_T *argvars, typval_T *rettv);
76#endif
77static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020078static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020079static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080#ifdef FEAT_FLOAT
81static void f_float2nr(typval_T *argvars, typval_T *rettv);
82static void f_floor(typval_T *argvars, typval_T *rettv);
83static void f_fmod(typval_T *argvars, typval_T *rettv);
84#endif
85static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020086static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020087static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020088static void f_function(typval_T *argvars, typval_T *rettv);
89static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
90static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010091static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020094static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020095static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010096static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020097static void f_getpid(typval_T *argvars, typval_T *rettv);
98static void f_getcurpos(typval_T *argvars, typval_T *rettv);
99static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200100static void f_getreg(typval_T *argvars, typval_T *rettv);
101static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100102static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200103static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
105static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200106static void f_hlID(typval_T *argvars, typval_T *rettv);
107static void f_hlexists(typval_T *argvars, typval_T *rettv);
108static void f_hostname(typval_T *argvars, typval_T *rettv);
109static void f_iconv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200110static void f_index(typval_T *argvars, typval_T *rettv);
111static void f_input(typval_T *argvars, typval_T *rettv);
112static void f_inputdialog(typval_T *argvars, typval_T *rettv);
113static void f_inputlist(typval_T *argvars, typval_T *rettv);
114static void f_inputrestore(typval_T *argvars, typval_T *rettv);
115static void f_inputsave(typval_T *argvars, typval_T *rettv);
116static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_islocked(typval_T *argvars, typval_T *rettv);
119#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200120static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200121static void f_isnan(typval_T *argvars, typval_T *rettv);
122#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200123static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
124static void f_len(typval_T *argvars, typval_T *rettv);
125static void f_libcall(typval_T *argvars, typval_T *rettv);
126static void f_libcallnr(typval_T *argvars, typval_T *rettv);
127static void f_line(typval_T *argvars, typval_T *rettv);
128static void f_line2byte(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_localtime(typval_T *argvars, typval_T *rettv);
130#ifdef FEAT_FLOAT
131static void f_log(typval_T *argvars, typval_T *rettv);
132static void f_log10(typval_T *argvars, typval_T *rettv);
133#endif
134#ifdef FEAT_LUA
135static void f_luaeval(typval_T *argvars, typval_T *rettv);
136#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200137static void f_maparg(typval_T *argvars, typval_T *rettv);
138static void f_mapcheck(typval_T *argvars, typval_T *rettv);
139static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200140static void f_matchend(typval_T *argvars, typval_T *rettv);
141static void f_matchlist(typval_T *argvars, typval_T *rettv);
142static void f_matchstr(typval_T *argvars, typval_T *rettv);
143static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
144static void f_max(typval_T *argvars, typval_T *rettv);
145static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200146#ifdef FEAT_MZSCHEME
147static void f_mzeval(typval_T *argvars, typval_T *rettv);
148#endif
149static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
150static void f_nr2char(typval_T *argvars, typval_T *rettv);
151static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200152#ifdef FEAT_PERL
153static void f_perleval(typval_T *argvars, typval_T *rettv);
154#endif
155#ifdef FEAT_FLOAT
156static void f_pow(typval_T *argvars, typval_T *rettv);
157#endif
158static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
159static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200160static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200161static void f_pumvisible(typval_T *argvars, typval_T *rettv);
162#ifdef FEAT_PYTHON3
163static void f_py3eval(typval_T *argvars, typval_T *rettv);
164#endif
165#ifdef FEAT_PYTHON
166static void f_pyeval(typval_T *argvars, typval_T *rettv);
167#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100168#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
169static void f_pyxeval(typval_T *argvars, typval_T *rettv);
170#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200171static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200172static void f_reg_executing(typval_T *argvars, typval_T *rettv);
173static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200174static void f_reltime(typval_T *argvars, typval_T *rettv);
175#ifdef FEAT_FLOAT
176static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
177#endif
178static void f_reltimestr(typval_T *argvars, typval_T *rettv);
179static void f_remote_expr(typval_T *argvars, typval_T *rettv);
180static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
181static void f_remote_peek(typval_T *argvars, typval_T *rettv);
182static void f_remote_read(typval_T *argvars, typval_T *rettv);
183static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100184static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200185static void f_rename(typval_T *argvars, typval_T *rettv);
186static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200187#ifdef FEAT_FLOAT
188static void f_round(typval_T *argvars, typval_T *rettv);
189#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100190#ifdef FEAT_RUBY
191static void f_rubyeval(typval_T *argvars, typval_T *rettv);
192#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200193static void f_screenattr(typval_T *argvars, typval_T *rettv);
194static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100195static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_screencol(typval_T *argvars, typval_T *rettv);
197static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100198static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200199static void f_search(typval_T *argvars, typval_T *rettv);
200static void f_searchdecl(typval_T *argvars, typval_T *rettv);
201static void f_searchpair(typval_T *argvars, typval_T *rettv);
202static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
203static void f_searchpos(typval_T *argvars, typval_T *rettv);
204static void f_server2client(typval_T *argvars, typval_T *rettv);
205static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200206static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200207static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200208static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200210static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100211static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200212#ifdef FEAT_CRYPT
213static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200214#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200215static void f_shellescape(typval_T *argvars, typval_T *rettv);
216static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200217#ifdef FEAT_FLOAT
218static void f_sin(typval_T *argvars, typval_T *rettv);
219static void f_sinh(typval_T *argvars, typval_T *rettv);
220#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_soundfold(typval_T *argvars, typval_T *rettv);
222static void f_spellbadword(typval_T *argvars, typval_T *rettv);
223static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
224static void f_split(typval_T *argvars, typval_T *rettv);
225#ifdef FEAT_FLOAT
226static void f_sqrt(typval_T *argvars, typval_T *rettv);
227static void f_str2float(typval_T *argvars, typval_T *rettv);
228#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200229static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200230static void f_str2nr(typval_T *argvars, typval_T *rettv);
231static void f_strchars(typval_T *argvars, typval_T *rettv);
232#ifdef HAVE_STRFTIME
233static void f_strftime(typval_T *argvars, typval_T *rettv);
234#endif
235static void f_strgetchar(typval_T *argvars, typval_T *rettv);
236static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200237static void f_strlen(typval_T *argvars, typval_T *rettv);
238static void f_strcharpart(typval_T *argvars, typval_T *rettv);
239static void f_strpart(typval_T *argvars, typval_T *rettv);
240static void f_strridx(typval_T *argvars, typval_T *rettv);
241static void f_strtrans(typval_T *argvars, typval_T *rettv);
242static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
243static void f_strwidth(typval_T *argvars, typval_T *rettv);
244static void f_submatch(typval_T *argvars, typval_T *rettv);
245static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200246static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200247static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200248static void f_synID(typval_T *argvars, typval_T *rettv);
249static void f_synIDattr(typval_T *argvars, typval_T *rettv);
250static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
251static void f_synstack(typval_T *argvars, typval_T *rettv);
252static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200253static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200254static void f_taglist(typval_T *argvars, typval_T *rettv);
255static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200256#ifdef FEAT_FLOAT
257static void f_tan(typval_T *argvars, typval_T *rettv);
258static void f_tanh(typval_T *argvars, typval_T *rettv);
259#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260static void f_tolower(typval_T *argvars, typval_T *rettv);
261static void f_toupper(typval_T *argvars, typval_T *rettv);
262static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100263static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264#ifdef FEAT_FLOAT
265static void f_trunc(typval_T *argvars, typval_T *rettv);
266#endif
267static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200268static void f_virtcol(typval_T *argvars, typval_T *rettv);
269static void f_visualmode(typval_T *argvars, typval_T *rettv);
270static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200271static void f_wordcount(typval_T *argvars, typval_T *rettv);
272static void f_xor(typval_T *argvars, typval_T *rettv);
273
274/*
275 * Array with names and number of arguments of all internal functions
276 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
277 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200278typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200279{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200280 char *f_name; // function name
281 char f_min_argc; // minimal number of arguments
282 char f_max_argc; // maximal number of arguments
283 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200284 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200285 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200286} funcentry_T;
287
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200288// values for f_argtype; zero means it cannot be used as a method
289#define FEARG_1 1 // base is the first argument
290#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200291#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200292#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200293#define FEARG_LAST 9 // base is the last argument
294
Bram Moolenaarac92e252019-08-03 21:58:38 +0200295static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200296{
297#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200298 {"abs", 1, 1, FEARG_1, f_abs},
299 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200300#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200301 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200302 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200303 {"append", 2, 2, FEARG_LAST, f_append},
304 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
305 {"argc", 0, 1, 0, f_argc},
306 {"argidx", 0, 0, 0, f_argidx},
307 {"arglistid", 0, 2, 0, f_arglistid},
308 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200309#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200310 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200311#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200312 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200313 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200314 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200315 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200316 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
317 {"assert_false", 1, 2, FEARG_1, f_assert_false},
318 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
319 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200320 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200321 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200322 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200323 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200324#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200325 {"atan", 1, 1, FEARG_1, f_atan},
326 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200327#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100328#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200329 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200330 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100331# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200332 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100333# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100334#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200335 {"browse", 4, 4, 0, f_browse},
336 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200337 {"bufadd", 1, 1, FEARG_1, f_bufadd},
338 {"bufexists", 1, 1, FEARG_1, f_bufexists},
339 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200340 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
341 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200342 {"buflisted", 1, 1, FEARG_1, f_buflisted},
343 {"bufload", 1, 1, FEARG_1, f_bufload},
344 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200345 {"bufname", 0, 1, FEARG_1, f_bufname},
346 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200347 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
348 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200349 {"byte2line", 1, 1, FEARG_1, f_byte2line},
350 {"byteidx", 2, 2, FEARG_1, f_byteidx},
351 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
352 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200354 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200355#endif
356#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200357 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
358 {"ch_close", 1, 1, FEARG_1, f_ch_close},
359 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
360 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
361 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
362 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
363 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
364 {"ch_info", 1, 1, FEARG_1, f_ch_info},
365 {"ch_log", 1, 2, FEARG_1, f_ch_log},
366 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
367 {"ch_open", 1, 2, FEARG_1, f_ch_open},
368 {"ch_read", 1, 2, FEARG_1, f_ch_read},
369 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
370 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
371 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
372 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
373 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
374 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200375#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200376 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200377 {"char2nr", 1, 2, FEARG_1, f_char2nr},
378 {"chdir", 1, 1, FEARG_1, f_chdir},
379 {"cindent", 1, 1, FEARG_1, f_cindent},
380 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
381 {"col", 1, 1, FEARG_1, f_col},
382 {"complete", 2, 2, FEARG_2, f_complete},
383 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200384 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200385 {"complete_info", 0, 1, FEARG_1, f_complete_info},
386 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200387 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200388#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200389 {"cos", 1, 1, FEARG_1, f_cos},
390 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200391#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200392 {"count", 2, 4, FEARG_1, f_count},
393 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200394 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100395#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200396 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200397#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200398 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
399 {"delete", 1, 2, FEARG_1, f_delete},
400 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200401 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200402 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
403 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200404 {"empty", 1, 1, FEARG_1, f_empty},
405 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200406 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200407 {"eval", 1, 1, FEARG_1, f_eval},
408 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200409 {"executable", 1, 1, FEARG_1, f_executable},
410 {"execute", 1, 2, FEARG_1, f_execute},
411 {"exepath", 1, 1, FEARG_1, f_exepath},
412 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200413#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200414 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200415#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200416 {"expand", 1, 3, FEARG_1, f_expand},
417 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200418 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200419 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
420 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
421 {"filereadable", 1, 1, FEARG_1, f_filereadable},
422 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200423 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200424 {"finddir", 1, 3, FEARG_1, f_finddir},
425 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200426#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200427 {"float2nr", 1, 1, FEARG_1, f_float2nr},
428 {"floor", 1, 1, FEARG_1, f_floor},
429 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200430#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200431 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
432 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
433 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
434 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
435 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200436 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200437 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200438 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200439 {"funcref", 1, 3, FEARG_1, f_funcref},
440 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200441 {"garbagecollect", 0, 1, 0, f_garbagecollect},
442 {"get", 2, 3, FEARG_1, f_get},
443 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200444 {"getbufline", 2, 3, FEARG_1, f_getbufline},
445 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
446 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200447 {"getchar", 0, 1, 0, f_getchar},
448 {"getcharmod", 0, 0, 0, f_getcharmod},
449 {"getcharsearch", 0, 0, 0, f_getcharsearch},
450 {"getcmdline", 0, 0, 0, f_getcmdline},
451 {"getcmdpos", 0, 0, 0, f_getcmdpos},
452 {"getcmdtype", 0, 0, 0, f_getcmdtype},
453 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200454 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200455 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200456 {"getcwd", 0, 2, FEARG_1, f_getcwd},
457 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200458 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200459 {"getfperm", 1, 1, FEARG_1, f_getfperm},
460 {"getfsize", 1, 1, FEARG_1, f_getfsize},
461 {"getftime", 1, 1, FEARG_1, f_getftime},
462 {"getftype", 1, 1, FEARG_1, f_getftype},
Bram Moolenaara3a12462019-09-07 15:08:38 +0200463 {"getimstatus", 0, 0, 0, f_getimstatus},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200464 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
465 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200466 {"getloclist", 1, 2, 0, f_getloclist},
467 {"getmatches", 0, 1, 0, f_getmatches},
468 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200469 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200470 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200471 {"getreg", 0, 3, FEARG_1, f_getreg},
472 {"getregtype", 0, 1, FEARG_1, f_getregtype},
473 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
474 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
475 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200476 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
477 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
478 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200479 {"getwinposx", 0, 0, 0, f_getwinposx},
480 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200481 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
482 {"glob", 1, 4, FEARG_1, f_glob},
483 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
484 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200485 {"has", 1, 1, 0, f_has},
486 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200487 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
488 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
489 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
490 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
491 {"histadd", 2, 2, FEARG_2, f_histadd},
492 {"histdel", 1, 2, FEARG_1, f_histdel},
493 {"histget", 1, 2, FEARG_1, f_histget},
494 {"histnr", 1, 1, FEARG_1, f_histnr},
495 {"hlID", 1, 1, FEARG_1, f_hlID},
496 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200497 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200498 {"iconv", 3, 3, FEARG_1, f_iconv},
499 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200500 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200501 {"input", 1, 3, FEARG_1, f_input},
502 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
503 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"inputrestore", 0, 0, 0, f_inputrestore},
505 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200506 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200507 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200508 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200509 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200510#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200511 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200512#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200513 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200514#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200515 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200516#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200517 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200518#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200519 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
520 {"job_info", 0, 1, FEARG_1, f_job_info},
521 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
522 {"job_start", 1, 2, FEARG_1, f_job_start},
523 {"job_status", 1, 1, FEARG_1, f_job_status},
524 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200526 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200527 {"js_decode", 1, 1, FEARG_1, f_js_decode},
528 {"js_encode", 1, 1, FEARG_1, f_js_encode},
529 {"json_decode", 1, 1, FEARG_1, f_json_decode},
530 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200531 {"keys", 1, 1, FEARG_1, f_keys},
532 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
533 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200534 {"libcall", 3, 3, FEARG_3, f_libcall},
535 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200536 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200537 {"line2byte", 1, 1, FEARG_1, f_line2byte},
538 {"lispindent", 1, 1, FEARG_1, f_lispindent},
539 {"list2str", 1, 2, FEARG_1, f_list2str},
540 {"listener_add", 1, 2, FEARG_2, f_listener_add},
541 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
542 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200543 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200544#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200545 {"log", 1, 1, FEARG_1, f_log},
546 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200547#endif
548#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200549 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200551 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200552 {"maparg", 1, 4, FEARG_1, f_maparg},
553 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
554 {"match", 2, 4, FEARG_1, f_match},
555 {"matchadd", 2, 5, FEARG_1, f_matchadd},
556 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
557 {"matcharg", 1, 1, FEARG_1, f_matcharg},
558 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
559 {"matchend", 2, 4, FEARG_1, f_matchend},
560 {"matchlist", 2, 4, FEARG_1, f_matchlist},
561 {"matchstr", 2, 4, FEARG_1, f_matchstr},
562 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200563 {"max", 1, 1, FEARG_1, f_max},
564 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200565 {"mkdir", 1, 3, FEARG_1, f_mkdir},
566 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200567#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200568 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200569#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200570 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
571 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200572 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200573 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200574#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200575 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200576#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200577#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200578 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
579 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200580 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200581 {"popup_close", 1, 2, FEARG_1, f_popup_close},
582 {"popup_create", 2, 2, FEARG_1, f_popup_create},
583 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200584 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
585 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200586 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
587 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200588 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
589 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
590 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200591 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200592 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
593 {"popup_move", 2, 2, FEARG_1, f_popup_move},
594 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
595 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
596 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
597 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200598#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200599#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200600 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200602 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200603 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200604#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200605 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
606 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
607 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200608#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100609#ifdef FEAT_TEXT_PROP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200610 {"prop_add", 3, 3, FEARG_1, f_prop_add},
611 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
612 {"prop_list", 1, 2, FEARG_1, f_prop_list},
613 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
614 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
615 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
616 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
617 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
618 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100619#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200620 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200621 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200622#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200623 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200624#endif
625#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200626 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200627#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100628#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200629 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100630#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200631 {"range", 1, 3, FEARG_1, f_range},
632 {"readdir", 1, 2, FEARG_1, f_readdir},
633 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200634 {"reg_executing", 0, 0, 0, f_reg_executing},
635 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200636 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200638 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200639#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200640 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
641 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
642 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
643 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
644 {"remote_read", 1, 2, FEARG_1, f_remote_read},
645 {"remote_send", 2, 3, FEARG_1, f_remote_send},
646 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200647 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200648 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200649 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200650 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200651 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200652#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200653 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200654#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100655#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200656 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100657#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200658 {"screenattr", 2, 2, FEARG_1, f_screenattr},
659 {"screenchar", 2, 2, FEARG_1, f_screenchar},
660 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200661 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200662 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200663 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200664 {"screenstring", 2, 2, FEARG_1, f_screenstring},
665 {"search", 1, 4, FEARG_1, f_search},
666 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200667 {"searchpair", 3, 7, 0, f_searchpair},
668 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200669 {"searchpos", 1, 4, FEARG_1, f_searchpos},
670 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200671 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200672 {"setbufline", 3, 3, FEARG_3, f_setbufline},
673 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
674 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
675 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
676 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200677 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200678 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200679 {"setloclist", 2, 4, FEARG_2, f_setloclist},
680 {"setmatches", 1, 2, FEARG_1, f_setmatches},
681 {"setpos", 2, 2, FEARG_2, f_setpos},
682 {"setqflist", 1, 3, FEARG_1, f_setqflist},
683 {"setreg", 2, 3, FEARG_2, f_setreg},
684 {"settabvar", 3, 3, FEARG_3, f_settabvar},
685 {"settabwinvar", 4, 4, FEARG_4, f_settabwinvar},
686 {"settagstack", 2, 3, FEARG_2, f_settagstack},
687 {"setwinvar", 3, 3, FEARG_3, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688#ifdef FEAT_CRYPT
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200689 {"sha256", 1, 1, FEARG_1, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200690#endif
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200691 {"shellescape", 1, 2, FEARG_1, f_shellescape},
692 {"shiftwidth", 0, 1, FEARG_1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100693#ifdef FEAT_SIGNS
Bram Moolenaar93476fd2019-09-06 22:00:54 +0200694 {"sign_define", 1, 2, FEARG_1, f_sign_define},
695 {"sign_getdefined", 0, 1, FEARG_1, f_sign_getdefined},
696 {"sign_getplaced", 0, 2, FEARG_1, f_sign_getplaced},
697 {"sign_jump", 3, 3, FEARG_1, f_sign_jump},
698 {"sign_place", 4, 5, FEARG_1, f_sign_place},
699 {"sign_placelist", 1, 1, FEARG_1, f_sign_placelist},
700 {"sign_undefine", 0, 1, FEARG_1, f_sign_undefine},
701 {"sign_unplace", 1, 2, FEARG_1, f_sign_unplace},
702 {"sign_unplacelist", 1, 2, FEARG_1, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100703#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200704 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200705#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200706 {"sin", 1, 1, FEARG_1, f_sin},
707 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200708#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200709 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200710#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200711 {"sound_clear", 0, 0, 0, f_sound_clear},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200712 {"sound_playevent", 1, 2, FEARG_1, f_sound_playevent},
713 {"sound_playfile", 1, 2, FEARG_1, f_sound_playfile},
714 {"sound_stop", 1, 1, FEARG_1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200715#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200716 {"soundfold", 1, 1, FEARG_1, f_soundfold},
717 {"spellbadword", 0, 1, FEARG_1, f_spellbadword},
718 {"spellsuggest", 1, 3, FEARG_1, f_spellsuggest},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200719 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200720#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200721 {"sqrt", 1, 1, FEARG_1, f_sqrt},
Bram Moolenaar0e57dd82019-09-16 22:56:03 +0200722#endif
723 {"state", 0, 1, FEARG_1, f_state},
724#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200725 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200726#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200727 {"str2list", 1, 2, FEARG_1, f_str2list},
Bram Moolenaar60a8de22019-09-15 14:33:22 +0200728 {"str2nr", 1, 3, FEARG_1, f_str2nr},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200729 {"strcharpart", 2, 3, FEARG_1, f_strcharpart},
730 {"strchars", 1, 2, FEARG_1, f_strchars},
731 {"strdisplaywidth", 1, 2, FEARG_1, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200732#ifdef HAVE_STRFTIME
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200733 {"strftime", 1, 2, FEARG_1, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200734#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200735 {"strgetchar", 2, 2, FEARG_1, f_strgetchar},
736 {"stridx", 2, 3, FEARG_1, f_stridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200737 {"string", 1, 1, FEARG_1, f_string},
738 {"strlen", 1, 1, FEARG_1, f_strlen},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200739 {"strpart", 2, 3, FEARG_1, f_strpart},
740 {"strridx", 2, 3, FEARG_1, f_strridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200741 {"strtrans", 1, 1, FEARG_1, f_strtrans},
742 {"strwidth", 1, 1, FEARG_1, f_strwidth},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200743 {"submatch", 1, 2, FEARG_1, f_submatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200744 {"substitute", 4, 4, FEARG_1, f_substitute},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200745 {"swapinfo", 1, 1, FEARG_1, f_swapinfo},
746 {"swapname", 1, 1, FEARG_1, f_swapname},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200747 {"synID", 3, 3, 0, f_synID},
748 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
749 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
750 {"synconcealed", 2, 2, 0, f_synconcealed},
751 {"synstack", 2, 2, 0, f_synstack},
752 {"system", 1, 2, FEARG_1, f_system},
753 {"systemlist", 1, 2, FEARG_1, f_systemlist},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200754 {"tabpagebuflist", 0, 1, FEARG_1, f_tabpagebuflist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200755 {"tabpagenr", 0, 1, 0, f_tabpagenr},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200756 {"tabpagewinnr", 1, 2, FEARG_1, f_tabpagewinnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200757 {"tagfiles", 0, 0, 0, f_tagfiles},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200758 {"taglist", 1, 2, FEARG_1, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200759#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200760 {"tan", 1, 1, FEARG_1, f_tan},
761 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200762#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200763 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200764#ifdef FEAT_TERMINAL
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200765 {"term_dumpdiff", 2, 3, FEARG_1, f_term_dumpdiff},
766 {"term_dumpload", 1, 2, FEARG_1, f_term_dumpload},
767 {"term_dumpwrite", 2, 3, FEARG_2, f_term_dumpwrite},
768 {"term_getaltscreen", 1, 1, FEARG_1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200769# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200770 {"term_getansicolors", 1, 1, FEARG_1, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200771# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200772 {"term_getattr", 2, 2, FEARG_1, f_term_getattr},
773 {"term_getcursor", 1, 1, FEARG_1, f_term_getcursor},
774 {"term_getjob", 1, 1, FEARG_1, f_term_getjob},
775 {"term_getline", 2, 2, FEARG_1, f_term_getline},
776 {"term_getscrolled", 1, 1, FEARG_1, f_term_getscrolled},
777 {"term_getsize", 1, 1, FEARG_1, f_term_getsize},
778 {"term_getstatus", 1, 1, FEARG_1, f_term_getstatus},
779 {"term_gettitle", 1, 1, FEARG_1, f_term_gettitle},
780 {"term_gettty", 1, 2, FEARG_1, f_term_gettty},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200781 {"term_list", 0, 0, 0, f_term_list},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200782 {"term_scrape", 2, 2, FEARG_1, f_term_scrape},
783 {"term_sendkeys", 2, 2, FEARG_1, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200784# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200785 {"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200786# endif
Bram Moolenaard2842ea2019-09-26 23:08:54 +0200787 {"term_setapi", 2, 2, FEARG_1, f_term_setapi},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200788 {"term_setkill", 2, 2, FEARG_1, f_term_setkill},
789 {"term_setrestore", 2, 2, FEARG_1, f_term_setrestore},
790 {"term_setsize", 3, 3, FEARG_1, f_term_setsize},
791 {"term_start", 1, 2, FEARG_1, f_term_start},
792 {"term_wait", 1, 2, FEARG_1, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200793#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200794 {"test_alloc_fail", 3, 3, FEARG_1, f_test_alloc_fail},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200795 {"test_autochdir", 0, 0, 0, f_test_autochdir},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200796 {"test_feedinput", 1, 1, FEARG_1, f_test_feedinput},
797 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
798 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
799 {"test_getvalue", 1, 1, FEARG_1, f_test_getvalue},
800 {"test_ignore_error", 1, 1, FEARG_1, f_test_ignore_error},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200801 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200802#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200803 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200805 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200806#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200807 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200808#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200809 {"test_null_list", 0, 0, 0, f_test_null_list},
810 {"test_null_partial", 0, 0, 0, f_test_null_partial},
811 {"test_null_string", 0, 0, 0, f_test_null_string},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200812 {"test_option_not_set", 1, 1, FEARG_1, f_test_option_not_set},
813 {"test_override", 2, 2, FEARG_2, f_test_override},
814 {"test_refcount", 1, 1, FEARG_1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200815#ifdef FEAT_GUI
Bram Moolenaarce90e362019-09-08 18:58:44 +0200816 {"test_scrollbar", 3, 3, FEARG_2, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200817#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200818#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200819 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200820#endif
Bram Moolenaarce90e362019-09-08 18:58:44 +0200821 {"test_settime", 1, 1, FEARG_1, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822#ifdef FEAT_TIMERS
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200823 {"timer_info", 0, 1, FEARG_1, f_timer_info},
824 {"timer_pause", 2, 2, FEARG_1, f_timer_pause},
825 {"timer_start", 2, 3, FEARG_1, f_timer_start},
826 {"timer_stop", 1, 1, FEARG_1, f_timer_stop},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200827 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200828#endif
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200829 {"tolower", 1, 1, FEARG_1, f_tolower},
830 {"toupper", 1, 1, FEARG_1, f_toupper},
831 {"tr", 3, 3, FEARG_1, f_tr},
832 {"trim", 1, 2, FEARG_1, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200833#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200834 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200835#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200836 {"type", 1, 1, FEARG_1, f_type},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200837 {"undofile", 1, 1, FEARG_1, f_undofile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200838 {"undotree", 0, 0, 0, f_undotree},
839 {"uniq", 1, 3, FEARG_1, f_uniq},
840 {"values", 1, 1, FEARG_1, f_values},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200841 {"virtcol", 1, 1, FEARG_1, f_virtcol},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200842 {"visualmode", 0, 1, 0, f_visualmode},
843 {"wildmenumode", 0, 0, 0, f_wildmenumode},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200844 {"win_execute", 2, 3, FEARG_2, f_win_execute},
845 {"win_findbuf", 1, 1, FEARG_1, f_win_findbuf},
846 {"win_getid", 0, 2, FEARG_1, f_win_getid},
847 {"win_gotoid", 1, 1, FEARG_1, f_win_gotoid},
848 {"win_id2tabwin", 1, 1, FEARG_1, f_win_id2tabwin},
849 {"win_id2win", 1, 1, FEARG_1, f_win_id2win},
850 {"win_screenpos", 1, 1, FEARG_1, f_win_screenpos},
Bram Moolenaard20dcb32019-09-10 21:22:58 +0200851 {"win_splitmove", 2, 3, FEARG_1, f_win_splitmove},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200852 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200853 {"wincol", 0, 0, 0, f_wincol},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200854 {"winheight", 1, 1, FEARG_1, f_winheight},
855 {"winlayout", 0, 1, FEARG_1, f_winlayout},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200856 {"winline", 0, 0, 0, f_winline},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200857 {"winnr", 0, 1, FEARG_1, f_winnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200858 {"winrestcmd", 0, 0, 0, f_winrestcmd},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200859 {"winrestview", 1, 1, FEARG_1, f_winrestview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200860 {"winsaveview", 0, 0, 0, f_winsaveview},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200861 {"winwidth", 1, 1, FEARG_1, f_winwidth},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200862 {"wordcount", 0, 0, 0, f_wordcount},
Bram Moolenaarf92e58c2019-09-08 21:51:41 +0200863 {"writefile", 2, 3, FEARG_1, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200864 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200865};
866
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200867/*
868 * Function given to ExpandGeneric() to obtain the list of internal
869 * or user defined function names.
870 */
871 char_u *
872get_function_name(expand_T *xp, int idx)
873{
874 static int intidx = -1;
875 char_u *name;
876
877 if (idx == 0)
878 intidx = -1;
879 if (intidx < 0)
880 {
881 name = get_user_func_name(xp, idx);
882 if (name != NULL)
883 return name;
884 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200885 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200886 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200887 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200888 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200889 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200890 STRCAT(IObuff, ")");
891 return IObuff;
892 }
893
894 return NULL;
895}
896
897/*
898 * Function given to ExpandGeneric() to obtain the list of internal or
899 * user defined variable or function names.
900 */
901 char_u *
902get_expr_name(expand_T *xp, int idx)
903{
904 static int intidx = -1;
905 char_u *name;
906
907 if (idx == 0)
908 intidx = -1;
909 if (intidx < 0)
910 {
911 name = get_function_name(xp, idx);
912 if (name != NULL)
913 return name;
914 }
915 return get_user_var_name(xp, ++intidx);
916}
917
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200919 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920 * Return index, or -1 if not found
921 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200922 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200923find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200924{
925 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200926 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200927 int cmp;
928 int x;
929
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200930 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200931
932 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200933 while (first <= last)
934 {
935 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200936 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200937 if (cmp < 0)
938 last = x - 1;
939 else if (cmp > 0)
940 first = x + 1;
941 else
942 return x;
943 }
944 return -1;
945}
946
947 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200948has_internal_func(char_u *name)
949{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200950 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200951}
952
953 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200954call_internal_func(
955 char_u *name,
956 int argcount,
957 typval_T *argvars,
958 typval_T *rettv)
959{
960 int i;
961
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200962 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200963 if (i < 0)
964 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200965 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200966 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200967 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200968 return ERROR_TOOMANY;
969 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200970 global_functions[i].f_func(argvars, rettv);
971 return ERROR_NONE;
972}
973
974/*
975 * Invoke a method for base->method().
976 */
977 int
978call_internal_method(
979 char_u *name,
980 int argcount,
981 typval_T *argvars,
982 typval_T *rettv,
983 typval_T *basetv)
984{
985 int i;
986 int fi;
987 typval_T argv[MAX_FUNC_ARGS + 1];
988
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200989 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +0200990 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200991 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +0200992 if (global_functions[fi].f_argtype == 0)
993 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200994 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200995 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200996 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +0200997 return ERROR_TOOMANY;
998
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200999 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001000 {
1001 // base value goes last
1002 for (i = 0; i < argcount; ++i)
1003 argv[i] = argvars[i];
1004 argv[argcount] = *basetv;
1005 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001006 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001007 {
1008 // base value goes second
1009 argv[0] = argvars[0];
1010 argv[1] = *basetv;
1011 for (i = 1; i < argcount; ++i)
1012 argv[i + 1] = argvars[i];
1013 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001014 else if (global_functions[fi].f_argtype == FEARG_3)
1015 {
1016 // base value goes third
1017 argv[0] = argvars[0];
1018 argv[1] = argvars[1];
1019 argv[2] = *basetv;
1020 for (i = 2; i < argcount; ++i)
1021 argv[i + 1] = argvars[i];
1022 }
Bram Moolenaaraad222c2019-09-06 22:46:09 +02001023 else if (global_functions[fi].f_argtype == FEARG_4)
1024 {
1025 // base value goes fourth
1026 argv[0] = argvars[0];
1027 argv[1] = argvars[1];
1028 argv[2] = argvars[2];
1029 argv[3] = *basetv;
1030 for (i = 3; i < argcount; ++i)
1031 argv[i + 1] = argvars[i];
1032 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001033 else
1034 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001035 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001036 argv[0] = *basetv;
1037 for (i = 0; i < argcount; ++i)
1038 argv[i + 1] = argvars[i];
1039 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001040 argv[argcount + 1].v_type = VAR_UNKNOWN;
1041
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001042 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001043 return ERROR_NONE;
1044}
1045
1046/*
1047 * Return TRUE for a non-zero Number and a non-empty String.
1048 */
Bram Moolenaar0e57dd82019-09-16 22:56:03 +02001049 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001050non_zero_arg(typval_T *argvars)
1051{
1052 return ((argvars[0].v_type == VAR_NUMBER
1053 && argvars[0].vval.v_number != 0)
1054 || (argvars[0].v_type == VAR_SPECIAL
1055 && argvars[0].vval.v_number == VVAL_TRUE)
1056 || (argvars[0].v_type == VAR_STRING
1057 && argvars[0].vval.v_string != NULL
1058 && *argvars[0].vval.v_string != NUL));
1059}
1060
1061/*
1062 * Get the lnum from the first argument.
1063 * Also accepts ".", "$", etc., but that only works for the current buffer.
1064 * Returns -1 on error.
1065 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001066 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001067tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001068{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001069 linenr_T lnum;
1070
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001071 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001072 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001073 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001074 int fnum;
1075 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1076
1077 if (fp != NULL)
1078 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001079 }
1080 return lnum;
1081}
1082
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001083/*
1084 * Get the lnum from the first argument.
1085 * Also accepts "$", then "buf" is used.
1086 * Returns 0 on error.
1087 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001088 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001089tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1090{
1091 if (argvars[0].v_type == VAR_STRING
1092 && argvars[0].vval.v_string != NULL
1093 && argvars[0].vval.v_string[0] == '$'
1094 && buf != NULL)
1095 return buf->b_ml.ml_line_count;
1096 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1097}
1098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001099#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001100/*
1101 * Get the float value of "argvars[0]" into "f".
1102 * Returns FAIL when the argument is not a Number or Float.
1103 */
1104 static int
1105get_float_arg(typval_T *argvars, float_T *f)
1106{
1107 if (argvars[0].v_type == VAR_FLOAT)
1108 {
1109 *f = argvars[0].vval.v_float;
1110 return OK;
1111 }
1112 if (argvars[0].v_type == VAR_NUMBER)
1113 {
1114 *f = (float_T)argvars[0].vval.v_number;
1115 return OK;
1116 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001117 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001118 return FAIL;
1119}
1120
1121/*
1122 * "abs(expr)" function
1123 */
1124 static void
1125f_abs(typval_T *argvars, typval_T *rettv)
1126{
1127 if (argvars[0].v_type == VAR_FLOAT)
1128 {
1129 rettv->v_type = VAR_FLOAT;
1130 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1131 }
1132 else
1133 {
1134 varnumber_T n;
1135 int error = FALSE;
1136
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001137 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001138 if (error)
1139 rettv->vval.v_number = -1;
1140 else if (n > 0)
1141 rettv->vval.v_number = n;
1142 else
1143 rettv->vval.v_number = -n;
1144 }
1145}
1146
1147/*
1148 * "acos()" function
1149 */
1150 static void
1151f_acos(typval_T *argvars, typval_T *rettv)
1152{
1153 float_T f = 0.0;
1154
1155 rettv->v_type = VAR_FLOAT;
1156 if (get_float_arg(argvars, &f) == OK)
1157 rettv->vval.v_float = acos(f);
1158 else
1159 rettv->vval.v_float = 0.0;
1160}
1161#endif
1162
1163/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001164 * "and(expr, expr)" function
1165 */
1166 static void
1167f_and(typval_T *argvars, typval_T *rettv)
1168{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001169 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1170 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001171}
1172
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001173#ifdef FEAT_FLOAT
1174/*
1175 * "asin()" function
1176 */
1177 static void
1178f_asin(typval_T *argvars, typval_T *rettv)
1179{
1180 float_T f = 0.0;
1181
1182 rettv->v_type = VAR_FLOAT;
1183 if (get_float_arg(argvars, &f) == OK)
1184 rettv->vval.v_float = asin(f);
1185 else
1186 rettv->vval.v_float = 0.0;
1187}
1188
1189/*
1190 * "atan()" function
1191 */
1192 static void
1193f_atan(typval_T *argvars, typval_T *rettv)
1194{
1195 float_T f = 0.0;
1196
1197 rettv->v_type = VAR_FLOAT;
1198 if (get_float_arg(argvars, &f) == OK)
1199 rettv->vval.v_float = atan(f);
1200 else
1201 rettv->vval.v_float = 0.0;
1202}
1203
1204/*
1205 * "atan2()" function
1206 */
1207 static void
1208f_atan2(typval_T *argvars, typval_T *rettv)
1209{
1210 float_T fx = 0.0, fy = 0.0;
1211
1212 rettv->v_type = VAR_FLOAT;
1213 if (get_float_arg(argvars, &fx) == OK
1214 && get_float_arg(&argvars[1], &fy) == OK)
1215 rettv->vval.v_float = atan2(fx, fy);
1216 else
1217 rettv->vval.v_float = 0.0;
1218}
1219#endif
1220
1221/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001222 * "balloon_show()" function
1223 */
1224#ifdef FEAT_BEVAL
1225 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001226f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1227{
1228 rettv->v_type = VAR_STRING;
1229 if (balloonEval != NULL)
1230 {
1231 if (balloonEval->msg == NULL)
1232 rettv->vval.v_string = NULL;
1233 else
1234 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1235 }
1236}
1237
1238 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001239f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1240{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001241 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001242 {
1243 if (argvars[0].v_type == VAR_LIST
1244# ifdef FEAT_GUI
1245 && !gui.in_use
1246# endif
1247 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001248 {
1249 list_T *l = argvars[0].vval.v_list;
1250
1251 // empty list removes the balloon
1252 post_balloon(balloonEval, NULL,
1253 l == NULL || l->lv_len == 0 ? NULL : l);
1254 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001255 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001256 {
1257 char_u *mesg = tv_get_string_chk(&argvars[0]);
1258
1259 if (mesg != NULL)
1260 // empty string removes the balloon
1261 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1262 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001263 }
1264}
1265
Bram Moolenaar669a8282017-11-19 20:13:05 +01001266# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001267 static void
1268f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1269{
1270 if (rettv_list_alloc(rettv) == OK)
1271 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001272 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001273
1274 if (msg != NULL)
1275 {
1276 pumitem_T *array;
1277 int size = split_message(msg, &array);
1278 int i;
1279
1280 /* Skip the first and last item, they are always empty. */
1281 for (i = 1; i < size - 1; ++i)
1282 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001283 while (size > 0)
1284 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001285 vim_free(array);
1286 }
1287 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001288}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001289# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001290#endif
1291
1292/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293 * Get buffer by number or pattern.
1294 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001295 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001296tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001297{
1298 char_u *name = tv->vval.v_string;
1299 buf_T *buf;
1300
1301 if (tv->v_type == VAR_NUMBER)
1302 return buflist_findnr((int)tv->vval.v_number);
1303 if (tv->v_type != VAR_STRING)
1304 return NULL;
1305 if (name == NULL || *name == NUL)
1306 return curbuf;
1307 if (name[0] == '$' && name[1] == NUL)
1308 return lastbuf;
1309
1310 buf = buflist_find_by_name(name, curtab_only);
1311
1312 /* If not found, try expanding the name, like done for bufexists(). */
1313 if (buf == NULL)
1314 buf = find_buffer(tv);
1315
1316 return buf;
1317}
1318
1319/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001320 * Get the buffer from "arg" and give an error and return NULL if it is not
1321 * valid.
1322 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001323 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001324get_buf_arg(typval_T *arg)
1325{
1326 buf_T *buf;
1327
1328 ++emsg_off;
1329 buf = tv_get_buf(arg, FALSE);
1330 --emsg_off;
1331 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001332 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001333 return buf;
1334}
1335
1336/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001337 * "byte2line(byte)" function
1338 */
1339 static void
1340f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1341{
1342#ifndef FEAT_BYTEOFF
1343 rettv->vval.v_number = -1;
1344#else
1345 long boff = 0;
1346
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001347 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001348 if (boff < 0)
1349 rettv->vval.v_number = -1;
1350 else
1351 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1352 (linenr_T)0, &boff);
1353#endif
1354}
1355
1356 static void
1357byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1358{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001359 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001360 char_u *str;
1361 varnumber_T idx;
1362
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001363 str = tv_get_string_chk(&argvars[0]);
1364 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001365 rettv->vval.v_number = -1;
1366 if (str == NULL || idx < 0)
1367 return;
1368
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001369 t = str;
1370 for ( ; idx > 0; idx--)
1371 {
1372 if (*t == NUL) /* EOL reached */
1373 return;
1374 if (enc_utf8 && comp)
1375 t += utf_ptr2len(t);
1376 else
1377 t += (*mb_ptr2len)(t);
1378 }
1379 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001380}
1381
1382/*
1383 * "byteidx()" function
1384 */
1385 static void
1386f_byteidx(typval_T *argvars, typval_T *rettv)
1387{
1388 byteidx(argvars, rettv, FALSE);
1389}
1390
1391/*
1392 * "byteidxcomp()" function
1393 */
1394 static void
1395f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1396{
1397 byteidx(argvars, rettv, TRUE);
1398}
1399
1400/*
1401 * "call(func, arglist [, dict])" function
1402 */
1403 static void
1404f_call(typval_T *argvars, typval_T *rettv)
1405{
1406 char_u *func;
1407 partial_T *partial = NULL;
1408 dict_T *selfdict = NULL;
1409
1410 if (argvars[1].v_type != VAR_LIST)
1411 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001412 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001413 return;
1414 }
1415 if (argvars[1].vval.v_list == NULL)
1416 return;
1417
1418 if (argvars[0].v_type == VAR_FUNC)
1419 func = argvars[0].vval.v_string;
1420 else if (argvars[0].v_type == VAR_PARTIAL)
1421 {
1422 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001423 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001424 }
1425 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001426 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001427 if (*func == NUL)
1428 return; /* type error or empty name */
1429
1430 if (argvars[2].v_type != VAR_UNKNOWN)
1431 {
1432 if (argvars[2].v_type != VAR_DICT)
1433 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001434 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001435 return;
1436 }
1437 selfdict = argvars[2].vval.v_dict;
1438 }
1439
1440 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1441}
1442
1443#ifdef FEAT_FLOAT
1444/*
1445 * "ceil({float})" function
1446 */
1447 static void
1448f_ceil(typval_T *argvars, typval_T *rettv)
1449{
1450 float_T f = 0.0;
1451
1452 rettv->v_type = VAR_FLOAT;
1453 if (get_float_arg(argvars, &f) == OK)
1454 rettv->vval.v_float = ceil(f);
1455 else
1456 rettv->vval.v_float = 0.0;
1457}
1458#endif
1459
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001460/*
1461 * "changenr()" function
1462 */
1463 static void
1464f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1465{
1466 rettv->vval.v_number = curbuf->b_u_seq_cur;
1467}
1468
1469/*
1470 * "char2nr(string)" function
1471 */
1472 static void
1473f_char2nr(typval_T *argvars, typval_T *rettv)
1474{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001475 if (has_mbyte)
1476 {
1477 int utf8 = 0;
1478
1479 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001480 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001481
1482 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001483 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001484 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001485 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001486 }
1487 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001488 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001489}
1490
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001491 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001492get_optional_window(typval_T *argvars, int idx)
1493{
1494 win_T *win = curwin;
1495
1496 if (argvars[idx].v_type != VAR_UNKNOWN)
1497 {
1498 win = find_win_by_nr_or_id(&argvars[idx]);
1499 if (win == NULL)
1500 {
1501 emsg(_(e_invalwindow));
1502 return NULL;
1503 }
1504 }
1505 return win;
1506}
1507
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001508/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001509 * "col(string)" function
1510 */
1511 static void
1512f_col(typval_T *argvars, typval_T *rettv)
1513{
1514 colnr_T col = 0;
1515 pos_T *fp;
1516 int fnum = curbuf->b_fnum;
1517
1518 fp = var2fpos(&argvars[0], FALSE, &fnum);
1519 if (fp != NULL && fnum == curbuf->b_fnum)
1520 {
1521 if (fp->col == MAXCOL)
1522 {
1523 /* '> can be MAXCOL, get the length of the line then */
1524 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1525 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1526 else
1527 col = MAXCOL;
1528 }
1529 else
1530 {
1531 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001532 /* col(".") when the cursor is on the NUL at the end of the line
1533 * because of "coladd" can be seen as an extra column. */
1534 if (virtual_active() && fp == &curwin->w_cursor)
1535 {
1536 char_u *p = ml_get_cursor();
1537
1538 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1539 curwin->w_virtcol - curwin->w_cursor.coladd))
1540 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001541 int l;
1542
1543 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1544 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001545 }
1546 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001547 }
1548 }
1549 rettv->vval.v_number = col;
1550}
1551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001552/*
1553 * "confirm(message, buttons[, default [, type]])" function
1554 */
1555 static void
1556f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1557{
1558#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1559 char_u *message;
1560 char_u *buttons = NULL;
1561 char_u buf[NUMBUFLEN];
1562 char_u buf2[NUMBUFLEN];
1563 int def = 1;
1564 int type = VIM_GENERIC;
1565 char_u *typestr;
1566 int error = FALSE;
1567
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001568 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001569 if (message == NULL)
1570 error = TRUE;
1571 if (argvars[1].v_type != VAR_UNKNOWN)
1572 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001573 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001574 if (buttons == NULL)
1575 error = TRUE;
1576 if (argvars[2].v_type != VAR_UNKNOWN)
1577 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001578 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001579 if (argvars[3].v_type != VAR_UNKNOWN)
1580 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001581 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001582 if (typestr == NULL)
1583 error = TRUE;
1584 else
1585 {
1586 switch (TOUPPER_ASC(*typestr))
1587 {
1588 case 'E': type = VIM_ERROR; break;
1589 case 'Q': type = VIM_QUESTION; break;
1590 case 'I': type = VIM_INFO; break;
1591 case 'W': type = VIM_WARNING; break;
1592 case 'G': type = VIM_GENERIC; break;
1593 }
1594 }
1595 }
1596 }
1597 }
1598
1599 if (buttons == NULL || *buttons == NUL)
1600 buttons = (char_u *)_("&Ok");
1601
1602 if (!error)
1603 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1604 def, NULL, FALSE);
1605#endif
1606}
1607
1608/*
1609 * "copy()" function
1610 */
1611 static void
1612f_copy(typval_T *argvars, typval_T *rettv)
1613{
1614 item_copy(&argvars[0], rettv, FALSE, 0);
1615}
1616
1617#ifdef FEAT_FLOAT
1618/*
1619 * "cos()" function
1620 */
1621 static void
1622f_cos(typval_T *argvars, typval_T *rettv)
1623{
1624 float_T f = 0.0;
1625
1626 rettv->v_type = VAR_FLOAT;
1627 if (get_float_arg(argvars, &f) == OK)
1628 rettv->vval.v_float = cos(f);
1629 else
1630 rettv->vval.v_float = 0.0;
1631}
1632
1633/*
1634 * "cosh()" function
1635 */
1636 static void
1637f_cosh(typval_T *argvars, typval_T *rettv)
1638{
1639 float_T f = 0.0;
1640
1641 rettv->v_type = VAR_FLOAT;
1642 if (get_float_arg(argvars, &f) == OK)
1643 rettv->vval.v_float = cosh(f);
1644 else
1645 rettv->vval.v_float = 0.0;
1646}
1647#endif
1648
1649/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001650 * "cursor(lnum, col)" function, or
1651 * "cursor(list)"
1652 *
1653 * Moves the cursor to the specified line and column.
1654 * Returns 0 when the position could be set, -1 otherwise.
1655 */
1656 static void
1657f_cursor(typval_T *argvars, typval_T *rettv)
1658{
1659 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001660 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661 int set_curswant = TRUE;
1662
1663 rettv->vval.v_number = -1;
1664 if (argvars[1].v_type == VAR_UNKNOWN)
1665 {
1666 pos_T pos;
1667 colnr_T curswant = -1;
1668
1669 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1670 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001671 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001672 return;
1673 }
1674 line = pos.lnum;
1675 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001676 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001677 if (curswant >= 0)
1678 {
1679 curwin->w_curswant = curswant - 1;
1680 set_curswant = FALSE;
1681 }
1682 }
1683 else
1684 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001685 line = tv_get_lnum(argvars);
1686 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001688 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001689 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001690 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001691 return; /* type error; errmsg already given */
1692 if (line > 0)
1693 curwin->w_cursor.lnum = line;
1694 if (col > 0)
1695 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001696 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001697
1698 /* Make sure the cursor is in a valid position. */
1699 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001700 /* Correct cursor for multi-byte character. */
1701 if (has_mbyte)
1702 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001703
1704 curwin->w_set_curswant = set_curswant;
1705 rettv->vval.v_number = 0;
1706}
1707
Bram Moolenaar4f974752019-02-17 17:44:42 +01001708#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001709/*
1710 * "debugbreak()" function
1711 */
1712 static void
1713f_debugbreak(typval_T *argvars, typval_T *rettv)
1714{
1715 int pid;
1716
1717 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001718 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001719 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001720 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001721 else
1722 {
1723 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1724
1725 if (hProcess != NULL)
1726 {
1727 DebugBreakProcess(hProcess);
1728 CloseHandle(hProcess);
1729 rettv->vval.v_number = OK;
1730 }
1731 }
1732}
1733#endif
1734
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001735/*
1736 * "deepcopy()" function
1737 */
1738 static void
1739f_deepcopy(typval_T *argvars, typval_T *rettv)
1740{
1741 int noref = 0;
1742 int copyID;
1743
1744 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001745 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001746 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001747 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001748 else
1749 {
1750 copyID = get_copyID();
1751 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1752 }
1753}
1754
1755/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001756 * "did_filetype()" function
1757 */
1758 static void
1759f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1760{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001761 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001762}
1763
1764/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001765 * "empty({expr})" function
1766 */
1767 static void
1768f_empty(typval_T *argvars, typval_T *rettv)
1769{
1770 int n = FALSE;
1771
1772 switch (argvars[0].v_type)
1773 {
1774 case VAR_STRING:
1775 case VAR_FUNC:
1776 n = argvars[0].vval.v_string == NULL
1777 || *argvars[0].vval.v_string == NUL;
1778 break;
1779 case VAR_PARTIAL:
1780 n = FALSE;
1781 break;
1782 case VAR_NUMBER:
1783 n = argvars[0].vval.v_number == 0;
1784 break;
1785 case VAR_FLOAT:
1786#ifdef FEAT_FLOAT
1787 n = argvars[0].vval.v_float == 0.0;
1788 break;
1789#endif
1790 case VAR_LIST:
1791 n = argvars[0].vval.v_list == NULL
1792 || argvars[0].vval.v_list->lv_first == NULL;
1793 break;
1794 case VAR_DICT:
1795 n = argvars[0].vval.v_dict == NULL
1796 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1797 break;
1798 case VAR_SPECIAL:
1799 n = argvars[0].vval.v_number != VVAL_TRUE;
1800 break;
1801
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001802 case VAR_BLOB:
1803 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001804 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1805 break;
1806
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001807 case VAR_JOB:
1808#ifdef FEAT_JOB_CHANNEL
1809 n = argvars[0].vval.v_job == NULL
1810 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1811 break;
1812#endif
1813 case VAR_CHANNEL:
1814#ifdef FEAT_JOB_CHANNEL
1815 n = argvars[0].vval.v_channel == NULL
1816 || !channel_is_open(argvars[0].vval.v_channel);
1817 break;
1818#endif
1819 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001820 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001821 n = TRUE;
1822 break;
1823 }
1824
1825 rettv->vval.v_number = n;
1826}
1827
1828/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001829 * "environ()" function
1830 */
1831 static void
1832f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1833{
1834#if !defined(AMIGA)
1835 int i = 0;
1836 char_u *entry, *value;
1837# ifdef MSWIN
1838 extern wchar_t **_wenviron;
1839# else
1840 extern char **environ;
1841# endif
1842
1843 if (rettv_dict_alloc(rettv) != OK)
1844 return;
1845
1846# ifdef MSWIN
1847 if (*_wenviron == NULL)
1848 return;
1849# else
1850 if (*environ == NULL)
1851 return;
1852# endif
1853
1854 for (i = 0; ; ++i)
1855 {
1856# ifdef MSWIN
1857 short_u *p;
1858
1859 if ((p = (short_u *)_wenviron[i]) == NULL)
1860 return;
1861 entry = utf16_to_enc(p, NULL);
1862# else
1863 if ((entry = (char_u *)environ[i]) == NULL)
1864 return;
1865 entry = vim_strsave(entry);
1866# endif
1867 if (entry == NULL) // out of memory
1868 return;
1869 if ((value = vim_strchr(entry, '=')) == NULL)
1870 {
1871 vim_free(entry);
1872 continue;
1873 }
1874 *value++ = NUL;
1875 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1876 vim_free(entry);
1877 }
1878#endif
1879}
1880
1881/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001882 * "escape({string}, {chars})" function
1883 */
1884 static void
1885f_escape(typval_T *argvars, typval_T *rettv)
1886{
1887 char_u buf[NUMBUFLEN];
1888
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001889 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1890 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001891 rettv->v_type = VAR_STRING;
1892}
1893
1894/*
1895 * "eval()" function
1896 */
1897 static void
1898f_eval(typval_T *argvars, typval_T *rettv)
1899{
1900 char_u *s, *p;
1901
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001902 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001903 if (s != NULL)
1904 s = skipwhite(s);
1905
1906 p = s;
1907 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1908 {
1909 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001910 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001911 need_clr_eos = FALSE;
1912 rettv->v_type = VAR_NUMBER;
1913 rettv->vval.v_number = 0;
1914 }
1915 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001916 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001917}
1918
1919/*
1920 * "eventhandler()" function
1921 */
1922 static void
1923f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1924{
1925 rettv->vval.v_number = vgetc_busy;
1926}
1927
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928static garray_T redir_execute_ga;
1929
1930/*
1931 * Append "value[value_len]" to the execute() output.
1932 */
1933 void
1934execute_redir_str(char_u *value, int value_len)
1935{
1936 int len;
1937
1938 if (value_len == -1)
1939 len = (int)STRLEN(value); /* Append the entire string */
1940 else
1941 len = value_len; /* Append only "value_len" characters */
1942 if (ga_grow(&redir_execute_ga, len) == OK)
1943 {
1944 mch_memmove((char *)redir_execute_ga.ga_data
1945 + redir_execute_ga.ga_len, value, len);
1946 redir_execute_ga.ga_len += len;
1947 }
1948}
1949
1950/*
1951 * Get next line from a list.
1952 * Called by do_cmdline() to get the next line.
1953 * Returns allocated string, or NULL for end of function.
1954 */
1955
1956 static char_u *
1957get_list_line(
1958 int c UNUSED,
1959 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001960 int indent UNUSED,
1961 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001962{
1963 listitem_T **p = (listitem_T **)cookie;
1964 listitem_T *item = *p;
1965 char_u buf[NUMBUFLEN];
1966 char_u *s;
1967
1968 if (item == NULL)
1969 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001970 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001971 *p = item->li_next;
1972 return s == NULL ? NULL : vim_strsave(s);
1973}
1974
1975/*
1976 * "execute()" function
1977 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02001978 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001979execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980{
1981 char_u *cmd = NULL;
1982 list_T *list = NULL;
1983 int save_msg_silent = msg_silent;
1984 int save_emsg_silent = emsg_silent;
1985 int save_emsg_noredir = emsg_noredir;
1986 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01001987 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001988 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01001989 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01001990 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991
1992 rettv->vval.v_string = NULL;
1993 rettv->v_type = VAR_STRING;
1994
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001995 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001996 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02001997 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001998 if (list == NULL || list->lv_first == NULL)
1999 /* empty list, no commands, empty output */
2000 return;
2001 ++list->lv_refcount;
2002 }
2003 else
2004 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002005 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002006 if (cmd == NULL)
2007 return;
2008 }
2009
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002010 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002011 {
2012 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002013 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002014
2015 if (s == NULL)
2016 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002017 if (*s == NUL)
2018 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002019 if (STRNCMP(s, "silent", 6) == 0)
2020 ++msg_silent;
2021 if (STRCMP(s, "silent!") == 0)
2022 {
2023 emsg_silent = TRUE;
2024 emsg_noredir = TRUE;
2025 }
2026 }
2027 else
2028 ++msg_silent;
2029
2030 if (redir_execute)
2031 save_ga = redir_execute_ga;
2032 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2033 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002034 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002035 if (!echo_output)
2036 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002037
2038 if (cmd != NULL)
2039 do_cmdline_cmd(cmd);
2040 else
2041 {
2042 listitem_T *item = list->lv_first;
2043
2044 do_cmdline(NULL, get_list_line, (void *)&item,
2045 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2046 --list->lv_refcount;
2047 }
2048
Bram Moolenaard297f352017-01-29 20:31:21 +01002049 /* Need to append a NUL to the result. */
2050 if (ga_grow(&redir_execute_ga, 1) == OK)
2051 {
2052 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2053 rettv->vval.v_string = redir_execute_ga.ga_data;
2054 }
2055 else
2056 {
2057 ga_clear(&redir_execute_ga);
2058 rettv->vval.v_string = NULL;
2059 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002060 msg_silent = save_msg_silent;
2061 emsg_silent = save_emsg_silent;
2062 emsg_noredir = save_emsg_noredir;
2063
2064 redir_execute = save_redir_execute;
2065 if (redir_execute)
2066 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002067 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002068
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002069 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002070 if (echo_output)
2071 // When not working silently: put it in column zero. A following
2072 // "echon" will overwrite the message, unavoidably.
2073 msg_col = 0;
2074 else
2075 // When working silently: Put it back where it was, since nothing
2076 // should have been written.
2077 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002078}
2079
2080/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002081 * "execute()" function
2082 */
2083 static void
2084f_execute(typval_T *argvars, typval_T *rettv)
2085{
2086 execute_common(argvars, rettv, 0);
2087}
2088
2089/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002090 * "exists()" function
2091 */
2092 static void
2093f_exists(typval_T *argvars, typval_T *rettv)
2094{
2095 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002096 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002097
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002098 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002099 if (*p == '$') /* environment variable */
2100 {
2101 /* first try "normal" environment variables (fast) */
2102 if (mch_getenv(p + 1) != NULL)
2103 n = TRUE;
2104 else
2105 {
2106 /* try expanding things like $VIM and ${HOME} */
2107 p = expand_env_save(p);
2108 if (p != NULL && *p != '$')
2109 n = TRUE;
2110 vim_free(p);
2111 }
2112 }
2113 else if (*p == '&' || *p == '+') /* option */
2114 {
2115 n = (get_option_tv(&p, NULL, TRUE) == OK);
2116 if (*skipwhite(p) != NUL)
2117 n = FALSE; /* trailing garbage */
2118 }
2119 else if (*p == '*') /* internal or user defined function */
2120 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002121 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122 }
2123 else if (*p == ':')
2124 {
2125 n = cmd_exists(p + 1);
2126 }
2127 else if (*p == '#')
2128 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002129 if (p[1] == '#')
2130 n = autocmd_supported(p + 2);
2131 else
2132 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002133 }
2134 else /* internal variable */
2135 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002136 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002137 }
2138
2139 rettv->vval.v_number = n;
2140}
2141
2142#ifdef FEAT_FLOAT
2143/*
2144 * "exp()" function
2145 */
2146 static void
2147f_exp(typval_T *argvars, typval_T *rettv)
2148{
2149 float_T f = 0.0;
2150
2151 rettv->v_type = VAR_FLOAT;
2152 if (get_float_arg(argvars, &f) == OK)
2153 rettv->vval.v_float = exp(f);
2154 else
2155 rettv->vval.v_float = 0.0;
2156}
2157#endif
2158
2159/*
2160 * "expand()" function
2161 */
2162 static void
2163f_expand(typval_T *argvars, typval_T *rettv)
2164{
2165 char_u *s;
2166 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002167 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002168 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2169 expand_T xpc;
2170 int error = FALSE;
2171 char_u *result;
2172
2173 rettv->v_type = VAR_STRING;
2174 if (argvars[1].v_type != VAR_UNKNOWN
2175 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002176 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002178 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002179
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002180 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002181 if (*s == '%' || *s == '#' || *s == '<')
2182 {
2183 ++emsg_off;
2184 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2185 --emsg_off;
2186 if (rettv->v_type == VAR_LIST)
2187 {
2188 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2189 list_append_string(rettv->vval.v_list, result, -1);
Bram Moolenaar86173482019-10-01 17:02:16 +02002190 vim_free(result);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002191 }
2192 else
2193 rettv->vval.v_string = result;
2194 }
2195 else
2196 {
2197 /* When the optional second argument is non-zero, don't remove matches
2198 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2199 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002200 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002201 options |= WILD_KEEP_ALL;
2202 if (!error)
2203 {
2204 ExpandInit(&xpc);
2205 xpc.xp_context = EXPAND_FILES;
2206 if (p_wic)
2207 options += WILD_ICASE;
2208 if (rettv->v_type == VAR_STRING)
2209 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2210 options, WILD_ALL);
2211 else if (rettv_list_alloc(rettv) != FAIL)
2212 {
2213 int i;
2214
2215 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2216 for (i = 0; i < xpc.xp_numfiles; i++)
2217 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2218 ExpandCleanup(&xpc);
2219 }
2220 }
2221 else
2222 rettv->vval.v_string = NULL;
2223 }
2224}
2225
2226/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002227 * "expandcmd()" function
2228 * Expand all the special characters in a command string.
2229 */
2230 static void
2231f_expandcmd(typval_T *argvars, typval_T *rettv)
2232{
2233 exarg_T eap;
2234 char_u *cmdstr;
2235 char *errormsg = NULL;
2236
2237 rettv->v_type = VAR_STRING;
2238 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2239
2240 memset(&eap, 0, sizeof(eap));
2241 eap.cmd = cmdstr;
2242 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002243 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002244 eap.usefilter = FALSE;
2245 eap.nextcmd = NULL;
2246 eap.cmdidx = CMD_USER;
2247
2248 expand_filename(&eap, &cmdstr, &errormsg);
2249 if (errormsg != NULL && *errormsg != NUL)
2250 emsg(errormsg);
2251
2252 rettv->vval.v_string = cmdstr;
2253}
2254
2255/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002256 * "feedkeys()" function
2257 */
2258 static void
2259f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2260{
2261 int remap = TRUE;
2262 int insert = FALSE;
2263 char_u *keys, *flags;
2264 char_u nbuf[NUMBUFLEN];
2265 int typed = FALSE;
2266 int execute = FALSE;
2267 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002268 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002269 char_u *keys_esc;
2270
2271 /* This is not allowed in the sandbox. If the commands would still be
2272 * executed in the sandbox it would be OK, but it probably happens later,
2273 * when "sandbox" is no longer set. */
2274 if (check_secure())
2275 return;
2276
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002277 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002278
2279 if (argvars[1].v_type != VAR_UNKNOWN)
2280 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002281 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002282 for ( ; *flags != NUL; ++flags)
2283 {
2284 switch (*flags)
2285 {
2286 case 'n': remap = FALSE; break;
2287 case 'm': remap = TRUE; break;
2288 case 't': typed = TRUE; break;
2289 case 'i': insert = TRUE; break;
2290 case 'x': execute = TRUE; break;
2291 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002292 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002293 }
2294 }
2295 }
2296
2297 if (*keys != NUL || execute)
2298 {
2299 /* Need to escape K_SPECIAL and CSI before putting the string in the
2300 * typeahead buffer. */
2301 keys_esc = vim_strsave_escape_csi(keys);
2302 if (keys_esc != NULL)
2303 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002304 if (lowlevel)
2305 {
2306#ifdef USE_INPUT_BUF
2307 add_to_input_buf(keys, (int)STRLEN(keys));
2308#else
2309 emsg(_("E980: lowlevel input not supported"));
2310#endif
2311 }
2312 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002313 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002314 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002315 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002316 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002317#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002318 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002319#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002320 )
2321 typebuf_was_filled = TRUE;
2322 }
2323 vim_free(keys_esc);
2324
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002325 if (execute)
2326 {
2327 int save_msg_scroll = msg_scroll;
2328
2329 /* Avoid a 1 second delay when the keys start Insert mode. */
2330 msg_scroll = FALSE;
2331
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002332 if (!dangerous)
2333 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002334 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002335 if (!dangerous)
2336 --ex_normal_busy;
2337
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002338 msg_scroll |= save_msg_scroll;
2339 }
2340 }
2341 }
2342}
2343
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002344#ifdef FEAT_FLOAT
2345/*
2346 * "float2nr({float})" function
2347 */
2348 static void
2349f_float2nr(typval_T *argvars, typval_T *rettv)
2350{
2351 float_T f = 0.0;
2352
2353 if (get_float_arg(argvars, &f) == OK)
2354 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002355 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002356 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002357 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002358 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002359 else
2360 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002361 }
2362}
2363
2364/*
2365 * "floor({float})" function
2366 */
2367 static void
2368f_floor(typval_T *argvars, typval_T *rettv)
2369{
2370 float_T f = 0.0;
2371
2372 rettv->v_type = VAR_FLOAT;
2373 if (get_float_arg(argvars, &f) == OK)
2374 rettv->vval.v_float = floor(f);
2375 else
2376 rettv->vval.v_float = 0.0;
2377}
2378
2379/*
2380 * "fmod()" function
2381 */
2382 static void
2383f_fmod(typval_T *argvars, typval_T *rettv)
2384{
2385 float_T fx = 0.0, fy = 0.0;
2386
2387 rettv->v_type = VAR_FLOAT;
2388 if (get_float_arg(argvars, &fx) == OK
2389 && get_float_arg(&argvars[1], &fy) == OK)
2390 rettv->vval.v_float = fmod(fx, fy);
2391 else
2392 rettv->vval.v_float = 0.0;
2393}
2394#endif
2395
2396/*
2397 * "fnameescape({string})" function
2398 */
2399 static void
2400f_fnameescape(typval_T *argvars, typval_T *rettv)
2401{
2402 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002403 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002404 rettv->v_type = VAR_STRING;
2405}
2406
2407/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002408 * "foreground()" function
2409 */
2410 static void
2411f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2412{
2413#ifdef FEAT_GUI
2414 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002415 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002416 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002417 return;
2418 }
2419#endif
2420#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002421 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002422#endif
2423}
2424
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002425 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002426common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002427{
2428 char_u *s;
2429 char_u *name;
2430 int use_string = FALSE;
2431 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002432 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002433
2434 if (argvars[0].v_type == VAR_FUNC)
2435 {
2436 /* function(MyFunc, [arg], dict) */
2437 s = argvars[0].vval.v_string;
2438 }
2439 else if (argvars[0].v_type == VAR_PARTIAL
2440 && argvars[0].vval.v_partial != NULL)
2441 {
2442 /* function(dict.MyFunc, [arg]) */
2443 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002444 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002445 }
2446 else
2447 {
2448 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002449 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 use_string = TRUE;
2451 }
2452
Bram Moolenaar843b8842016-08-21 14:36:15 +02002453 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002454 {
2455 name = s;
2456 trans_name = trans_function_name(&name, FALSE,
2457 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2458 if (*name != NUL)
2459 s = NULL;
2460 }
2461
Bram Moolenaar843b8842016-08-21 14:36:15 +02002462 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2463 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002464 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002466 else if (trans_name != NULL && (is_funcref
2467 ? find_func(trans_name) == NULL
2468 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002469 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002470 else
2471 {
2472 int dict_idx = 0;
2473 int arg_idx = 0;
2474 list_T *list = NULL;
2475
2476 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2477 {
2478 char sid_buf[25];
2479 int off = *s == 's' ? 2 : 5;
2480
2481 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2482 * also be called from another script. Using trans_function_name()
2483 * would also work, but some plugins depend on the name being
2484 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002485 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002486 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002487 if (name != NULL)
2488 {
2489 STRCPY(name, sid_buf);
2490 STRCAT(name, s + off);
2491 }
2492 }
2493 else
2494 name = vim_strsave(s);
2495
2496 if (argvars[1].v_type != VAR_UNKNOWN)
2497 {
2498 if (argvars[2].v_type != VAR_UNKNOWN)
2499 {
2500 /* function(name, [args], dict) */
2501 arg_idx = 1;
2502 dict_idx = 2;
2503 }
2504 else if (argvars[1].v_type == VAR_DICT)
2505 /* function(name, dict) */
2506 dict_idx = 1;
2507 else
2508 /* function(name, [args]) */
2509 arg_idx = 1;
2510 if (dict_idx > 0)
2511 {
2512 if (argvars[dict_idx].v_type != VAR_DICT)
2513 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002514 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002515 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002516 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517 }
2518 if (argvars[dict_idx].vval.v_dict == NULL)
2519 dict_idx = 0;
2520 }
2521 if (arg_idx > 0)
2522 {
2523 if (argvars[arg_idx].v_type != VAR_LIST)
2524 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002525 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002526 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002527 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528 }
2529 list = argvars[arg_idx].vval.v_list;
2530 if (list == NULL || list->lv_len == 0)
2531 arg_idx = 0;
2532 }
2533 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002534 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002535 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002536 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537
2538 /* result is a VAR_PARTIAL */
2539 if (pt == NULL)
2540 vim_free(name);
2541 else
2542 {
2543 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2544 {
2545 listitem_T *li;
2546 int i = 0;
2547 int arg_len = 0;
2548 int lv_len = 0;
2549
2550 if (arg_pt != NULL)
2551 arg_len = arg_pt->pt_argc;
2552 if (list != NULL)
2553 lv_len = list->lv_len;
2554 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002555 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002556 if (pt->pt_argv == NULL)
2557 {
2558 vim_free(pt);
2559 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002560 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002561 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002562 for (i = 0; i < arg_len; i++)
2563 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2564 if (lv_len > 0)
2565 for (li = list->lv_first; li != NULL;
2566 li = li->li_next)
2567 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002568 }
2569
2570 /* For "function(dict.func, [], dict)" and "func" is a partial
2571 * use "dict". That is backwards compatible. */
2572 if (dict_idx > 0)
2573 {
2574 /* The dict is bound explicitly, pt_auto is FALSE. */
2575 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2576 ++pt->pt_dict->dv_refcount;
2577 }
2578 else if (arg_pt != NULL)
2579 {
2580 /* If the dict was bound automatically the result is also
2581 * bound automatically. */
2582 pt->pt_dict = arg_pt->pt_dict;
2583 pt->pt_auto = arg_pt->pt_auto;
2584 if (pt->pt_dict != NULL)
2585 ++pt->pt_dict->dv_refcount;
2586 }
2587
2588 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002589 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2590 {
2591 pt->pt_func = arg_pt->pt_func;
2592 func_ptr_ref(pt->pt_func);
2593 vim_free(name);
2594 }
2595 else if (is_funcref)
2596 {
2597 pt->pt_func = find_func(trans_name);
2598 func_ptr_ref(pt->pt_func);
2599 vim_free(name);
2600 }
2601 else
2602 {
2603 pt->pt_name = name;
2604 func_ref(name);
2605 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002606 }
2607 rettv->v_type = VAR_PARTIAL;
2608 rettv->vval.v_partial = pt;
2609 }
2610 else
2611 {
2612 /* result is a VAR_FUNC */
2613 rettv->v_type = VAR_FUNC;
2614 rettv->vval.v_string = name;
2615 func_ref(name);
2616 }
2617 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002618theend:
2619 vim_free(trans_name);
2620}
2621
2622/*
2623 * "funcref()" function
2624 */
2625 static void
2626f_funcref(typval_T *argvars, typval_T *rettv)
2627{
2628 common_function(argvars, rettv, TRUE);
2629}
2630
2631/*
2632 * "function()" function
2633 */
2634 static void
2635f_function(typval_T *argvars, typval_T *rettv)
2636{
2637 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002638}
2639
2640/*
2641 * "garbagecollect()" function
2642 */
2643 static void
2644f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2645{
2646 /* This is postponed until we are back at the toplevel, because we may be
2647 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2648 want_garbage_collect = TRUE;
2649
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002650 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002651 garbage_collect_at_exit = TRUE;
2652}
2653
2654/*
2655 * "get()" function
2656 */
2657 static void
2658f_get(typval_T *argvars, typval_T *rettv)
2659{
2660 listitem_T *li;
2661 list_T *l;
2662 dictitem_T *di;
2663 dict_T *d;
2664 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002665 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002666
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002667 if (argvars[0].v_type == VAR_BLOB)
2668 {
2669 int error = FALSE;
2670 int idx = tv_get_number_chk(&argvars[1], &error);
2671
2672 if (!error)
2673 {
2674 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002675 if (idx < 0)
2676 idx = blob_len(argvars[0].vval.v_blob) + idx;
2677 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2678 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002679 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002680 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002681 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002682 tv = rettv;
2683 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002684 }
2685 }
2686 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002687 {
2688 if ((l = argvars[0].vval.v_list) != NULL)
2689 {
2690 int error = FALSE;
2691
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002692 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002693 if (!error && li != NULL)
2694 tv = &li->li_tv;
2695 }
2696 }
2697 else if (argvars[0].v_type == VAR_DICT)
2698 {
2699 if ((d = argvars[0].vval.v_dict) != NULL)
2700 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002701 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002702 if (di != NULL)
2703 tv = &di->di_tv;
2704 }
2705 }
2706 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2707 {
2708 partial_T *pt;
2709 partial_T fref_pt;
2710
2711 if (argvars[0].v_type == VAR_PARTIAL)
2712 pt = argvars[0].vval.v_partial;
2713 else
2714 {
2715 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2716 fref_pt.pt_name = argvars[0].vval.v_string;
2717 pt = &fref_pt;
2718 }
2719
2720 if (pt != NULL)
2721 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002722 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002723 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002724
2725 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2726 {
2727 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002728 n = partial_name(pt);
2729 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002730 rettv->vval.v_string = NULL;
2731 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002732 {
2733 rettv->vval.v_string = vim_strsave(n);
2734 if (rettv->v_type == VAR_FUNC)
2735 func_ref(rettv->vval.v_string);
2736 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002737 }
2738 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002739 {
2740 what_is_dict = TRUE;
2741 if (pt->pt_dict != NULL)
2742 rettv_dict_set(rettv, pt->pt_dict);
2743 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002744 else if (STRCMP(what, "args") == 0)
2745 {
2746 rettv->v_type = VAR_LIST;
2747 if (rettv_list_alloc(rettv) == OK)
2748 {
2749 int i;
2750
2751 for (i = 0; i < pt->pt_argc; ++i)
2752 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2753 }
2754 }
2755 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002756 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002757
2758 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2759 // third argument
2760 if (!what_is_dict)
2761 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 }
2763 }
2764 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002765 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002766
2767 if (tv == NULL)
2768 {
2769 if (argvars[2].v_type != VAR_UNKNOWN)
2770 copy_tv(&argvars[2], rettv);
2771 }
2772 else
2773 copy_tv(tv, rettv);
2774}
2775
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002776/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002777 * "getchangelist()" function
2778 */
2779 static void
2780f_getchangelist(typval_T *argvars, typval_T *rettv)
2781{
2782#ifdef FEAT_JUMPLIST
2783 buf_T *buf;
2784 int i;
2785 list_T *l;
2786 dict_T *d;
2787#endif
2788
2789 if (rettv_list_alloc(rettv) != OK)
2790 return;
2791
2792#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002793 if (argvars[0].v_type == VAR_UNKNOWN)
2794 buf = curbuf;
2795 else
2796 {
2797 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2798 ++emsg_off;
2799 buf = tv_get_buf(&argvars[0], FALSE);
2800 --emsg_off;
2801 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002802 if (buf == NULL)
2803 return;
2804
2805 l = list_alloc();
2806 if (l == NULL)
2807 return;
2808
2809 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2810 return;
2811 /*
2812 * The current window change list index tracks only the position in the
2813 * current buffer change list. For other buffers, use the change list
2814 * length as the current index.
2815 */
2816 list_append_number(rettv->vval.v_list,
2817 (varnumber_T)((buf == curwin->w_buffer)
2818 ? curwin->w_changelistidx : buf->b_changelistlen));
2819
2820 for (i = 0; i < buf->b_changelistlen; ++i)
2821 {
2822 if (buf->b_changelist[i].lnum == 0)
2823 continue;
2824 if ((d = dict_alloc()) == NULL)
2825 return;
2826 if (list_append_dict(l, d) == FAIL)
2827 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002828 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2829 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002830 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002831 }
2832#endif
2833}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002834
2835/*
2836 * "getcharsearch()" function
2837 */
2838 static void
2839f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2840{
2841 if (rettv_dict_alloc(rettv) != FAIL)
2842 {
2843 dict_T *dict = rettv->vval.v_dict;
2844
Bram Moolenaare0be1672018-07-08 16:50:37 +02002845 dict_add_string(dict, "char", last_csearch());
2846 dict_add_number(dict, "forward", last_csearch_forward());
2847 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002848 }
2849}
2850
2851/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002852 * "getcmdwintype()" function
2853 */
2854 static void
2855f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2856{
2857 rettv->v_type = VAR_STRING;
2858 rettv->vval.v_string = NULL;
2859#ifdef FEAT_CMDWIN
2860 rettv->vval.v_string = alloc(2);
2861 if (rettv->vval.v_string != NULL)
2862 {
2863 rettv->vval.v_string[0] = cmdwin_type;
2864 rettv->vval.v_string[1] = NUL;
2865 }
2866#endif
2867}
2868
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002870 * "getenv()" function
2871 */
2872 static void
2873f_getenv(typval_T *argvars, typval_T *rettv)
2874{
2875 int mustfree = FALSE;
2876 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2877
2878 if (p == NULL)
2879 {
2880 rettv->v_type = VAR_SPECIAL;
2881 rettv->vval.v_number = VVAL_NULL;
2882 return;
2883 }
2884 if (!mustfree)
2885 p = vim_strsave(p);
2886 rettv->vval.v_string = p;
2887 rettv->v_type = VAR_STRING;
2888}
2889
2890/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002891 * "getfontname()" function
2892 */
2893 static void
2894f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2895{
2896 rettv->v_type = VAR_STRING;
2897 rettv->vval.v_string = NULL;
2898#ifdef FEAT_GUI
2899 if (gui.in_use)
2900 {
2901 GuiFont font;
2902 char_u *name = NULL;
2903
2904 if (argvars[0].v_type == VAR_UNKNOWN)
2905 {
2906 /* Get the "Normal" font. Either the name saved by
2907 * hl_set_font_name() or from the font ID. */
2908 font = gui.norm_font;
2909 name = hl_get_font_name();
2910 }
2911 else
2912 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002913 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002914 if (STRCMP(name, "*") == 0) /* don't use font dialog */
2915 return;
2916 font = gui_mch_get_font(name, FALSE);
2917 if (font == NOFONT)
2918 return; /* Invalid font name, return empty string. */
2919 }
2920 rettv->vval.v_string = gui_mch_get_fontname(font, name);
2921 if (argvars[0].v_type != VAR_UNKNOWN)
2922 gui_mch_free_font(font);
2923 }
2924#endif
2925}
2926
2927/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01002928 * "getjumplist()" function
2929 */
2930 static void
2931f_getjumplist(typval_T *argvars, typval_T *rettv)
2932{
2933#ifdef FEAT_JUMPLIST
2934 win_T *wp;
2935 int i;
2936 list_T *l;
2937 dict_T *d;
2938#endif
2939
2940 if (rettv_list_alloc(rettv) != OK)
2941 return;
2942
2943#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02002944 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002945 if (wp == NULL)
2946 return;
2947
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01002948 cleanup_jumplist(wp, TRUE);
2949
Bram Moolenaar4f505882018-02-10 21:06:32 +01002950 l = list_alloc();
2951 if (l == NULL)
2952 return;
2953
2954 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2955 return;
2956 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
2957
2958 for (i = 0; i < wp->w_jumplistlen; ++i)
2959 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002960 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
2961 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01002962 if ((d = dict_alloc()) == NULL)
2963 return;
2964 if (list_append_dict(l, d) == FAIL)
2965 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002966 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
2967 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002968 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002969 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002970 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02002971 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002972 }
2973#endif
2974}
2975
2976/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002977 * "getpid()" function
2978 */
2979 static void
2980f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
2981{
2982 rettv->vval.v_number = mch_get_pid();
2983}
2984
2985 static void
2986getpos_both(
2987 typval_T *argvars,
2988 typval_T *rettv,
2989 int getcurpos)
2990{
2991 pos_T *fp;
2992 list_T *l;
2993 int fnum = -1;
2994
2995 if (rettv_list_alloc(rettv) == OK)
2996 {
2997 l = rettv->vval.v_list;
2998 if (getcurpos)
2999 fp = &curwin->w_cursor;
3000 else
3001 fp = var2fpos(&argvars[0], TRUE, &fnum);
3002 if (fnum != -1)
3003 list_append_number(l, (varnumber_T)fnum);
3004 else
3005 list_append_number(l, (varnumber_T)0);
3006 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3007 : (varnumber_T)0);
3008 list_append_number(l, (fp != NULL)
3009 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3010 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003011 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003012 (varnumber_T)0);
3013 if (getcurpos)
3014 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003015 int save_set_curswant = curwin->w_set_curswant;
3016 colnr_T save_curswant = curwin->w_curswant;
3017 colnr_T save_virtcol = curwin->w_virtcol;
3018
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003019 update_curswant();
3020 list_append_number(l, curwin->w_curswant == MAXCOL ?
3021 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003022
3023 // Do not change "curswant", as it is unexpected that a get
3024 // function has a side effect.
3025 if (save_set_curswant)
3026 {
3027 curwin->w_set_curswant = save_set_curswant;
3028 curwin->w_curswant = save_curswant;
3029 curwin->w_virtcol = save_virtcol;
3030 curwin->w_valid &= ~VALID_VIRTCOL;
3031 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003032 }
3033 }
3034 else
3035 rettv->vval.v_number = FALSE;
3036}
3037
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038/*
3039 * "getcurpos()" function
3040 */
3041 static void
3042f_getcurpos(typval_T *argvars, typval_T *rettv)
3043{
3044 getpos_both(argvars, rettv, TRUE);
3045}
3046
3047/*
3048 * "getpos(string)" function
3049 */
3050 static void
3051f_getpos(typval_T *argvars, typval_T *rettv)
3052{
3053 getpos_both(argvars, rettv, FALSE);
3054}
3055
3056/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003057 * "getreg()" function
3058 */
3059 static void
3060f_getreg(typval_T *argvars, typval_T *rettv)
3061{
3062 char_u *strregname;
3063 int regname;
3064 int arg2 = FALSE;
3065 int return_list = FALSE;
3066 int error = FALSE;
3067
3068 if (argvars[0].v_type != VAR_UNKNOWN)
3069 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003070 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003071 error = strregname == NULL;
3072 if (argvars[1].v_type != VAR_UNKNOWN)
3073 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003074 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003076 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 }
3078 }
3079 else
3080 strregname = get_vim_var_str(VV_REG);
3081
3082 if (error)
3083 return;
3084
3085 regname = (strregname == NULL ? '"' : *strregname);
3086 if (regname == 0)
3087 regname = '"';
3088
3089 if (return_list)
3090 {
3091 rettv->v_type = VAR_LIST;
3092 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3093 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3094 if (rettv->vval.v_list == NULL)
3095 (void)rettv_list_alloc(rettv);
3096 else
3097 ++rettv->vval.v_list->lv_refcount;
3098 }
3099 else
3100 {
3101 rettv->v_type = VAR_STRING;
3102 rettv->vval.v_string = get_reg_contents(regname,
3103 arg2 ? GREG_EXPR_SRC : 0);
3104 }
3105}
3106
3107/*
3108 * "getregtype()" function
3109 */
3110 static void
3111f_getregtype(typval_T *argvars, typval_T *rettv)
3112{
3113 char_u *strregname;
3114 int regname;
3115 char_u buf[NUMBUFLEN + 2];
3116 long reglen = 0;
3117
3118 if (argvars[0].v_type != VAR_UNKNOWN)
3119 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003120 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003121 if (strregname == NULL) /* type error; errmsg already given */
3122 {
3123 rettv->v_type = VAR_STRING;
3124 rettv->vval.v_string = NULL;
3125 return;
3126 }
3127 }
3128 else
3129 /* Default to v:register */
3130 strregname = get_vim_var_str(VV_REG);
3131
3132 regname = (strregname == NULL ? '"' : *strregname);
3133 if (regname == 0)
3134 regname = '"';
3135
3136 buf[0] = NUL;
3137 buf[1] = NUL;
3138 switch (get_reg_type(regname, &reglen))
3139 {
3140 case MLINE: buf[0] = 'V'; break;
3141 case MCHAR: buf[0] = 'v'; break;
3142 case MBLOCK:
3143 buf[0] = Ctrl_V;
3144 sprintf((char *)buf + 1, "%ld", reglen + 1);
3145 break;
3146 }
3147 rettv->v_type = VAR_STRING;
3148 rettv->vval.v_string = vim_strsave(buf);
3149}
3150
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003151/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003152 * "gettagstack()" function
3153 */
3154 static void
3155f_gettagstack(typval_T *argvars, typval_T *rettv)
3156{
3157 win_T *wp = curwin; // default is current window
3158
3159 if (rettv_dict_alloc(rettv) != OK)
3160 return;
3161
3162 if (argvars[0].v_type != VAR_UNKNOWN)
3163 {
3164 wp = find_win_by_nr_or_id(&argvars[0]);
3165 if (wp == NULL)
3166 return;
3167 }
3168
3169 get_tagstack(wp, rettv->vval.v_dict);
3170}
3171
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003172/* for VIM_VERSION_ defines */
3173#include "version.h"
3174
3175/*
3176 * "has()" function
3177 */
3178 static void
3179f_has(typval_T *argvars, typval_T *rettv)
3180{
3181 int i;
3182 char_u *name;
3183 int n = FALSE;
3184 static char *(has_list[]) =
3185 {
3186#ifdef AMIGA
3187 "amiga",
3188# ifdef FEAT_ARP
3189 "arp",
3190# endif
3191#endif
3192#ifdef __BEOS__
3193 "beos",
3194#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003195#if defined(BSD) && !defined(MACOS_X)
3196 "bsd",
3197#endif
3198#ifdef hpux
3199 "hpux",
3200#endif
3201#ifdef __linux__
3202 "linux",
3203#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003204#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003205 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3206 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003207# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003208 "macunix", /* Mac OS X, with the darwin feature */
3209 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003210# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003211#endif
3212#ifdef __QNX__
3213 "qnx",
3214#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003215#ifdef SUN_SYSTEM
3216 "sun",
3217#else
3218 "moon",
3219#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003220#ifdef UNIX
3221 "unix",
3222#endif
3223#ifdef VMS
3224 "vms",
3225#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003226#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003227 "win32",
3228#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003229#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003230 "win32unix",
3231#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003232#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003233 "win64",
3234#endif
3235#ifdef EBCDIC
3236 "ebcdic",
3237#endif
3238#ifndef CASE_INSENSITIVE_FILENAME
3239 "fname_case",
3240#endif
3241#ifdef HAVE_ACL
3242 "acl",
3243#endif
3244#ifdef FEAT_ARABIC
3245 "arabic",
3246#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003247 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003248#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003249 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003250#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003251#ifdef FEAT_AUTOSERVERNAME
3252 "autoservername",
3253#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003254#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003255 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003256# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003257 "balloon_multiline",
3258# endif
3259#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003260#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003261 "balloon_eval_term",
3262#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003263#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3264 "builtin_terms",
3265# ifdef ALL_BUILTIN_TCAPS
3266 "all_builtin_terms",
3267# endif
3268#endif
3269#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003270 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003271 || defined(FEAT_GUI_MOTIF))
3272 "browsefilter",
3273#endif
3274#ifdef FEAT_BYTEOFF
3275 "byte_offset",
3276#endif
3277#ifdef FEAT_JOB_CHANNEL
3278 "channel",
3279#endif
3280#ifdef FEAT_CINDENT
3281 "cindent",
3282#endif
3283#ifdef FEAT_CLIENTSERVER
3284 "clientserver",
3285#endif
3286#ifdef FEAT_CLIPBOARD
3287 "clipboard",
3288#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003289 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003290 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003291 "comments",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003292#ifdef FEAT_CONCEAL
3293 "conceal",
3294#endif
3295#ifdef FEAT_CRYPT
3296 "cryptv",
3297 "crypt-blowfish",
3298 "crypt-blowfish2",
3299#endif
3300#ifdef FEAT_CSCOPE
3301 "cscope",
3302#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003303 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003304#ifdef CURSOR_SHAPE
3305 "cursorshape",
3306#endif
3307#ifdef DEBUG
3308 "debug",
3309#endif
3310#ifdef FEAT_CON_DIALOG
3311 "dialog_con",
3312#endif
3313#ifdef FEAT_GUI_DIALOG
3314 "dialog_gui",
3315#endif
3316#ifdef FEAT_DIFF
3317 "diff",
3318#endif
3319#ifdef FEAT_DIGRAPHS
3320 "digraphs",
3321#endif
3322#ifdef FEAT_DIRECTX
3323 "directx",
3324#endif
3325#ifdef FEAT_DND
3326 "dnd",
3327#endif
3328#ifdef FEAT_EMACS_TAGS
3329 "emacs_tags",
3330#endif
3331 "eval", /* always present, of course! */
3332 "ex_extra", /* graduated feature */
3333#ifdef FEAT_SEARCH_EXTRA
3334 "extra_search",
3335#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003336#ifdef FEAT_SEARCHPATH
3337 "file_in_path",
3338#endif
3339#ifdef FEAT_FILTERPIPE
3340 "filterpipe",
3341#endif
3342#ifdef FEAT_FIND_ID
3343 "find_in_path",
3344#endif
3345#ifdef FEAT_FLOAT
3346 "float",
3347#endif
3348#ifdef FEAT_FOLDING
3349 "folding",
3350#endif
3351#ifdef FEAT_FOOTER
3352 "footer",
3353#endif
3354#if !defined(USE_SYSTEM) && defined(UNIX)
3355 "fork",
3356#endif
3357#ifdef FEAT_GETTEXT
3358 "gettext",
3359#endif
3360#ifdef FEAT_GUI
3361 "gui",
3362#endif
3363#ifdef FEAT_GUI_ATHENA
3364# ifdef FEAT_GUI_NEXTAW
3365 "gui_neXtaw",
3366# else
3367 "gui_athena",
3368# endif
3369#endif
3370#ifdef FEAT_GUI_GTK
3371 "gui_gtk",
3372# ifdef USE_GTK3
3373 "gui_gtk3",
3374# else
3375 "gui_gtk2",
3376# endif
3377#endif
3378#ifdef FEAT_GUI_GNOME
3379 "gui_gnome",
3380#endif
3381#ifdef FEAT_GUI_MAC
3382 "gui_mac",
3383#endif
3384#ifdef FEAT_GUI_MOTIF
3385 "gui_motif",
3386#endif
3387#ifdef FEAT_GUI_PHOTON
3388 "gui_photon",
3389#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003390#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003391 "gui_win32",
3392#endif
3393#ifdef FEAT_HANGULIN
3394 "hangul_input",
3395#endif
3396#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3397 "iconv",
3398#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003399 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003400#ifdef FEAT_JOB_CHANNEL
3401 "job",
3402#endif
3403#ifdef FEAT_JUMPLIST
3404 "jumplist",
3405#endif
3406#ifdef FEAT_KEYMAP
3407 "keymap",
3408#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003409 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003410#ifdef FEAT_LANGMAP
3411 "langmap",
3412#endif
3413#ifdef FEAT_LIBCALL
3414 "libcall",
3415#endif
3416#ifdef FEAT_LINEBREAK
3417 "linebreak",
3418#endif
3419#ifdef FEAT_LISP
3420 "lispindent",
3421#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003422 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003423 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003424#ifdef FEAT_LUA
3425# ifndef DYNAMIC_LUA
3426 "lua",
3427# endif
3428#endif
3429#ifdef FEAT_MENU
3430 "menu",
3431#endif
3432#ifdef FEAT_SESSION
3433 "mksession",
3434#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003435 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436#ifdef FEAT_MOUSE
3437 "mouse",
3438#endif
3439#ifdef FEAT_MOUSESHAPE
3440 "mouseshape",
3441#endif
3442#if defined(UNIX) || defined(VMS)
3443# ifdef FEAT_MOUSE_DEC
3444 "mouse_dec",
3445# endif
3446# ifdef FEAT_MOUSE_GPM
3447 "mouse_gpm",
3448# endif
3449# ifdef FEAT_MOUSE_JSB
3450 "mouse_jsbterm",
3451# endif
3452# ifdef FEAT_MOUSE_NET
3453 "mouse_netterm",
3454# endif
3455# ifdef FEAT_MOUSE_PTERM
3456 "mouse_pterm",
3457# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003458# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003459 "mouse_sgr",
3460# endif
3461# ifdef FEAT_SYSMOUSE
3462 "mouse_sysmouse",
3463# endif
3464# ifdef FEAT_MOUSE_URXVT
3465 "mouse_urxvt",
3466# endif
3467# ifdef FEAT_MOUSE_XTERM
3468 "mouse_xterm",
3469# endif
3470#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003472#ifdef FEAT_MBYTE_IME
3473 "multi_byte_ime",
3474#endif
3475#ifdef FEAT_MULTI_LANG
3476 "multi_lang",
3477#endif
3478#ifdef FEAT_MZSCHEME
3479#ifndef DYNAMIC_MZSCHEME
3480 "mzscheme",
3481#endif
3482#endif
3483#ifdef FEAT_NUM64
3484 "num64",
3485#endif
3486#ifdef FEAT_OLE
3487 "ole",
3488#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003489#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003490 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003491#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492#ifdef FEAT_PATH_EXTRA
3493 "path_extra",
3494#endif
3495#ifdef FEAT_PERL
3496#ifndef DYNAMIC_PERL
3497 "perl",
3498#endif
3499#endif
3500#ifdef FEAT_PERSISTENT_UNDO
3501 "persistent_undo",
3502#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003503#if defined(FEAT_PYTHON)
3504 "python_compiled",
3505# if defined(DYNAMIC_PYTHON)
3506 "python_dynamic",
3507# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003508 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003509 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003510# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003511#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003512#if defined(FEAT_PYTHON3)
3513 "python3_compiled",
3514# if defined(DYNAMIC_PYTHON3)
3515 "python3_dynamic",
3516# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003517 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003518 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003519# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003520#endif
3521#ifdef FEAT_POSTSCRIPT
3522 "postscript",
3523#endif
3524#ifdef FEAT_PRINTER
3525 "printer",
3526#endif
3527#ifdef FEAT_PROFILE
3528 "profile",
3529#endif
3530#ifdef FEAT_RELTIME
3531 "reltime",
3532#endif
3533#ifdef FEAT_QUICKFIX
3534 "quickfix",
3535#endif
3536#ifdef FEAT_RIGHTLEFT
3537 "rightleft",
3538#endif
3539#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3540 "ruby",
3541#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003542 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003543#ifdef FEAT_CMDL_INFO
3544 "showcmd",
3545 "cmdline_info",
3546#endif
3547#ifdef FEAT_SIGNS
3548 "signs",
3549#endif
3550#ifdef FEAT_SMARTINDENT
3551 "smartindent",
3552#endif
3553#ifdef STARTUPTIME
3554 "startuptime",
3555#endif
3556#ifdef FEAT_STL_OPT
3557 "statusline",
3558#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003559#ifdef FEAT_NETBEANS_INTG
3560 "netbeans_intg",
3561#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003562#ifdef FEAT_SOUND
3563 "sound",
3564#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003565#ifdef FEAT_SPELL
3566 "spell",
3567#endif
3568#ifdef FEAT_SYN_HL
3569 "syntax",
3570#endif
3571#if defined(USE_SYSTEM) || !defined(UNIX)
3572 "system",
3573#endif
3574#ifdef FEAT_TAG_BINS
3575 "tag_binary",
3576#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003577#ifdef FEAT_TCL
3578# ifndef DYNAMIC_TCL
3579 "tcl",
3580# endif
3581#endif
3582#ifdef FEAT_TERMGUICOLORS
3583 "termguicolors",
3584#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003585#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003586 "terminal",
3587#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003588#ifdef TERMINFO
3589 "terminfo",
3590#endif
3591#ifdef FEAT_TERMRESPONSE
3592 "termresponse",
3593#endif
3594#ifdef FEAT_TEXTOBJ
3595 "textobjects",
3596#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003597#ifdef FEAT_TEXT_PROP
3598 "textprop",
3599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003600#ifdef HAVE_TGETENT
3601 "tgetent",
3602#endif
3603#ifdef FEAT_TIMERS
3604 "timers",
3605#endif
3606#ifdef FEAT_TITLE
3607 "title",
3608#endif
3609#ifdef FEAT_TOOLBAR
3610 "toolbar",
3611#endif
3612#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3613 "unnamedplus",
3614#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003615 "user-commands", /* was accidentally included in 5.4 */
3616 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003617#ifdef FEAT_VARTABS
3618 "vartabs",
3619#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003620 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003621#ifdef FEAT_VIMINFO
3622 "viminfo",
3623#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003624 "vimscript-1",
3625 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003626 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003627 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003628 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003629 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003630 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003631 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003632#ifdef FEAT_VTP
3633 "vtp",
3634#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003635#ifdef FEAT_WILDIGN
3636 "wildignore",
3637#endif
3638#ifdef FEAT_WILDMENU
3639 "wildmenu",
3640#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003641 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003642#ifdef FEAT_WAK
3643 "winaltkeys",
3644#endif
3645#ifdef FEAT_WRITEBACKUP
3646 "writebackup",
3647#endif
3648#ifdef FEAT_XIM
3649 "xim",
3650#endif
3651#ifdef FEAT_XFONTSET
3652 "xfontset",
3653#endif
3654#ifdef FEAT_XPM_W32
3655 "xpm",
3656 "xpm_w32", /* for backward compatibility */
3657#else
3658# if defined(HAVE_XPM)
3659 "xpm",
3660# endif
3661#endif
3662#ifdef USE_XSMP
3663 "xsmp",
3664#endif
3665#ifdef USE_XSMP_INTERACT
3666 "xsmp_interact",
3667#endif
3668#ifdef FEAT_XCLIPBOARD
3669 "xterm_clipboard",
3670#endif
3671#ifdef FEAT_XTERM_SAVE
3672 "xterm_save",
3673#endif
3674#if defined(UNIX) && defined(FEAT_X11)
3675 "X11",
3676#endif
3677 NULL
3678 };
3679
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003680 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681 for (i = 0; has_list[i] != NULL; ++i)
3682 if (STRICMP(name, has_list[i]) == 0)
3683 {
3684 n = TRUE;
3685 break;
3686 }
3687
3688 if (n == FALSE)
3689 {
3690 if (STRNICMP(name, "patch", 5) == 0)
3691 {
3692 if (name[5] == '-'
3693 && STRLEN(name) >= 11
3694 && vim_isdigit(name[6])
3695 && vim_isdigit(name[8])
3696 && vim_isdigit(name[10]))
3697 {
3698 int major = atoi((char *)name + 6);
3699 int minor = atoi((char *)name + 8);
3700
3701 /* Expect "patch-9.9.01234". */
3702 n = (major < VIM_VERSION_MAJOR
3703 || (major == VIM_VERSION_MAJOR
3704 && (minor < VIM_VERSION_MINOR
3705 || (minor == VIM_VERSION_MINOR
3706 && has_patch(atoi((char *)name + 10))))));
3707 }
3708 else
3709 n = has_patch(atoi((char *)name + 5));
3710 }
3711 else if (STRICMP(name, "vim_starting") == 0)
3712 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003713 else if (STRICMP(name, "ttyin") == 0)
3714 n = mch_input_isatty();
3715 else if (STRICMP(name, "ttyout") == 0)
3716 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003717 else if (STRICMP(name, "multi_byte_encoding") == 0)
3718 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003719#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720 else if (STRICMP(name, "balloon_multiline") == 0)
3721 n = multiline_balloon_available();
3722#endif
3723#ifdef DYNAMIC_TCL
3724 else if (STRICMP(name, "tcl") == 0)
3725 n = tcl_enabled(FALSE);
3726#endif
3727#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3728 else if (STRICMP(name, "iconv") == 0)
3729 n = iconv_enabled(FALSE);
3730#endif
3731#ifdef DYNAMIC_LUA
3732 else if (STRICMP(name, "lua") == 0)
3733 n = lua_enabled(FALSE);
3734#endif
3735#ifdef DYNAMIC_MZSCHEME
3736 else if (STRICMP(name, "mzscheme") == 0)
3737 n = mzscheme_enabled(FALSE);
3738#endif
3739#ifdef DYNAMIC_RUBY
3740 else if (STRICMP(name, "ruby") == 0)
3741 n = ruby_enabled(FALSE);
3742#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003743#ifdef DYNAMIC_PYTHON
3744 else if (STRICMP(name, "python") == 0)
3745 n = python_enabled(FALSE);
3746#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747#ifdef DYNAMIC_PYTHON3
3748 else if (STRICMP(name, "python3") == 0)
3749 n = python3_enabled(FALSE);
3750#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003751#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3752 else if (STRICMP(name, "pythonx") == 0)
3753 {
3754# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3755 if (p_pyx == 0)
3756 n = python3_enabled(FALSE) || python_enabled(FALSE);
3757 else if (p_pyx == 3)
3758 n = python3_enabled(FALSE);
3759 else if (p_pyx == 2)
3760 n = python_enabled(FALSE);
3761# elif defined(DYNAMIC_PYTHON)
3762 n = python_enabled(FALSE);
3763# elif defined(DYNAMIC_PYTHON3)
3764 n = python3_enabled(FALSE);
3765# endif
3766 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003767#endif
3768#ifdef DYNAMIC_PERL
3769 else if (STRICMP(name, "perl") == 0)
3770 n = perl_enabled(FALSE);
3771#endif
3772#ifdef FEAT_GUI
3773 else if (STRICMP(name, "gui_running") == 0)
3774 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003775# ifdef FEAT_BROWSE
3776 else if (STRICMP(name, "browse") == 0)
3777 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3778# endif
3779#endif
3780#ifdef FEAT_SYN_HL
3781 else if (STRICMP(name, "syntax_items") == 0)
3782 n = syntax_present(curwin);
3783#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003784#ifdef FEAT_VTP
3785 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003786 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003787#endif
3788#ifdef FEAT_NETBEANS_INTG
3789 else if (STRICMP(name, "netbeans_enabled") == 0)
3790 n = netbeans_active();
3791#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003792#ifdef FEAT_MOUSE_GPM
3793 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3794 n = gpm_enabled();
3795#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003796#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003797 else if (STRICMP(name, "terminal") == 0)
3798 n = terminal_enabled();
3799#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003800#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003801 else if (STRICMP(name, "conpty") == 0)
3802 n = use_conpty();
3803#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003804#ifdef FEAT_CLIPBOARD
3805 else if (STRICMP(name, "clipboard_working") == 0)
3806 n = clip_star.available;
3807#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003808 }
3809
3810 rettv->vval.v_number = n;
3811}
3812
3813/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003814 * "haslocaldir()" function
3815 */
3816 static void
3817f_haslocaldir(typval_T *argvars, typval_T *rettv)
3818{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003819 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003820 win_T *wp = NULL;
3821
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003822 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3823
3824 // Check for window-local and tab-local directories
3825 if (wp != NULL && wp->w_localdir != NULL)
3826 rettv->vval.v_number = 1;
3827 else if (tp != NULL && tp->tp_localdir != NULL)
3828 rettv->vval.v_number = 2;
3829 else
3830 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003831}
3832
3833/*
3834 * "hasmapto()" function
3835 */
3836 static void
3837f_hasmapto(typval_T *argvars, typval_T *rettv)
3838{
3839 char_u *name;
3840 char_u *mode;
3841 char_u buf[NUMBUFLEN];
3842 int abbr = FALSE;
3843
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003844 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003845 if (argvars[1].v_type == VAR_UNKNOWN)
3846 mode = (char_u *)"nvo";
3847 else
3848 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003849 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003850 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003851 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003852 }
3853
3854 if (map_to_exists(name, mode, abbr))
3855 rettv->vval.v_number = TRUE;
3856 else
3857 rettv->vval.v_number = FALSE;
3858}
3859
3860/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003861 * "highlightID(name)" function
3862 */
3863 static void
3864f_hlID(typval_T *argvars, typval_T *rettv)
3865{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003866 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003867}
3868
3869/*
3870 * "highlight_exists()" function
3871 */
3872 static void
3873f_hlexists(typval_T *argvars, typval_T *rettv)
3874{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003875 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003876}
3877
3878/*
3879 * "hostname()" function
3880 */
3881 static void
3882f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3883{
3884 char_u hostname[256];
3885
3886 mch_get_host_name(hostname, 256);
3887 rettv->v_type = VAR_STRING;
3888 rettv->vval.v_string = vim_strsave(hostname);
3889}
3890
3891/*
3892 * iconv() function
3893 */
3894 static void
3895f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3896{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003897 char_u buf1[NUMBUFLEN];
3898 char_u buf2[NUMBUFLEN];
3899 char_u *from, *to, *str;
3900 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003901
3902 rettv->v_type = VAR_STRING;
3903 rettv->vval.v_string = NULL;
3904
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003905 str = tv_get_string(&argvars[0]);
3906 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3907 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003908 vimconv.vc_type = CONV_NONE;
3909 convert_setup(&vimconv, from, to);
3910
3911 /* If the encodings are equal, no conversion needed. */
3912 if (vimconv.vc_type == CONV_NONE)
3913 rettv->vval.v_string = vim_strsave(str);
3914 else
3915 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
3916
3917 convert_setup(&vimconv, NULL, NULL);
3918 vim_free(from);
3919 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003920}
3921
3922/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003923 * "index()" function
3924 */
3925 static void
3926f_index(typval_T *argvars, typval_T *rettv)
3927{
3928 list_T *l;
3929 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003930 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003931 long idx = 0;
3932 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003933 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934
3935 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003936 if (argvars[0].v_type == VAR_BLOB)
3937 {
3938 typval_T tv;
3939 int start = 0;
3940
3941 if (argvars[2].v_type != VAR_UNKNOWN)
3942 {
3943 start = tv_get_number_chk(&argvars[2], &error);
3944 if (error)
3945 return;
3946 }
3947 b = argvars[0].vval.v_blob;
3948 if (b == NULL)
3949 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01003950 if (start < 0)
3951 {
3952 start = blob_len(b) + start;
3953 if (start < 0)
3954 start = 0;
3955 }
3956
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003957 for (idx = start; idx < blob_len(b); ++idx)
3958 {
3959 tv.v_type = VAR_NUMBER;
3960 tv.vval.v_number = blob_get(b, idx);
3961 if (tv_equal(&tv, &argvars[1], ic, FALSE))
3962 {
3963 rettv->vval.v_number = idx;
3964 return;
3965 }
3966 }
3967 return;
3968 }
3969 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003970 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003971 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003972 return;
3973 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003974
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003975 l = argvars[0].vval.v_list;
3976 if (l != NULL)
3977 {
3978 item = l->lv_first;
3979 if (argvars[2].v_type != VAR_UNKNOWN)
3980 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003981 /* Start at specified item. Use the cached index that list_find()
3982 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003983 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003984 idx = l->lv_idx;
3985 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003986 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003987 if (error)
3988 item = NULL;
3989 }
3990
3991 for ( ; item != NULL; item = item->li_next, ++idx)
3992 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
3993 {
3994 rettv->vval.v_number = idx;
3995 break;
3996 }
3997 }
3998}
3999
4000static int inputsecret_flag = 0;
4001
4002/*
4003 * "input()" function
4004 * Also handles inputsecret() when inputsecret is set.
4005 */
4006 static void
4007f_input(typval_T *argvars, typval_T *rettv)
4008{
4009 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4010}
4011
4012/*
4013 * "inputdialog()" function
4014 */
4015 static void
4016f_inputdialog(typval_T *argvars, typval_T *rettv)
4017{
4018#if defined(FEAT_GUI_TEXTDIALOG)
4019 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4020 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4021 {
4022 char_u *message;
4023 char_u buf[NUMBUFLEN];
4024 char_u *defstr = (char_u *)"";
4025
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004026 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004027 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004028 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004029 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4030 else
4031 IObuff[0] = NUL;
4032 if (message != NULL && defstr != NULL
4033 && do_dialog(VIM_QUESTION, NULL, message,
4034 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4035 rettv->vval.v_string = vim_strsave(IObuff);
4036 else
4037 {
4038 if (message != NULL && defstr != NULL
4039 && argvars[1].v_type != VAR_UNKNOWN
4040 && argvars[2].v_type != VAR_UNKNOWN)
4041 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004042 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004043 else
4044 rettv->vval.v_string = NULL;
4045 }
4046 rettv->v_type = VAR_STRING;
4047 }
4048 else
4049#endif
4050 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4051}
4052
4053/*
4054 * "inputlist()" function
4055 */
4056 static void
4057f_inputlist(typval_T *argvars, typval_T *rettv)
4058{
4059 listitem_T *li;
4060 int selected;
4061 int mouse_used;
4062
4063#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004064 /* While starting up, there is no place to enter text. When running tests
4065 * with --not-a-term we assume feedkeys() will be used. */
4066 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004067 return;
4068#endif
4069 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4070 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004071 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004072 return;
4073 }
4074
4075 msg_start();
4076 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4077 lines_left = Rows; /* avoid more prompt */
4078 msg_scroll = TRUE;
4079 msg_clr_eos();
4080
4081 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4082 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004083 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004084 msg_putchar('\n');
4085 }
4086
4087 /* Ask for choice. */
4088 selected = prompt_for_number(&mouse_used);
4089 if (mouse_used)
4090 selected -= lines_left;
4091
4092 rettv->vval.v_number = selected;
4093}
4094
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004095static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4096
4097/*
4098 * "inputrestore()" function
4099 */
4100 static void
4101f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4102{
4103 if (ga_userinput.ga_len > 0)
4104 {
4105 --ga_userinput.ga_len;
4106 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4107 + ga_userinput.ga_len);
4108 /* default return is zero == OK */
4109 }
4110 else if (p_verbose > 1)
4111 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004112 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004113 rettv->vval.v_number = 1; /* Failed */
4114 }
4115}
4116
4117/*
4118 * "inputsave()" function
4119 */
4120 static void
4121f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4122{
4123 /* Add an entry to the stack of typeahead storage. */
4124 if (ga_grow(&ga_userinput, 1) == OK)
4125 {
4126 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4127 + ga_userinput.ga_len);
4128 ++ga_userinput.ga_len;
4129 /* default return is zero == OK */
4130 }
4131 else
4132 rettv->vval.v_number = 1; /* Failed */
4133}
4134
4135/*
4136 * "inputsecret()" function
4137 */
4138 static void
4139f_inputsecret(typval_T *argvars, typval_T *rettv)
4140{
4141 ++cmdline_star;
4142 ++inputsecret_flag;
4143 f_input(argvars, rettv);
4144 --cmdline_star;
4145 --inputsecret_flag;
4146}
4147
4148/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004149 * "invert(expr)" function
4150 */
4151 static void
4152f_invert(typval_T *argvars, typval_T *rettv)
4153{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004154 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004155}
4156
4157/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004158 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4159 * or it refers to a List or Dictionary that is locked.
4160 */
4161 static int
4162tv_islocked(typval_T *tv)
4163{
4164 return (tv->v_lock & VAR_LOCKED)
4165 || (tv->v_type == VAR_LIST
4166 && tv->vval.v_list != NULL
4167 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4168 || (tv->v_type == VAR_DICT
4169 && tv->vval.v_dict != NULL
4170 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4171}
4172
4173/*
4174 * "islocked()" function
4175 */
4176 static void
4177f_islocked(typval_T *argvars, typval_T *rettv)
4178{
4179 lval_T lv;
4180 char_u *end;
4181 dictitem_T *di;
4182
4183 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004184 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004185 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004186 if (end != NULL && lv.ll_name != NULL)
4187 {
4188 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004189 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004190 else
4191 {
4192 if (lv.ll_tv == NULL)
4193 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004194 di = find_var(lv.ll_name, NULL, TRUE);
4195 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004196 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004197 /* Consider a variable locked when:
4198 * 1. the variable itself is locked
4199 * 2. the value of the variable is locked.
4200 * 3. the List or Dict value is locked.
4201 */
4202 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4203 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004204 }
4205 }
4206 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004207 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004208 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004209 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004210 else if (lv.ll_list != NULL)
4211 /* List item. */
4212 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4213 else
4214 /* Dictionary item. */
4215 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4216 }
4217 }
4218
4219 clear_lval(&lv);
4220}
4221
4222#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4223/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004224 * "isinf()" function
4225 */
4226 static void
4227f_isinf(typval_T *argvars, typval_T *rettv)
4228{
4229 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4230 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4231}
4232
4233/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004234 * "isnan()" function
4235 */
4236 static void
4237f_isnan(typval_T *argvars, typval_T *rettv)
4238{
4239 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4240 && isnan(argvars[0].vval.v_float);
4241}
4242#endif
4243
4244/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004245 * "last_buffer_nr()" function.
4246 */
4247 static void
4248f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4249{
4250 int n = 0;
4251 buf_T *buf;
4252
Bram Moolenaar29323592016-07-24 22:04:11 +02004253 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004254 if (n < buf->b_fnum)
4255 n = buf->b_fnum;
4256
4257 rettv->vval.v_number = n;
4258}
4259
4260/*
4261 * "len()" function
4262 */
4263 static void
4264f_len(typval_T *argvars, typval_T *rettv)
4265{
4266 switch (argvars[0].v_type)
4267 {
4268 case VAR_STRING:
4269 case VAR_NUMBER:
4270 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004271 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004272 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004273 case VAR_BLOB:
4274 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4275 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004276 case VAR_LIST:
4277 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4278 break;
4279 case VAR_DICT:
4280 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4281 break;
4282 case VAR_UNKNOWN:
4283 case VAR_SPECIAL:
4284 case VAR_FLOAT:
4285 case VAR_FUNC:
4286 case VAR_PARTIAL:
4287 case VAR_JOB:
4288 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004289 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004290 break;
4291 }
4292}
4293
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004294 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004295libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004296{
4297#ifdef FEAT_LIBCALL
4298 char_u *string_in;
4299 char_u **string_result;
4300 int nr_result;
4301#endif
4302
4303 rettv->v_type = type;
4304 if (type != VAR_NUMBER)
4305 rettv->vval.v_string = NULL;
4306
4307 if (check_restricted() || check_secure())
4308 return;
4309
4310#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004311 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004312 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4313 {
4314 string_in = NULL;
4315 if (argvars[2].v_type == VAR_STRING)
4316 string_in = argvars[2].vval.v_string;
4317 if (type == VAR_NUMBER)
4318 string_result = NULL;
4319 else
4320 string_result = &rettv->vval.v_string;
4321 if (mch_libcall(argvars[0].vval.v_string,
4322 argvars[1].vval.v_string,
4323 string_in,
4324 argvars[2].vval.v_number,
4325 string_result,
4326 &nr_result) == OK
4327 && type == VAR_NUMBER)
4328 rettv->vval.v_number = nr_result;
4329 }
4330#endif
4331}
4332
4333/*
4334 * "libcall()" function
4335 */
4336 static void
4337f_libcall(typval_T *argvars, typval_T *rettv)
4338{
4339 libcall_common(argvars, rettv, VAR_STRING);
4340}
4341
4342/*
4343 * "libcallnr()" function
4344 */
4345 static void
4346f_libcallnr(typval_T *argvars, typval_T *rettv)
4347{
4348 libcall_common(argvars, rettv, VAR_NUMBER);
4349}
4350
4351/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004352 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004353 */
4354 static void
4355f_line(typval_T *argvars, typval_T *rettv)
4356{
4357 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004358 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004359 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004360 int id;
4361 tabpage_T *tp;
4362 win_T *wp;
4363 win_T *save_curwin;
4364 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004365
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004366 if (argvars[1].v_type != VAR_UNKNOWN)
4367 {
4368 // use window specified in the second argument
4369 id = (int)tv_get_number(&argvars[1]);
4370 wp = win_id2wp_tp(id, &tp);
4371 if (wp != NULL && tp != NULL)
4372 {
4373 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4374 == OK)
4375 {
4376 check_cursor();
4377 fp = var2fpos(&argvars[0], TRUE, &fnum);
4378 }
4379 restore_win_noblock(save_curwin, save_curtab, TRUE);
4380 }
4381 }
4382 else
4383 // use current window
4384 fp = var2fpos(&argvars[0], TRUE, &fnum);
4385
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004386 if (fp != NULL)
4387 lnum = fp->lnum;
4388 rettv->vval.v_number = lnum;
4389}
4390
4391/*
4392 * "line2byte(lnum)" function
4393 */
4394 static void
4395f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4396{
4397#ifndef FEAT_BYTEOFF
4398 rettv->vval.v_number = -1;
4399#else
4400 linenr_T lnum;
4401
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004402 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004403 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4404 rettv->vval.v_number = -1;
4405 else
4406 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4407 if (rettv->vval.v_number >= 0)
4408 ++rettv->vval.v_number;
4409#endif
4410}
4411
4412/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004413 * "localtime()" function
4414 */
4415 static void
4416f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4417{
4418 rettv->vval.v_number = (varnumber_T)time(NULL);
4419}
4420
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004421#ifdef FEAT_FLOAT
4422/*
4423 * "log()" function
4424 */
4425 static void
4426f_log(typval_T *argvars, typval_T *rettv)
4427{
4428 float_T f = 0.0;
4429
4430 rettv->v_type = VAR_FLOAT;
4431 if (get_float_arg(argvars, &f) == OK)
4432 rettv->vval.v_float = log(f);
4433 else
4434 rettv->vval.v_float = 0.0;
4435}
4436
4437/*
4438 * "log10()" function
4439 */
4440 static void
4441f_log10(typval_T *argvars, typval_T *rettv)
4442{
4443 float_T f = 0.0;
4444
4445 rettv->v_type = VAR_FLOAT;
4446 if (get_float_arg(argvars, &f) == OK)
4447 rettv->vval.v_float = log10(f);
4448 else
4449 rettv->vval.v_float = 0.0;
4450}
4451#endif
4452
4453#ifdef FEAT_LUA
4454/*
4455 * "luaeval()" function
4456 */
4457 static void
4458f_luaeval(typval_T *argvars, typval_T *rettv)
4459{
4460 char_u *str;
4461 char_u buf[NUMBUFLEN];
4462
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004463 if (check_restricted() || check_secure())
4464 return;
4465
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004466 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004467 do_luaeval(str, argvars + 1, rettv);
4468}
4469#endif
4470
4471/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004472 * "maparg()" function
4473 */
4474 static void
4475f_maparg(typval_T *argvars, typval_T *rettv)
4476{
4477 get_maparg(argvars, rettv, TRUE);
4478}
4479
4480/*
4481 * "mapcheck()" function
4482 */
4483 static void
4484f_mapcheck(typval_T *argvars, typval_T *rettv)
4485{
4486 get_maparg(argvars, rettv, FALSE);
4487}
4488
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004489typedef enum
4490{
4491 MATCH_END, /* matchend() */
4492 MATCH_MATCH, /* match() */
4493 MATCH_STR, /* matchstr() */
4494 MATCH_LIST, /* matchlist() */
4495 MATCH_POS /* matchstrpos() */
4496} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004497
4498 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004499find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004500{
4501 char_u *str = NULL;
4502 long len = 0;
4503 char_u *expr = NULL;
4504 char_u *pat;
4505 regmatch_T regmatch;
4506 char_u patbuf[NUMBUFLEN];
4507 char_u strbuf[NUMBUFLEN];
4508 char_u *save_cpo;
4509 long start = 0;
4510 long nth = 1;
4511 colnr_T startcol = 0;
4512 int match = 0;
4513 list_T *l = NULL;
4514 listitem_T *li = NULL;
4515 long idx = 0;
4516 char_u *tofree = NULL;
4517
4518 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4519 save_cpo = p_cpo;
4520 p_cpo = (char_u *)"";
4521
4522 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004523 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004524 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004525 /* type MATCH_LIST: return empty list when there are no matches.
4526 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004527 if (rettv_list_alloc(rettv) == FAIL)
4528 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004529 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004530 && (list_append_string(rettv->vval.v_list,
4531 (char_u *)"", 0) == FAIL
4532 || list_append_number(rettv->vval.v_list,
4533 (varnumber_T)-1) == FAIL
4534 || list_append_number(rettv->vval.v_list,
4535 (varnumber_T)-1) == FAIL
4536 || list_append_number(rettv->vval.v_list,
4537 (varnumber_T)-1) == FAIL))
4538 {
4539 list_free(rettv->vval.v_list);
4540 rettv->vval.v_list = NULL;
4541 goto theend;
4542 }
4543 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004544 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004545 {
4546 rettv->v_type = VAR_STRING;
4547 rettv->vval.v_string = NULL;
4548 }
4549
4550 if (argvars[0].v_type == VAR_LIST)
4551 {
4552 if ((l = argvars[0].vval.v_list) == NULL)
4553 goto theend;
4554 li = l->lv_first;
4555 }
4556 else
4557 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004558 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004559 len = (long)STRLEN(str);
4560 }
4561
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004562 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004563 if (pat == NULL)
4564 goto theend;
4565
4566 if (argvars[2].v_type != VAR_UNKNOWN)
4567 {
4568 int error = FALSE;
4569
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004570 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004571 if (error)
4572 goto theend;
4573 if (l != NULL)
4574 {
4575 li = list_find(l, start);
4576 if (li == NULL)
4577 goto theend;
4578 idx = l->lv_idx; /* use the cached index */
4579 }
4580 else
4581 {
4582 if (start < 0)
4583 start = 0;
4584 if (start > len)
4585 goto theend;
4586 /* When "count" argument is there ignore matches before "start",
4587 * otherwise skip part of the string. Differs when pattern is "^"
4588 * or "\<". */
4589 if (argvars[3].v_type != VAR_UNKNOWN)
4590 startcol = start;
4591 else
4592 {
4593 str += start;
4594 len -= start;
4595 }
4596 }
4597
4598 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004599 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004600 if (error)
4601 goto theend;
4602 }
4603
4604 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4605 if (regmatch.regprog != NULL)
4606 {
4607 regmatch.rm_ic = p_ic;
4608
4609 for (;;)
4610 {
4611 if (l != NULL)
4612 {
4613 if (li == NULL)
4614 {
4615 match = FALSE;
4616 break;
4617 }
4618 vim_free(tofree);
4619 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4620 if (str == NULL)
4621 break;
4622 }
4623
4624 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4625
4626 if (match && --nth <= 0)
4627 break;
4628 if (l == NULL && !match)
4629 break;
4630
4631 /* Advance to just after the match. */
4632 if (l != NULL)
4633 {
4634 li = li->li_next;
4635 ++idx;
4636 }
4637 else
4638 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004639 startcol = (colnr_T)(regmatch.startp[0]
4640 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004641 if (startcol > (colnr_T)len
4642 || str + startcol <= regmatch.startp[0])
4643 {
4644 match = FALSE;
4645 break;
4646 }
4647 }
4648 }
4649
4650 if (match)
4651 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004652 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004653 {
4654 listitem_T *li1 = rettv->vval.v_list->lv_first;
4655 listitem_T *li2 = li1->li_next;
4656 listitem_T *li3 = li2->li_next;
4657 listitem_T *li4 = li3->li_next;
4658
4659 vim_free(li1->li_tv.vval.v_string);
4660 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4661 (int)(regmatch.endp[0] - regmatch.startp[0]));
4662 li3->li_tv.vval.v_number =
4663 (varnumber_T)(regmatch.startp[0] - expr);
4664 li4->li_tv.vval.v_number =
4665 (varnumber_T)(regmatch.endp[0] - expr);
4666 if (l != NULL)
4667 li2->li_tv.vval.v_number = (varnumber_T)idx;
4668 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004669 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004670 {
4671 int i;
4672
4673 /* return list with matched string and submatches */
4674 for (i = 0; i < NSUBEXP; ++i)
4675 {
4676 if (regmatch.endp[i] == NULL)
4677 {
4678 if (list_append_string(rettv->vval.v_list,
4679 (char_u *)"", 0) == FAIL)
4680 break;
4681 }
4682 else if (list_append_string(rettv->vval.v_list,
4683 regmatch.startp[i],
4684 (int)(regmatch.endp[i] - regmatch.startp[i]))
4685 == FAIL)
4686 break;
4687 }
4688 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004689 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004690 {
4691 /* return matched string */
4692 if (l != NULL)
4693 copy_tv(&li->li_tv, rettv);
4694 else
4695 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4696 (int)(regmatch.endp[0] - regmatch.startp[0]));
4697 }
4698 else if (l != NULL)
4699 rettv->vval.v_number = idx;
4700 else
4701 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004702 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004703 rettv->vval.v_number =
4704 (varnumber_T)(regmatch.startp[0] - str);
4705 else
4706 rettv->vval.v_number =
4707 (varnumber_T)(regmatch.endp[0] - str);
4708 rettv->vval.v_number += (varnumber_T)(str - expr);
4709 }
4710 }
4711 vim_regfree(regmatch.regprog);
4712 }
4713
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004714theend:
4715 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004716 /* matchstrpos() without a list: drop the second item. */
4717 listitem_remove(rettv->vval.v_list,
4718 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719 vim_free(tofree);
4720 p_cpo = save_cpo;
4721}
4722
4723/*
4724 * "match()" function
4725 */
4726 static void
4727f_match(typval_T *argvars, typval_T *rettv)
4728{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004729 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004730}
4731
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004732/*
4733 * "matchend()" function
4734 */
4735 static void
4736f_matchend(typval_T *argvars, typval_T *rettv)
4737{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004738 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004739}
4740
4741/*
4742 * "matchlist()" function
4743 */
4744 static void
4745f_matchlist(typval_T *argvars, typval_T *rettv)
4746{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004747 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004748}
4749
4750/*
4751 * "matchstr()" function
4752 */
4753 static void
4754f_matchstr(typval_T *argvars, typval_T *rettv)
4755{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004756 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004757}
4758
4759/*
4760 * "matchstrpos()" function
4761 */
4762 static void
4763f_matchstrpos(typval_T *argvars, typval_T *rettv)
4764{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004765 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766}
4767
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768 static void
4769max_min(typval_T *argvars, typval_T *rettv, int domax)
4770{
4771 varnumber_T n = 0;
4772 varnumber_T i;
4773 int error = FALSE;
4774
4775 if (argvars[0].v_type == VAR_LIST)
4776 {
4777 list_T *l;
4778 listitem_T *li;
4779
4780 l = argvars[0].vval.v_list;
4781 if (l != NULL)
4782 {
4783 li = l->lv_first;
4784 if (li != NULL)
4785 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004786 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004787 for (;;)
4788 {
4789 li = li->li_next;
4790 if (li == NULL)
4791 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004792 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004793 if (domax ? i > n : i < n)
4794 n = i;
4795 }
4796 }
4797 }
4798 }
4799 else if (argvars[0].v_type == VAR_DICT)
4800 {
4801 dict_T *d;
4802 int first = TRUE;
4803 hashitem_T *hi;
4804 int todo;
4805
4806 d = argvars[0].vval.v_dict;
4807 if (d != NULL)
4808 {
4809 todo = (int)d->dv_hashtab.ht_used;
4810 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4811 {
4812 if (!HASHITEM_EMPTY(hi))
4813 {
4814 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004815 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004816 if (first)
4817 {
4818 n = i;
4819 first = FALSE;
4820 }
4821 else if (domax ? i > n : i < n)
4822 n = i;
4823 }
4824 }
4825 }
4826 }
4827 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004828 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004829 rettv->vval.v_number = error ? 0 : n;
4830}
4831
4832/*
4833 * "max()" function
4834 */
4835 static void
4836f_max(typval_T *argvars, typval_T *rettv)
4837{
4838 max_min(argvars, rettv, TRUE);
4839}
4840
4841/*
4842 * "min()" function
4843 */
4844 static void
4845f_min(typval_T *argvars, typval_T *rettv)
4846{
4847 max_min(argvars, rettv, FALSE);
4848}
4849
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004850#if defined(FEAT_MZSCHEME) || defined(PROTO)
4851/*
4852 * "mzeval()" function
4853 */
4854 static void
4855f_mzeval(typval_T *argvars, typval_T *rettv)
4856{
4857 char_u *str;
4858 char_u buf[NUMBUFLEN];
4859
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004860 if (check_restricted() || check_secure())
4861 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004862 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004863 do_mzeval(str, rettv);
4864}
4865
4866 void
4867mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
4868{
4869 typval_T argvars[3];
4870
4871 argvars[0].v_type = VAR_STRING;
4872 argvars[0].vval.v_string = name;
4873 copy_tv(args, &argvars[1]);
4874 argvars[2].v_type = VAR_UNKNOWN;
4875 f_call(argvars, rettv);
4876 clear_tv(&argvars[1]);
4877}
4878#endif
4879
4880/*
4881 * "nextnonblank()" function
4882 */
4883 static void
4884f_nextnonblank(typval_T *argvars, typval_T *rettv)
4885{
4886 linenr_T lnum;
4887
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004888 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004889 {
4890 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
4891 {
4892 lnum = 0;
4893 break;
4894 }
4895 if (*skipwhite(ml_get(lnum)) != NUL)
4896 break;
4897 }
4898 rettv->vval.v_number = lnum;
4899}
4900
4901/*
4902 * "nr2char()" function
4903 */
4904 static void
4905f_nr2char(typval_T *argvars, typval_T *rettv)
4906{
4907 char_u buf[NUMBUFLEN];
4908
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909 if (has_mbyte)
4910 {
4911 int utf8 = 0;
4912
4913 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004914 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01004916 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004918 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004919 }
4920 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004921 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004922 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004923 buf[1] = NUL;
4924 }
4925 rettv->v_type = VAR_STRING;
4926 rettv->vval.v_string = vim_strsave(buf);
4927}
4928
4929/*
4930 * "or(expr, expr)" function
4931 */
4932 static void
4933f_or(typval_T *argvars, typval_T *rettv)
4934{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004935 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
4936 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004937}
4938
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004939#ifdef FEAT_PERL
4940/*
4941 * "perleval()" function
4942 */
4943 static void
4944f_perleval(typval_T *argvars, typval_T *rettv)
4945{
4946 char_u *str;
4947 char_u buf[NUMBUFLEN];
4948
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004949 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004950 do_perleval(str, rettv);
4951}
4952#endif
4953
4954#ifdef FEAT_FLOAT
4955/*
4956 * "pow()" function
4957 */
4958 static void
4959f_pow(typval_T *argvars, typval_T *rettv)
4960{
4961 float_T fx = 0.0, fy = 0.0;
4962
4963 rettv->v_type = VAR_FLOAT;
4964 if (get_float_arg(argvars, &fx) == OK
4965 && get_float_arg(&argvars[1], &fy) == OK)
4966 rettv->vval.v_float = pow(fx, fy);
4967 else
4968 rettv->vval.v_float = 0.0;
4969}
4970#endif
4971
4972/*
4973 * "prevnonblank()" function
4974 */
4975 static void
4976f_prevnonblank(typval_T *argvars, typval_T *rettv)
4977{
4978 linenr_T lnum;
4979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004980 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004981 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
4982 lnum = 0;
4983 else
4984 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
4985 --lnum;
4986 rettv->vval.v_number = lnum;
4987}
4988
4989/* This dummy va_list is here because:
4990 * - passing a NULL pointer doesn't work when va_list isn't a pointer
4991 * - locally in the function results in a "used before set" warning
4992 * - using va_start() to initialize it gives "function with fixed args" error */
4993static va_list ap;
4994
4995/*
4996 * "printf()" function
4997 */
4998 static void
4999f_printf(typval_T *argvars, typval_T *rettv)
5000{
5001 char_u buf[NUMBUFLEN];
5002 int len;
5003 char_u *s;
5004 int saved_did_emsg = did_emsg;
5005 char *fmt;
5006
5007 rettv->v_type = VAR_STRING;
5008 rettv->vval.v_string = NULL;
5009
5010 /* Get the required length, allocate the buffer and do it for real. */
5011 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005012 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005013 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005014 if (!did_emsg)
5015 {
5016 s = alloc(len + 1);
5017 if (s != NULL)
5018 {
5019 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005020 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5021 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005022 }
5023 }
5024 did_emsg |= saved_did_emsg;
5025}
5026
5027/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005028 * "pum_getpos()" function
5029 */
5030 static void
5031f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5032{
5033 if (rettv_dict_alloc(rettv) != OK)
5034 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005035 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005036}
5037
5038/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005039 * "pumvisible()" function
5040 */
5041 static void
5042f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5043{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005044 if (pum_visible())
5045 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005046}
5047
5048#ifdef FEAT_PYTHON3
5049/*
5050 * "py3eval()" function
5051 */
5052 static void
5053f_py3eval(typval_T *argvars, typval_T *rettv)
5054{
5055 char_u *str;
5056 char_u buf[NUMBUFLEN];
5057
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005058 if (check_restricted() || check_secure())
5059 return;
5060
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005061 if (p_pyx == 0)
5062 p_pyx = 3;
5063
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005064 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005065 do_py3eval(str, rettv);
5066}
5067#endif
5068
5069#ifdef FEAT_PYTHON
5070/*
5071 * "pyeval()" function
5072 */
5073 static void
5074f_pyeval(typval_T *argvars, typval_T *rettv)
5075{
5076 char_u *str;
5077 char_u buf[NUMBUFLEN];
5078
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005079 if (check_restricted() || check_secure())
5080 return;
5081
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005082 if (p_pyx == 0)
5083 p_pyx = 2;
5084
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005085 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005086 do_pyeval(str, rettv);
5087}
5088#endif
5089
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005090#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5091/*
5092 * "pyxeval()" function
5093 */
5094 static void
5095f_pyxeval(typval_T *argvars, typval_T *rettv)
5096{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005097 if (check_restricted() || check_secure())
5098 return;
5099
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005100# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5101 init_pyxversion();
5102 if (p_pyx == 2)
5103 f_pyeval(argvars, rettv);
5104 else
5105 f_py3eval(argvars, rettv);
5106# elif defined(FEAT_PYTHON)
5107 f_pyeval(argvars, rettv);
5108# elif defined(FEAT_PYTHON3)
5109 f_py3eval(argvars, rettv);
5110# endif
5111}
5112#endif
5113
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005114/*
5115 * "range()" function
5116 */
5117 static void
5118f_range(typval_T *argvars, typval_T *rettv)
5119{
5120 varnumber_T start;
5121 varnumber_T end;
5122 varnumber_T stride = 1;
5123 varnumber_T i;
5124 int error = FALSE;
5125
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005126 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005127 if (argvars[1].v_type == VAR_UNKNOWN)
5128 {
5129 end = start - 1;
5130 start = 0;
5131 }
5132 else
5133 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005134 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005135 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005136 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005137 }
5138
5139 if (error)
5140 return; /* type error; errmsg already given */
5141 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005142 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005143 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005144 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145 else
5146 {
5147 if (rettv_list_alloc(rettv) == OK)
5148 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5149 if (list_append_number(rettv->vval.v_list,
5150 (varnumber_T)i) == FAIL)
5151 break;
5152 }
5153}
5154
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005155 static void
5156return_register(int regname, typval_T *rettv)
5157{
5158 char_u buf[2] = {0, 0};
5159
5160 buf[0] = (char_u)regname;
5161 rettv->v_type = VAR_STRING;
5162 rettv->vval.v_string = vim_strsave(buf);
5163}
5164
5165/*
5166 * "reg_executing()" function
5167 */
5168 static void
5169f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5170{
5171 return_register(reg_executing, rettv);
5172}
5173
5174/*
5175 * "reg_recording()" function
5176 */
5177 static void
5178f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5179{
5180 return_register(reg_recording, rettv);
5181}
5182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005183#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005184/*
5185 * Convert a List to proftime_T.
5186 * Return FAIL when there is something wrong.
5187 */
5188 static int
5189list2proftime(typval_T *arg, proftime_T *tm)
5190{
5191 long n1, n2;
5192 int error = FALSE;
5193
5194 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5195 || arg->vval.v_list->lv_len != 2)
5196 return FAIL;
5197 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5198 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005199# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005200 tm->HighPart = n1;
5201 tm->LowPart = n2;
5202# else
5203 tm->tv_sec = n1;
5204 tm->tv_usec = n2;
5205# endif
5206 return error ? FAIL : OK;
5207}
5208#endif /* FEAT_RELTIME */
5209
5210/*
5211 * "reltime()" function
5212 */
5213 static void
5214f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5215{
5216#ifdef FEAT_RELTIME
5217 proftime_T res;
5218 proftime_T start;
5219
5220 if (argvars[0].v_type == VAR_UNKNOWN)
5221 {
5222 /* No arguments: get current time. */
5223 profile_start(&res);
5224 }
5225 else if (argvars[1].v_type == VAR_UNKNOWN)
5226 {
5227 if (list2proftime(&argvars[0], &res) == FAIL)
5228 return;
5229 profile_end(&res);
5230 }
5231 else
5232 {
5233 /* Two arguments: compute the difference. */
5234 if (list2proftime(&argvars[0], &start) == FAIL
5235 || list2proftime(&argvars[1], &res) == FAIL)
5236 return;
5237 profile_sub(&res, &start);
5238 }
5239
5240 if (rettv_list_alloc(rettv) == OK)
5241 {
5242 long n1, n2;
5243
Bram Moolenaar4f974752019-02-17 17:44:42 +01005244# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005245 n1 = res.HighPart;
5246 n2 = res.LowPart;
5247# else
5248 n1 = res.tv_sec;
5249 n2 = res.tv_usec;
5250# endif
5251 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5252 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5253 }
5254#endif
5255}
5256
5257#ifdef FEAT_FLOAT
5258/*
5259 * "reltimefloat()" function
5260 */
5261 static void
5262f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5263{
5264# ifdef FEAT_RELTIME
5265 proftime_T tm;
5266# endif
5267
5268 rettv->v_type = VAR_FLOAT;
5269 rettv->vval.v_float = 0;
5270# ifdef FEAT_RELTIME
5271 if (list2proftime(&argvars[0], &tm) == OK)
5272 rettv->vval.v_float = profile_float(&tm);
5273# endif
5274}
5275#endif
5276
5277/*
5278 * "reltimestr()" function
5279 */
5280 static void
5281f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5282{
5283#ifdef FEAT_RELTIME
5284 proftime_T tm;
5285#endif
5286
5287 rettv->v_type = VAR_STRING;
5288 rettv->vval.v_string = NULL;
5289#ifdef FEAT_RELTIME
5290 if (list2proftime(&argvars[0], &tm) == OK)
5291 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5292#endif
5293}
5294
5295#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296 static void
5297make_connection(void)
5298{
5299 if (X_DISPLAY == NULL
5300# ifdef FEAT_GUI
5301 && !gui.in_use
5302# endif
5303 )
5304 {
5305 x_force_connect = TRUE;
5306 setup_term_clip();
5307 x_force_connect = FALSE;
5308 }
5309}
5310
5311 static int
5312check_connection(void)
5313{
5314 make_connection();
5315 if (X_DISPLAY == NULL)
5316 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005317 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005318 return FAIL;
5319 }
5320 return OK;
5321}
5322#endif
5323
5324#ifdef FEAT_CLIENTSERVER
5325 static void
5326remote_common(typval_T *argvars, typval_T *rettv, int expr)
5327{
5328 char_u *server_name;
5329 char_u *keys;
5330 char_u *r = NULL;
5331 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005332 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005333# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005334 HWND w;
5335# else
5336 Window w;
5337# endif
5338
5339 if (check_restricted() || check_secure())
5340 return;
5341
5342# ifdef FEAT_X11
5343 if (check_connection() == FAIL)
5344 return;
5345# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005346 if (argvars[2].v_type != VAR_UNKNOWN
5347 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005348 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005349
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005350 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005351 if (server_name == NULL)
5352 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005353 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005354# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005355 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005356# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005357 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5358 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005359# endif
5360 {
5361 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005362 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005363 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005364 vim_free(r);
5365 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005366 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005367 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005368 return;
5369 }
5370
5371 rettv->vval.v_string = r;
5372
5373 if (argvars[2].v_type != VAR_UNKNOWN)
5374 {
5375 dictitem_T v;
5376 char_u str[30];
5377 char_u *idvar;
5378
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005379 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005380 if (idvar != NULL && *idvar != NUL)
5381 {
5382 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5383 v.di_tv.v_type = VAR_STRING;
5384 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005385 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005386 vim_free(v.di_tv.vval.v_string);
5387 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005388 }
5389}
5390#endif
5391
5392/*
5393 * "remote_expr()" function
5394 */
5395 static void
5396f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5397{
5398 rettv->v_type = VAR_STRING;
5399 rettv->vval.v_string = NULL;
5400#ifdef FEAT_CLIENTSERVER
5401 remote_common(argvars, rettv, TRUE);
5402#endif
5403}
5404
5405/*
5406 * "remote_foreground()" function
5407 */
5408 static void
5409f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5410{
5411#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005412# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005413 /* On Win32 it's done in this application. */
5414 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005415 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005416
5417 if (server_name != NULL)
5418 serverForeground(server_name);
5419 }
5420# else
5421 /* Send a foreground() expression to the server. */
5422 argvars[1].v_type = VAR_STRING;
5423 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5424 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005425 rettv->v_type = VAR_STRING;
5426 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005427 remote_common(argvars, rettv, TRUE);
5428 vim_free(argvars[1].vval.v_string);
5429# endif
5430#endif
5431}
5432
5433 static void
5434f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5435{
5436#ifdef FEAT_CLIENTSERVER
5437 dictitem_T v;
5438 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005439# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005440 long_u n = 0;
5441# endif
5442 char_u *serverid;
5443
5444 if (check_restricted() || check_secure())
5445 {
5446 rettv->vval.v_number = -1;
5447 return;
5448 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005449 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005450 if (serverid == NULL)
5451 {
5452 rettv->vval.v_number = -1;
5453 return; /* type error; errmsg already given */
5454 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005455# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005456 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5457 if (n == 0)
5458 rettv->vval.v_number = -1;
5459 else
5460 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005461 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005462 rettv->vval.v_number = (s != NULL);
5463 }
5464# else
5465 if (check_connection() == FAIL)
5466 return;
5467
5468 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5469 serverStrToWin(serverid), &s);
5470# endif
5471
5472 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5473 {
5474 char_u *retvar;
5475
5476 v.di_tv.v_type = VAR_STRING;
5477 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005478 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005479 if (retvar != NULL)
5480 set_var(retvar, &v.di_tv, FALSE);
5481 vim_free(v.di_tv.vval.v_string);
5482 }
5483#else
5484 rettv->vval.v_number = -1;
5485#endif
5486}
5487
5488 static void
5489f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5490{
5491 char_u *r = NULL;
5492
5493#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005494 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005495
5496 if (serverid != NULL && !check_restricted() && !check_secure())
5497 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005498 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005499# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005500 /* The server's HWND is encoded in the 'id' parameter */
5501 long_u n = 0;
5502# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005503
5504 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005505 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005506
Bram Moolenaar4f974752019-02-17 17:44:42 +01005507# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005508 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5509 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005510 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005511 if (r == NULL)
5512# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005513 if (check_connection() == FAIL
5514 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5515 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005516# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005517 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005518 }
5519#endif
5520 rettv->v_type = VAR_STRING;
5521 rettv->vval.v_string = r;
5522}
5523
5524/*
5525 * "remote_send()" function
5526 */
5527 static void
5528f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5529{
5530 rettv->v_type = VAR_STRING;
5531 rettv->vval.v_string = NULL;
5532#ifdef FEAT_CLIENTSERVER
5533 remote_common(argvars, rettv, FALSE);
5534#endif
5535}
5536
5537/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005538 * "remote_startserver()" function
5539 */
5540 static void
5541f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5542{
5543#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005544 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005545
5546 if (server == NULL)
5547 return; /* type error; errmsg already given */
5548 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005549 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005550 else
5551 {
5552# ifdef FEAT_X11
5553 if (check_connection() == OK)
5554 serverRegisterName(X_DISPLAY, server);
5555# else
5556 serverSetName(server);
5557# endif
5558 }
5559#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005560 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005561#endif
5562}
5563
5564/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005565 * "rename({from}, {to})" function
5566 */
5567 static void
5568f_rename(typval_T *argvars, typval_T *rettv)
5569{
5570 char_u buf[NUMBUFLEN];
5571
5572 if (check_restricted() || check_secure())
5573 rettv->vval.v_number = -1;
5574 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005575 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5576 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005577}
5578
5579/*
5580 * "repeat()" function
5581 */
5582 static void
5583f_repeat(typval_T *argvars, typval_T *rettv)
5584{
5585 char_u *p;
5586 int n;
5587 int slen;
5588 int len;
5589 char_u *r;
5590 int i;
5591
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005592 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005593 if (argvars[0].v_type == VAR_LIST)
5594 {
5595 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5596 while (n-- > 0)
5597 if (list_extend(rettv->vval.v_list,
5598 argvars[0].vval.v_list, NULL) == FAIL)
5599 break;
5600 }
5601 else
5602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005603 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604 rettv->v_type = VAR_STRING;
5605 rettv->vval.v_string = NULL;
5606
5607 slen = (int)STRLEN(p);
5608 len = slen * n;
5609 if (len <= 0)
5610 return;
5611
5612 r = alloc(len + 1);
5613 if (r != NULL)
5614 {
5615 for (i = 0; i < n; i++)
5616 mch_memmove(r + i * slen, p, (size_t)slen);
5617 r[len] = NUL;
5618 }
5619
5620 rettv->vval.v_string = r;
5621 }
5622}
5623
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005624#define SP_NOMOVE 0x01 /* don't move cursor */
5625#define SP_REPEAT 0x02 /* repeat to find outer pair */
5626#define SP_RETCOUNT 0x04 /* return matchcount */
5627#define SP_SETPCMARK 0x08 /* set previous context mark */
5628#define SP_START 0x10 /* accept match at start position */
5629#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5630#define SP_END 0x40 /* leave cursor at end of match */
5631#define SP_COLUMN 0x80 /* start at cursor column */
5632
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005633/*
5634 * Get flags for a search function.
5635 * Possibly sets "p_ws".
5636 * Returns BACKWARD, FORWARD or zero (for an error).
5637 */
5638 static int
5639get_search_arg(typval_T *varp, int *flagsp)
5640{
5641 int dir = FORWARD;
5642 char_u *flags;
5643 char_u nbuf[NUMBUFLEN];
5644 int mask;
5645
5646 if (varp->v_type != VAR_UNKNOWN)
5647 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005648 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005649 if (flags == NULL)
5650 return 0; /* type error; errmsg already given */
5651 while (*flags != NUL)
5652 {
5653 switch (*flags)
5654 {
5655 case 'b': dir = BACKWARD; break;
5656 case 'w': p_ws = TRUE; break;
5657 case 'W': p_ws = FALSE; break;
5658 default: mask = 0;
5659 if (flagsp != NULL)
5660 switch (*flags)
5661 {
5662 case 'c': mask = SP_START; break;
5663 case 'e': mask = SP_END; break;
5664 case 'm': mask = SP_RETCOUNT; break;
5665 case 'n': mask = SP_NOMOVE; break;
5666 case 'p': mask = SP_SUBPAT; break;
5667 case 'r': mask = SP_REPEAT; break;
5668 case 's': mask = SP_SETPCMARK; break;
5669 case 'z': mask = SP_COLUMN; break;
5670 }
5671 if (mask == 0)
5672 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005673 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005674 dir = 0;
5675 }
5676 else
5677 *flagsp |= mask;
5678 }
5679 if (dir == 0)
5680 break;
5681 ++flags;
5682 }
5683 }
5684 return dir;
5685}
5686
5687/*
5688 * Shared by search() and searchpos() functions.
5689 */
5690 static int
5691search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5692{
5693 int flags;
5694 char_u *pat;
5695 pos_T pos;
5696 pos_T save_cursor;
5697 int save_p_ws = p_ws;
5698 int dir;
5699 int retval = 0; /* default: FAIL */
5700 long lnum_stop = 0;
5701 proftime_T tm;
5702#ifdef FEAT_RELTIME
5703 long time_limit = 0;
5704#endif
5705 int options = SEARCH_KEEP;
5706 int subpatnum;
5707
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005708 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005709 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5710 if (dir == 0)
5711 goto theend;
5712 flags = *flagsp;
5713 if (flags & SP_START)
5714 options |= SEARCH_START;
5715 if (flags & SP_END)
5716 options |= SEARCH_END;
5717 if (flags & SP_COLUMN)
5718 options |= SEARCH_COL;
5719
5720 /* Optional arguments: line number to stop searching and timeout. */
5721 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5722 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005723 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005724 if (lnum_stop < 0)
5725 goto theend;
5726#ifdef FEAT_RELTIME
5727 if (argvars[3].v_type != VAR_UNKNOWN)
5728 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005729 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005730 if (time_limit < 0)
5731 goto theend;
5732 }
5733#endif
5734 }
5735
5736#ifdef FEAT_RELTIME
5737 /* Set the time limit, if there is one. */
5738 profile_setlimit(time_limit, &tm);
5739#endif
5740
5741 /*
5742 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5743 * Check to make sure only those flags are set.
5744 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5745 * flags cannot be set. Check for that condition also.
5746 */
5747 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5748 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5749 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005750 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005751 goto theend;
5752 }
5753
5754 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005755 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02005756 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005757 if (subpatnum != FAIL)
5758 {
5759 if (flags & SP_SUBPAT)
5760 retval = subpatnum;
5761 else
5762 retval = pos.lnum;
5763 if (flags & SP_SETPCMARK)
5764 setpcmark();
5765 curwin->w_cursor = pos;
5766 if (match_pos != NULL)
5767 {
5768 /* Store the match cursor position */
5769 match_pos->lnum = pos.lnum;
5770 match_pos->col = pos.col + 1;
5771 }
5772 /* "/$" will put the cursor after the end of the line, may need to
5773 * correct that here */
5774 check_cursor();
5775 }
5776
5777 /* If 'n' flag is used: restore cursor position. */
5778 if (flags & SP_NOMOVE)
5779 curwin->w_cursor = save_cursor;
5780 else
5781 curwin->w_set_curswant = TRUE;
5782theend:
5783 p_ws = save_p_ws;
5784
5785 return retval;
5786}
5787
5788#ifdef FEAT_FLOAT
5789
5790/*
5791 * round() is not in C90, use ceil() or floor() instead.
5792 */
5793 float_T
5794vim_round(float_T f)
5795{
5796 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
5797}
5798
5799/*
5800 * "round({float})" function
5801 */
5802 static void
5803f_round(typval_T *argvars, typval_T *rettv)
5804{
5805 float_T f = 0.0;
5806
5807 rettv->v_type = VAR_FLOAT;
5808 if (get_float_arg(argvars, &f) == OK)
5809 rettv->vval.v_float = vim_round(f);
5810 else
5811 rettv->vval.v_float = 0.0;
5812}
5813#endif
5814
Bram Moolenaare99be0e2019-03-26 22:51:09 +01005815#ifdef FEAT_RUBY
5816/*
5817 * "rubyeval()" function
5818 */
5819 static void
5820f_rubyeval(typval_T *argvars, typval_T *rettv)
5821{
5822 char_u *str;
5823 char_u buf[NUMBUFLEN];
5824
5825 str = tv_get_string_buf(&argvars[0], buf);
5826 do_rubyeval(str, rettv);
5827}
5828#endif
5829
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005830/*
5831 * "screenattr()" function
5832 */
5833 static void
5834f_screenattr(typval_T *argvars, typval_T *rettv)
5835{
5836 int row;
5837 int col;
5838 int c;
5839
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005840 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5841 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005842 if (row < 0 || row >= screen_Rows
5843 || col < 0 || col >= screen_Columns)
5844 c = -1;
5845 else
5846 c = ScreenAttrs[LineOffset[row] + col];
5847 rettv->vval.v_number = c;
5848}
5849
5850/*
5851 * "screenchar()" function
5852 */
5853 static void
5854f_screenchar(typval_T *argvars, typval_T *rettv)
5855{
5856 int row;
5857 int col;
5858 int off;
5859 int c;
5860
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005861 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5862 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005863 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005864 c = -1;
5865 else
5866 {
5867 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005868 if (enc_utf8 && ScreenLinesUC[off] != 0)
5869 c = ScreenLinesUC[off];
5870 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005871 c = ScreenLines[off];
5872 }
5873 rettv->vval.v_number = c;
5874}
5875
5876/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005877 * "screenchars()" function
5878 */
5879 static void
5880f_screenchars(typval_T *argvars, typval_T *rettv)
5881{
5882 int row;
5883 int col;
5884 int off;
5885 int c;
5886 int i;
5887
5888 if (rettv_list_alloc(rettv) == FAIL)
5889 return;
5890 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5891 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5892 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5893 return;
5894
5895 off = LineOffset[row] + col;
5896 if (enc_utf8 && ScreenLinesUC[off] != 0)
5897 c = ScreenLinesUC[off];
5898 else
5899 c = ScreenLines[off];
5900 list_append_number(rettv->vval.v_list, (varnumber_T)c);
5901
5902 if (enc_utf8)
5903
5904 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
5905 list_append_number(rettv->vval.v_list,
5906 (varnumber_T)ScreenLinesC[i][off]);
5907}
5908
5909/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005910 * "screencol()" function
5911 *
5912 * First column is 1 to be consistent with virtcol().
5913 */
5914 static void
5915f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
5916{
5917 rettv->vval.v_number = screen_screencol() + 1;
5918}
5919
5920/*
5921 * "screenrow()" function
5922 */
5923 static void
5924f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
5925{
5926 rettv->vval.v_number = screen_screenrow() + 1;
5927}
5928
5929/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01005930 * "screenstring()" function
5931 */
5932 static void
5933f_screenstring(typval_T *argvars, typval_T *rettv)
5934{
5935 int row;
5936 int col;
5937 int off;
5938 int c;
5939 int i;
5940 char_u buf[MB_MAXBYTES + 1];
5941 int buflen = 0;
5942
5943 rettv->vval.v_string = NULL;
5944 rettv->v_type = VAR_STRING;
5945
5946 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5947 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
5948 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
5949 return;
5950
5951 off = LineOffset[row] + col;
5952 if (enc_utf8 && ScreenLinesUC[off] != 0)
5953 c = ScreenLinesUC[off];
5954 else
5955 c = ScreenLines[off];
5956 buflen += mb_char2bytes(c, buf);
5957
5958 if (enc_utf8)
5959 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
5960 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
5961
5962 buf[buflen] = NUL;
5963 rettv->vval.v_string = vim_strsave(buf);
5964}
5965
5966/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005967 * "search()" function
5968 */
5969 static void
5970f_search(typval_T *argvars, typval_T *rettv)
5971{
5972 int flags = 0;
5973
5974 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
5975}
5976
5977/*
5978 * "searchdecl()" function
5979 */
5980 static void
5981f_searchdecl(typval_T *argvars, typval_T *rettv)
5982{
5983 int locally = 1;
5984 int thisblock = 0;
5985 int error = FALSE;
5986 char_u *name;
5987
5988 rettv->vval.v_number = 1; /* default: FAIL */
5989
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005990 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005991 if (argvars[1].v_type != VAR_UNKNOWN)
5992 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005993 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005994 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005995 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005996 }
5997 if (!error && name != NULL)
5998 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
5999 locally, thisblock, SEARCH_KEEP) == FAIL;
6000}
6001
6002/*
6003 * Used by searchpair() and searchpairpos()
6004 */
6005 static int
6006searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6007{
6008 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006009 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006010 int save_p_ws = p_ws;
6011 int dir;
6012 int flags = 0;
6013 char_u nbuf1[NUMBUFLEN];
6014 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006015 int retval = 0; /* default: FAIL */
6016 long lnum_stop = 0;
6017 long time_limit = 0;
6018
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006019 /* Get the three pattern arguments: start, middle, end. Will result in an
6020 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006021 spat = tv_get_string_chk(&argvars[0]);
6022 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6023 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006024 if (spat == NULL || mpat == NULL || epat == NULL)
6025 goto theend; /* type error */
6026
6027 /* Handle the optional fourth argument: flags */
6028 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6029 if (dir == 0)
6030 goto theend;
6031
6032 /* Don't accept SP_END or SP_SUBPAT.
6033 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6034 */
6035 if ((flags & (SP_END | SP_SUBPAT)) != 0
6036 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6037 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006038 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006039 goto theend;
6040 }
6041
6042 /* Using 'r' implies 'W', otherwise it doesn't work. */
6043 if (flags & SP_REPEAT)
6044 p_ws = FALSE;
6045
6046 /* Optional fifth argument: skip expression */
6047 if (argvars[3].v_type == VAR_UNKNOWN
6048 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006049 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006050 else
6051 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006052 skip = &argvars[4];
6053 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6054 && skip->v_type != VAR_STRING)
6055 {
6056 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006057 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006058 goto theend;
6059 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006060 if (argvars[5].v_type != VAR_UNKNOWN)
6061 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006062 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006064 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006065 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006066 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006067 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006068#ifdef FEAT_RELTIME
6069 if (argvars[6].v_type != VAR_UNKNOWN)
6070 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006071 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006072 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006073 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006074 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006075 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006076 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006077 }
6078#endif
6079 }
6080 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081
6082 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6083 match_pos, lnum_stop, time_limit);
6084
6085theend:
6086 p_ws = save_p_ws;
6087
6088 return retval;
6089}
6090
6091/*
6092 * "searchpair()" function
6093 */
6094 static void
6095f_searchpair(typval_T *argvars, typval_T *rettv)
6096{
6097 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6098}
6099
6100/*
6101 * "searchpairpos()" function
6102 */
6103 static void
6104f_searchpairpos(typval_T *argvars, typval_T *rettv)
6105{
6106 pos_T match_pos;
6107 int lnum = 0;
6108 int col = 0;
6109
6110 if (rettv_list_alloc(rettv) == FAIL)
6111 return;
6112
6113 if (searchpair_cmn(argvars, &match_pos) > 0)
6114 {
6115 lnum = match_pos.lnum;
6116 col = match_pos.col;
6117 }
6118
6119 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6120 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6121}
6122
6123/*
6124 * Search for a start/middle/end thing.
6125 * Used by searchpair(), see its documentation for the details.
6126 * Returns 0 or -1 for no match,
6127 */
6128 long
6129do_searchpair(
6130 char_u *spat, /* start pattern */
6131 char_u *mpat, /* middle pattern */
6132 char_u *epat, /* end pattern */
6133 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006134 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006135 int flags, /* SP_SETPCMARK and other SP_ values */
6136 pos_T *match_pos,
6137 linenr_T lnum_stop, /* stop at this line if not zero */
6138 long time_limit UNUSED) /* stop after this many msec */
6139{
6140 char_u *save_cpo;
6141 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6142 long retval = 0;
6143 pos_T pos;
6144 pos_T firstpos;
6145 pos_T foundpos;
6146 pos_T save_cursor;
6147 pos_T save_pos;
6148 int n;
6149 int r;
6150 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006151 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006152 int err;
6153 int options = SEARCH_KEEP;
6154 proftime_T tm;
6155
6156 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6157 save_cpo = p_cpo;
6158 p_cpo = empty_option;
6159
6160#ifdef FEAT_RELTIME
6161 /* Set the time limit, if there is one. */
6162 profile_setlimit(time_limit, &tm);
6163#endif
6164
6165 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6166 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006167 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6168 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006169 if (pat2 == NULL || pat3 == NULL)
6170 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006171 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006172 if (*mpat == NUL)
6173 STRCPY(pat3, pat2);
6174 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006175 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006176 spat, epat, mpat);
6177 if (flags & SP_START)
6178 options |= SEARCH_START;
6179
Bram Moolenaar48570482017-10-30 21:48:41 +01006180 if (skip != NULL)
6181 {
6182 /* Empty string means to not use the skip expression. */
6183 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6184 use_skip = skip->vval.v_string != NULL
6185 && *skip->vval.v_string != NUL;
6186 }
6187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188 save_cursor = curwin->w_cursor;
6189 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006190 CLEAR_POS(&firstpos);
6191 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006192 pat = pat3;
6193 for (;;)
6194 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006195 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006196 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006197 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006198 /* didn't find it or found the first match again: FAIL */
6199 break;
6200
6201 if (firstpos.lnum == 0)
6202 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006203 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006204 {
6205 /* Found the same position again. Can happen with a pattern that
6206 * has "\zs" at the end and searching backwards. Advance one
6207 * character and try again. */
6208 if (dir == BACKWARD)
6209 decl(&pos);
6210 else
6211 incl(&pos);
6212 }
6213 foundpos = pos;
6214
6215 /* clear the start flag to avoid getting stuck here */
6216 options &= ~SEARCH_START;
6217
6218 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006219 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006220 {
6221 save_pos = curwin->w_cursor;
6222 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006223 err = FALSE;
6224 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006225 curwin->w_cursor = save_pos;
6226 if (err)
6227 {
6228 /* Evaluating {skip} caused an error, break here. */
6229 curwin->w_cursor = save_cursor;
6230 retval = -1;
6231 break;
6232 }
6233 if (r)
6234 continue;
6235 }
6236
6237 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6238 {
6239 /* Found end when searching backwards or start when searching
6240 * forward: nested pair. */
6241 ++nest;
6242 pat = pat2; /* nested, don't search for middle */
6243 }
6244 else
6245 {
6246 /* Found end when searching forward or start when searching
6247 * backward: end of (nested) pair; or found middle in outer pair. */
6248 if (--nest == 1)
6249 pat = pat3; /* outer level, search for middle */
6250 }
6251
6252 if (nest == 0)
6253 {
6254 /* Found the match: return matchcount or line number. */
6255 if (flags & SP_RETCOUNT)
6256 ++retval;
6257 else
6258 retval = pos.lnum;
6259 if (flags & SP_SETPCMARK)
6260 setpcmark();
6261 curwin->w_cursor = pos;
6262 if (!(flags & SP_REPEAT))
6263 break;
6264 nest = 1; /* search for next unmatched */
6265 }
6266 }
6267
6268 if (match_pos != NULL)
6269 {
6270 /* Store the match cursor position */
6271 match_pos->lnum = curwin->w_cursor.lnum;
6272 match_pos->col = curwin->w_cursor.col + 1;
6273 }
6274
6275 /* If 'n' flag is used or search failed: restore cursor position. */
6276 if ((flags & SP_NOMOVE) || retval == 0)
6277 curwin->w_cursor = save_cursor;
6278
6279theend:
6280 vim_free(pat2);
6281 vim_free(pat3);
6282 if (p_cpo == empty_option)
6283 p_cpo = save_cpo;
6284 else
6285 /* Darn, evaluating the {skip} expression changed the value. */
6286 free_string_option(save_cpo);
6287
6288 return retval;
6289}
6290
6291/*
6292 * "searchpos()" function
6293 */
6294 static void
6295f_searchpos(typval_T *argvars, typval_T *rettv)
6296{
6297 pos_T match_pos;
6298 int lnum = 0;
6299 int col = 0;
6300 int n;
6301 int flags = 0;
6302
6303 if (rettv_list_alloc(rettv) == FAIL)
6304 return;
6305
6306 n = search_cmn(argvars, &match_pos, &flags);
6307 if (n > 0)
6308 {
6309 lnum = match_pos.lnum;
6310 col = match_pos.col;
6311 }
6312
6313 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6314 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6315 if (flags & SP_SUBPAT)
6316 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6317}
6318
6319 static void
6320f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6321{
6322#ifdef FEAT_CLIENTSERVER
6323 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006324 char_u *server = tv_get_string_chk(&argvars[0]);
6325 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006326
6327 rettv->vval.v_number = -1;
6328 if (server == NULL || reply == NULL)
6329 return;
6330 if (check_restricted() || check_secure())
6331 return;
6332# ifdef FEAT_X11
6333 if (check_connection() == FAIL)
6334 return;
6335# endif
6336
6337 if (serverSendReply(server, reply) < 0)
6338 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006339 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006340 return;
6341 }
6342 rettv->vval.v_number = 0;
6343#else
6344 rettv->vval.v_number = -1;
6345#endif
6346}
6347
6348 static void
6349f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6350{
6351 char_u *r = NULL;
6352
6353#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006354# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006355 r = serverGetVimNames();
6356# else
6357 make_connection();
6358 if (X_DISPLAY != NULL)
6359 r = serverGetVimNames(X_DISPLAY);
6360# endif
6361#endif
6362 rettv->v_type = VAR_STRING;
6363 rettv->vval.v_string = r;
6364}
6365
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006366 static void
6367f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6368{
6369 dict_T *d;
6370 dictitem_T *di;
6371 char_u *csearch;
6372
6373 if (argvars[0].v_type != VAR_DICT)
6374 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006375 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006376 return;
6377 }
6378
6379 if ((d = argvars[0].vval.v_dict) != NULL)
6380 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006381 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006382 if (csearch != NULL)
6383 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006384 if (enc_utf8)
6385 {
6386 int pcc[MAX_MCO];
6387 int c = utfc_ptr2char(csearch, pcc);
6388
6389 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6390 }
6391 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006392 set_last_csearch(PTR2CHAR(csearch),
Bram Moolenaar1614a142019-10-06 22:00:13 +02006393 csearch, mb_ptr2len(csearch));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006394 }
6395
6396 di = dict_find(d, (char_u *)"forward", -1);
6397 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006398 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006399 ? FORWARD : BACKWARD);
6400
6401 di = dict_find(d, (char_u *)"until", -1);
6402 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006403 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006404 }
6405}
6406
6407/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006408 * "setenv()" function
6409 */
6410 static void
6411f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6412{
6413 char_u namebuf[NUMBUFLEN];
6414 char_u valbuf[NUMBUFLEN];
6415 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6416
6417 if (argvars[1].v_type == VAR_SPECIAL
6418 && argvars[1].vval.v_number == VVAL_NULL)
6419 vim_unsetenv(name);
6420 else
6421 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6422}
6423
6424/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006425 * "setfperm({fname}, {mode})" function
6426 */
6427 static void
6428f_setfperm(typval_T *argvars, typval_T *rettv)
6429{
6430 char_u *fname;
6431 char_u modebuf[NUMBUFLEN];
6432 char_u *mode_str;
6433 int i;
6434 int mask;
6435 int mode = 0;
6436
6437 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006438 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006439 if (fname == NULL)
6440 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006441 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006442 if (mode_str == NULL)
6443 return;
6444 if (STRLEN(mode_str) != 9)
6445 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006446 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006447 return;
6448 }
6449
6450 mask = 1;
6451 for (i = 8; i >= 0; --i)
6452 {
6453 if (mode_str[i] != '-')
6454 mode |= mask;
6455 mask = mask << 1;
6456 }
6457 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6458}
6459
6460/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006461 * "setpos()" function
6462 */
6463 static void
6464f_setpos(typval_T *argvars, typval_T *rettv)
6465{
6466 pos_T pos;
6467 int fnum;
6468 char_u *name;
6469 colnr_T curswant = -1;
6470
6471 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006472 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006473 if (name != NULL)
6474 {
6475 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6476 {
6477 if (--pos.col < 0)
6478 pos.col = 0;
6479 if (name[0] == '.' && name[1] == NUL)
6480 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006481 /* set cursor; "fnum" is ignored */
6482 curwin->w_cursor = pos;
6483 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006485 curwin->w_curswant = curswant - 1;
6486 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006487 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006488 check_cursor();
6489 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006490 }
6491 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6492 {
6493 /* set mark */
6494 if (setmark_pos(name[1], &pos, fnum) == OK)
6495 rettv->vval.v_number = 0;
6496 }
6497 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006498 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006499 }
6500 }
6501}
6502
6503/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504 * "setreg()" function
6505 */
6506 static void
6507f_setreg(typval_T *argvars, typval_T *rettv)
6508{
6509 int regname;
6510 char_u *strregname;
6511 char_u *stropt;
6512 char_u *strval;
6513 int append;
6514 char_u yank_type;
6515 long block_len;
6516
6517 block_len = -1;
6518 yank_type = MAUTO;
6519 append = FALSE;
6520
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006521 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006522 rettv->vval.v_number = 1; /* FAIL is default */
6523
6524 if (strregname == NULL)
6525 return; /* type error; errmsg already given */
6526 regname = *strregname;
6527 if (regname == 0 || regname == '@')
6528 regname = '"';
6529
6530 if (argvars[2].v_type != VAR_UNKNOWN)
6531 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006532 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006533 if (stropt == NULL)
6534 return; /* type error */
6535 for (; *stropt != NUL; ++stropt)
6536 switch (*stropt)
6537 {
6538 case 'a': case 'A': /* append */
6539 append = TRUE;
6540 break;
6541 case 'v': case 'c': /* character-wise selection */
6542 yank_type = MCHAR;
6543 break;
6544 case 'V': case 'l': /* line-wise selection */
6545 yank_type = MLINE;
6546 break;
6547 case 'b': case Ctrl_V: /* block-wise selection */
6548 yank_type = MBLOCK;
6549 if (VIM_ISDIGIT(stropt[1]))
6550 {
6551 ++stropt;
6552 block_len = getdigits(&stropt) - 1;
6553 --stropt;
6554 }
6555 break;
6556 }
6557 }
6558
6559 if (argvars[1].v_type == VAR_LIST)
6560 {
6561 char_u **lstval;
6562 char_u **allocval;
6563 char_u buf[NUMBUFLEN];
6564 char_u **curval;
6565 char_u **curallocval;
6566 list_T *ll = argvars[1].vval.v_list;
6567 listitem_T *li;
6568 int len;
6569
6570 /* If the list is NULL handle like an empty list. */
6571 len = ll == NULL ? 0 : ll->lv_len;
6572
6573 /* First half: use for pointers to result lines; second half: use for
6574 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006575 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006576 if (lstval == NULL)
6577 return;
6578 curval = lstval;
6579 allocval = lstval + len + 2;
6580 curallocval = allocval;
6581
6582 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6583 li = li->li_next)
6584 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006585 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006586 if (strval == NULL)
6587 goto free_lstval;
6588 if (strval == buf)
6589 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006590 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006591 * overwrite the string. */
6592 strval = vim_strsave(buf);
6593 if (strval == NULL)
6594 goto free_lstval;
6595 *curallocval++ = strval;
6596 }
6597 *curval++ = strval;
6598 }
6599 *curval++ = NULL;
6600
6601 write_reg_contents_lst(regname, lstval, -1,
6602 append, yank_type, block_len);
6603free_lstval:
6604 while (curallocval > allocval)
6605 vim_free(*--curallocval);
6606 vim_free(lstval);
6607 }
6608 else
6609 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006610 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006611 if (strval == NULL)
6612 return;
6613 write_reg_contents_ex(regname, strval, -1,
6614 append, yank_type, block_len);
6615 }
6616 rettv->vval.v_number = 0;
6617}
6618
6619/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006620 * "settagstack()" function
6621 */
6622 static void
6623f_settagstack(typval_T *argvars, typval_T *rettv)
6624{
6625 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6626 win_T *wp;
6627 dict_T *d;
6628 int action = 'r';
6629
6630 rettv->vval.v_number = -1;
6631
6632 // first argument: window number or id
6633 wp = find_win_by_nr_or_id(&argvars[0]);
6634 if (wp == NULL)
6635 return;
6636
6637 // second argument: dict with items to set in the tag stack
6638 if (argvars[1].v_type != VAR_DICT)
6639 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006640 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006641 return;
6642 }
6643 d = argvars[1].vval.v_dict;
6644 if (d == NULL)
6645 return;
6646
6647 // third argument: action - 'a' for append and 'r' for replace.
6648 // default is to replace the stack.
6649 if (argvars[2].v_type == VAR_UNKNOWN)
6650 action = 'r';
6651 else if (argvars[2].v_type == VAR_STRING)
6652 {
6653 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006654 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006655 if (actstr == NULL)
6656 return;
6657 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6658 action = *actstr;
6659 else
6660 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006661 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006662 return;
6663 }
6664 }
6665 else
6666 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006667 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006668 return;
6669 }
6670
6671 if (set_tagstack(wp, d, action) == OK)
6672 rettv->vval.v_number = 0;
6673}
6674
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006675#ifdef FEAT_CRYPT
6676/*
6677 * "sha256({string})" function
6678 */
6679 static void
6680f_sha256(typval_T *argvars, typval_T *rettv)
6681{
6682 char_u *p;
6683
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006684 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006685 rettv->vval.v_string = vim_strsave(
6686 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6687 rettv->v_type = VAR_STRING;
6688}
6689#endif /* FEAT_CRYPT */
6690
6691/*
6692 * "shellescape({string})" function
6693 */
6694 static void
6695f_shellescape(typval_T *argvars, typval_T *rettv)
6696{
Bram Moolenaar20615522017-06-05 18:46:26 +02006697 int do_special = non_zero_arg(&argvars[1]);
6698
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006699 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006700 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 rettv->v_type = VAR_STRING;
6702}
6703
6704/*
6705 * shiftwidth() function
6706 */
6707 static void
6708f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6709{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006710 rettv->vval.v_number = 0;
6711
6712 if (argvars[0].v_type != VAR_UNKNOWN)
6713 {
6714 long col;
6715
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006716 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006717 if (col < 0)
6718 return; // type error; errmsg already given
6719#ifdef FEAT_VARTABS
6720 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6721 return;
6722#endif
6723 }
6724
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006725 rettv->vval.v_number = get_sw_value(curbuf);
6726}
6727
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006728#ifdef FEAT_FLOAT
6729/*
6730 * "sin()" function
6731 */
6732 static void
6733f_sin(typval_T *argvars, typval_T *rettv)
6734{
6735 float_T f = 0.0;
6736
6737 rettv->v_type = VAR_FLOAT;
6738 if (get_float_arg(argvars, &f) == OK)
6739 rettv->vval.v_float = sin(f);
6740 else
6741 rettv->vval.v_float = 0.0;
6742}
6743
6744/*
6745 * "sinh()" function
6746 */
6747 static void
6748f_sinh(typval_T *argvars, typval_T *rettv)
6749{
6750 float_T f = 0.0;
6751
6752 rettv->v_type = VAR_FLOAT;
6753 if (get_float_arg(argvars, &f) == OK)
6754 rettv->vval.v_float = sinh(f);
6755 else
6756 rettv->vval.v_float = 0.0;
6757}
6758#endif
6759
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006760/*
6761 * "soundfold({word})" function
6762 */
6763 static void
6764f_soundfold(typval_T *argvars, typval_T *rettv)
6765{
6766 char_u *s;
6767
6768 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006769 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006770#ifdef FEAT_SPELL
6771 rettv->vval.v_string = eval_soundfold(s);
6772#else
6773 rettv->vval.v_string = vim_strsave(s);
6774#endif
6775}
6776
6777/*
6778 * "spellbadword()" function
6779 */
6780 static void
6781f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6782{
6783 char_u *word = (char_u *)"";
6784 hlf_T attr = HLF_COUNT;
6785 int len = 0;
6786
6787 if (rettv_list_alloc(rettv) == FAIL)
6788 return;
6789
6790#ifdef FEAT_SPELL
6791 if (argvars[0].v_type == VAR_UNKNOWN)
6792 {
6793 /* Find the start and length of the badly spelled word. */
6794 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
6795 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006796 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006797 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006798 curwin->w_set_curswant = TRUE;
6799 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006800 }
6801 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
6802 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006803 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804 int capcol = -1;
6805
6806 if (str != NULL)
6807 {
6808 /* Check the argument for spelling. */
6809 while (*str != NUL)
6810 {
6811 len = spell_check(curwin, str, &attr, &capcol, FALSE);
6812 if (attr != HLF_COUNT)
6813 {
6814 word = str;
6815 break;
6816 }
6817 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02006818 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02006819 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006820 }
6821 }
6822 }
6823#endif
6824
6825 list_append_string(rettv->vval.v_list, word, len);
6826 list_append_string(rettv->vval.v_list, (char_u *)(
6827 attr == HLF_SPB ? "bad" :
6828 attr == HLF_SPR ? "rare" :
6829 attr == HLF_SPL ? "local" :
6830 attr == HLF_SPC ? "caps" :
6831 ""), -1);
6832}
6833
6834/*
6835 * "spellsuggest()" function
6836 */
6837 static void
6838f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
6839{
6840#ifdef FEAT_SPELL
6841 char_u *str;
6842 int typeerr = FALSE;
6843 int maxcount;
6844 garray_T ga;
6845 int i;
6846 listitem_T *li;
6847 int need_capital = FALSE;
6848#endif
6849
6850 if (rettv_list_alloc(rettv) == FAIL)
6851 return;
6852
6853#ifdef FEAT_SPELL
6854 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
6855 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006856 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006857 if (argvars[1].v_type != VAR_UNKNOWN)
6858 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006859 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006860 if (maxcount <= 0)
6861 return;
6862 if (argvars[2].v_type != VAR_UNKNOWN)
6863 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006864 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006865 if (typeerr)
6866 return;
6867 }
6868 }
6869 else
6870 maxcount = 25;
6871
6872 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
6873
6874 for (i = 0; i < ga.ga_len; ++i)
6875 {
6876 str = ((char_u **)ga.ga_data)[i];
6877
6878 li = listitem_alloc();
6879 if (li == NULL)
6880 vim_free(str);
6881 else
6882 {
6883 li->li_tv.v_type = VAR_STRING;
6884 li->li_tv.v_lock = 0;
6885 li->li_tv.vval.v_string = str;
6886 list_append(rettv->vval.v_list, li);
6887 }
6888 }
6889 ga_clear(&ga);
6890 }
6891#endif
6892}
6893
6894 static void
6895f_split(typval_T *argvars, typval_T *rettv)
6896{
6897 char_u *str;
6898 char_u *end;
6899 char_u *pat = NULL;
6900 regmatch_T regmatch;
6901 char_u patbuf[NUMBUFLEN];
6902 char_u *save_cpo;
6903 int match;
6904 colnr_T col = 0;
6905 int keepempty = FALSE;
6906 int typeerr = FALSE;
6907
6908 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6909 save_cpo = p_cpo;
6910 p_cpo = (char_u *)"";
6911
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006912 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006913 if (argvars[1].v_type != VAR_UNKNOWN)
6914 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006915 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006916 if (pat == NULL)
6917 typeerr = TRUE;
6918 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006919 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006920 }
6921 if (pat == NULL || *pat == NUL)
6922 pat = (char_u *)"[\\x01- ]\\+";
6923
6924 if (rettv_list_alloc(rettv) == FAIL)
6925 return;
6926 if (typeerr)
6927 return;
6928
6929 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6930 if (regmatch.regprog != NULL)
6931 {
6932 regmatch.rm_ic = FALSE;
6933 while (*str != NUL || keepempty)
6934 {
6935 if (*str == NUL)
6936 match = FALSE; /* empty item at the end */
6937 else
6938 match = vim_regexec_nl(&regmatch, str, col);
6939 if (match)
6940 end = regmatch.startp[0];
6941 else
6942 end = str + STRLEN(str);
6943 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
6944 && *str != NUL && match && end < regmatch.endp[0]))
6945 {
6946 if (list_append_string(rettv->vval.v_list, str,
6947 (int)(end - str)) == FAIL)
6948 break;
6949 }
6950 if (!match)
6951 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01006952 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006953 if (regmatch.endp[0] > str)
6954 col = 0;
6955 else
Bram Moolenaar13505972019-01-24 15:04:48 +01006956 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006957 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006958 str = regmatch.endp[0];
6959 }
6960
6961 vim_regfree(regmatch.regprog);
6962 }
6963
6964 p_cpo = save_cpo;
6965}
6966
6967#ifdef FEAT_FLOAT
6968/*
6969 * "sqrt()" function
6970 */
6971 static void
6972f_sqrt(typval_T *argvars, typval_T *rettv)
6973{
6974 float_T f = 0.0;
6975
6976 rettv->v_type = VAR_FLOAT;
6977 if (get_float_arg(argvars, &f) == OK)
6978 rettv->vval.v_float = sqrt(f);
6979 else
6980 rettv->vval.v_float = 0.0;
6981}
6982
6983/*
6984 * "str2float()" function
6985 */
6986 static void
6987f_str2float(typval_T *argvars, typval_T *rettv)
6988{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006989 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01006990 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991
Bram Moolenaar08243d22017-01-10 16:12:29 +01006992 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006993 p = skipwhite(p + 1);
6994 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01006995 if (isneg)
6996 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006997 rettv->v_type = VAR_FLOAT;
6998}
6999#endif
7000
7001/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007002 * "str2list()" function
7003 */
7004 static void
7005f_str2list(typval_T *argvars, typval_T *rettv)
7006{
7007 char_u *p;
7008 int utf8 = FALSE;
7009
7010 if (rettv_list_alloc(rettv) == FAIL)
7011 return;
7012
7013 if (argvars[1].v_type != VAR_UNKNOWN)
7014 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7015
7016 p = tv_get_string(&argvars[0]);
7017
7018 if (has_mbyte || utf8)
7019 {
7020 int (*ptr2len)(char_u *);
7021 int (*ptr2char)(char_u *);
7022
7023 if (utf8 || enc_utf8)
7024 {
7025 ptr2len = utf_ptr2len;
7026 ptr2char = utf_ptr2char;
7027 }
7028 else
7029 {
7030 ptr2len = mb_ptr2len;
7031 ptr2char = mb_ptr2char;
7032 }
7033
7034 for ( ; *p != NUL; p += (*ptr2len)(p))
7035 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7036 }
7037 else
7038 for ( ; *p != NUL; ++p)
7039 list_append_number(rettv->vval.v_list, *p);
7040}
7041
7042/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007043 * "str2nr()" function
7044 */
7045 static void
7046f_str2nr(typval_T *argvars, typval_T *rettv)
7047{
7048 int base = 10;
7049 char_u *p;
7050 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007051 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007052 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007053
7054 if (argvars[1].v_type != VAR_UNKNOWN)
7055 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007056 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007057 if (base != 2 && base != 8 && base != 10 && base != 16)
7058 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007059 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007060 return;
7061 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007062 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7063 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007064 }
7065
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007066 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007067 isneg = (*p == '-');
7068 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069 p = skipwhite(p + 1);
7070 switch (base)
7071 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007072 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7073 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7074 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007076 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7077 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007078 if (isneg)
7079 rettv->vval.v_number = -n;
7080 else
7081 rettv->vval.v_number = n;
7082
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007083}
7084
7085#ifdef HAVE_STRFTIME
7086/*
7087 * "strftime({format}[, {time}])" function
7088 */
7089 static void
7090f_strftime(typval_T *argvars, typval_T *rettv)
7091{
7092 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007093 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007094 struct tm *curtime;
7095 time_t seconds;
7096 char_u *p;
7097
7098 rettv->v_type = VAR_STRING;
7099
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007100 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007101 if (argvars[1].v_type == VAR_UNKNOWN)
7102 seconds = time(NULL);
7103 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007104 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007105 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007106 /* MSVC returns NULL for an invalid value of seconds. */
7107 if (curtime == NULL)
7108 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7109 else
7110 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007111 vimconv_T conv;
7112 char_u *enc;
7113
7114 conv.vc_type = CONV_NONE;
7115 enc = enc_locale();
7116 convert_setup(&conv, p_enc, enc);
7117 if (conv.vc_type != CONV_NONE)
7118 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007119 if (p != NULL)
7120 (void)strftime((char *)result_buf, sizeof(result_buf),
7121 (char *)p, curtime);
7122 else
7123 result_buf[0] = NUL;
7124
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007125 if (conv.vc_type != CONV_NONE)
7126 vim_free(p);
7127 convert_setup(&conv, enc, p_enc);
7128 if (conv.vc_type != CONV_NONE)
7129 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7130 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007131 rettv->vval.v_string = vim_strsave(result_buf);
7132
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007133 /* Release conversion descriptors */
7134 convert_setup(&conv, NULL, NULL);
7135 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007136 }
7137}
7138#endif
7139
7140/*
7141 * "strgetchar()" function
7142 */
7143 static void
7144f_strgetchar(typval_T *argvars, typval_T *rettv)
7145{
7146 char_u *str;
7147 int len;
7148 int error = FALSE;
7149 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007150 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007151
7152 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007153 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007154 if (str == NULL)
7155 return;
7156 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007157 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007158 if (error)
7159 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007160
Bram Moolenaar13505972019-01-24 15:04:48 +01007161 while (charidx >= 0 && byteidx < len)
7162 {
7163 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007164 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007165 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7166 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007167 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007168 --charidx;
7169 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007170 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007171}
7172
7173/*
7174 * "stridx()" function
7175 */
7176 static void
7177f_stridx(typval_T *argvars, typval_T *rettv)
7178{
7179 char_u buf[NUMBUFLEN];
7180 char_u *needle;
7181 char_u *haystack;
7182 char_u *save_haystack;
7183 char_u *pos;
7184 int start_idx;
7185
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007186 needle = tv_get_string_chk(&argvars[1]);
7187 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007188 rettv->vval.v_number = -1;
7189 if (needle == NULL || haystack == NULL)
7190 return; /* type error; errmsg already given */
7191
7192 if (argvars[2].v_type != VAR_UNKNOWN)
7193 {
7194 int error = FALSE;
7195
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007196 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007197 if (error || start_idx >= (int)STRLEN(haystack))
7198 return;
7199 if (start_idx >= 0)
7200 haystack += start_idx;
7201 }
7202
7203 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7204 if (pos != NULL)
7205 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7206}
7207
7208/*
7209 * "string()" function
7210 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007211 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007212f_string(typval_T *argvars, typval_T *rettv)
7213{
7214 char_u *tofree;
7215 char_u numbuf[NUMBUFLEN];
7216
7217 rettv->v_type = VAR_STRING;
7218 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7219 get_copyID());
7220 /* Make a copy if we have a value but it's not in allocated memory. */
7221 if (rettv->vval.v_string != NULL && tofree == NULL)
7222 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7223}
7224
7225/*
7226 * "strlen()" function
7227 */
7228 static void
7229f_strlen(typval_T *argvars, typval_T *rettv)
7230{
7231 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007232 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233}
7234
7235/*
7236 * "strchars()" function
7237 */
7238 static void
7239f_strchars(typval_T *argvars, typval_T *rettv)
7240{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007241 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007242 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007243 varnumber_T len = 0;
7244 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007245
7246 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007247 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007248 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007249 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007250 else
7251 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007252 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7253 while (*s != NUL)
7254 {
7255 func_mb_ptr2char_adv(&s);
7256 ++len;
7257 }
7258 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007259 }
7260}
7261
7262/*
7263 * "strdisplaywidth()" function
7264 */
7265 static void
7266f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7267{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007268 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007269 int col = 0;
7270
7271 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007272 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007273
7274 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7275}
7276
7277/*
7278 * "strwidth()" function
7279 */
7280 static void
7281f_strwidth(typval_T *argvars, typval_T *rettv)
7282{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007283 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007284
Bram Moolenaar13505972019-01-24 15:04:48 +01007285 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007286}
7287
7288/*
7289 * "strcharpart()" function
7290 */
7291 static void
7292f_strcharpart(typval_T *argvars, typval_T *rettv)
7293{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007294 char_u *p;
7295 int nchar;
7296 int nbyte = 0;
7297 int charlen;
7298 int len = 0;
7299 int slen;
7300 int error = FALSE;
7301
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007302 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007303 slen = (int)STRLEN(p);
7304
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007305 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007306 if (!error)
7307 {
7308 if (nchar > 0)
7309 while (nchar > 0 && nbyte < slen)
7310 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007311 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007312 --nchar;
7313 }
7314 else
7315 nbyte = nchar;
7316 if (argvars[2].v_type != VAR_UNKNOWN)
7317 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007318 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319 while (charlen > 0 && nbyte + len < slen)
7320 {
7321 int off = nbyte + len;
7322
7323 if (off < 0)
7324 len += 1;
7325 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007326 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007327 --charlen;
7328 }
7329 }
7330 else
7331 len = slen - nbyte; /* default: all bytes that are available. */
7332 }
7333
7334 /*
7335 * Only return the overlap between the specified part and the actual
7336 * string.
7337 */
7338 if (nbyte < 0)
7339 {
7340 len += nbyte;
7341 nbyte = 0;
7342 }
7343 else if (nbyte > slen)
7344 nbyte = slen;
7345 if (len < 0)
7346 len = 0;
7347 else if (nbyte + len > slen)
7348 len = slen - nbyte;
7349
7350 rettv->v_type = VAR_STRING;
7351 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007352}
7353
7354/*
7355 * "strpart()" function
7356 */
7357 static void
7358f_strpart(typval_T *argvars, typval_T *rettv)
7359{
7360 char_u *p;
7361 int n;
7362 int len;
7363 int slen;
7364 int error = FALSE;
7365
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007366 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007367 slen = (int)STRLEN(p);
7368
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007369 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007370 if (error)
7371 len = 0;
7372 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007373 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374 else
7375 len = slen - n; /* default len: all bytes that are available. */
7376
7377 /*
7378 * Only return the overlap between the specified part and the actual
7379 * string.
7380 */
7381 if (n < 0)
7382 {
7383 len += n;
7384 n = 0;
7385 }
7386 else if (n > slen)
7387 n = slen;
7388 if (len < 0)
7389 len = 0;
7390 else if (n + len > slen)
7391 len = slen - n;
7392
7393 rettv->v_type = VAR_STRING;
7394 rettv->vval.v_string = vim_strnsave(p + n, len);
7395}
7396
7397/*
7398 * "strridx()" function
7399 */
7400 static void
7401f_strridx(typval_T *argvars, typval_T *rettv)
7402{
7403 char_u buf[NUMBUFLEN];
7404 char_u *needle;
7405 char_u *haystack;
7406 char_u *rest;
7407 char_u *lastmatch = NULL;
7408 int haystack_len, end_idx;
7409
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007410 needle = tv_get_string_chk(&argvars[1]);
7411 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412
7413 rettv->vval.v_number = -1;
7414 if (needle == NULL || haystack == NULL)
7415 return; /* type error; errmsg already given */
7416
7417 haystack_len = (int)STRLEN(haystack);
7418 if (argvars[2].v_type != VAR_UNKNOWN)
7419 {
7420 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007421 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007422 if (end_idx < 0)
7423 return; /* can never find a match */
7424 }
7425 else
7426 end_idx = haystack_len;
7427
7428 if (*needle == NUL)
7429 {
7430 /* Empty string matches past the end. */
7431 lastmatch = haystack + end_idx;
7432 }
7433 else
7434 {
7435 for (rest = haystack; *rest != '\0'; ++rest)
7436 {
7437 rest = (char_u *)strstr((char *)rest, (char *)needle);
7438 if (rest == NULL || rest > haystack + end_idx)
7439 break;
7440 lastmatch = rest;
7441 }
7442 }
7443
7444 if (lastmatch == NULL)
7445 rettv->vval.v_number = -1;
7446 else
7447 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7448}
7449
7450/*
7451 * "strtrans()" function
7452 */
7453 static void
7454f_strtrans(typval_T *argvars, typval_T *rettv)
7455{
7456 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007457 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007458}
7459
7460/*
7461 * "submatch()" function
7462 */
7463 static void
7464f_submatch(typval_T *argvars, typval_T *rettv)
7465{
7466 int error = FALSE;
7467 int no;
7468 int retList = 0;
7469
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007470 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007471 if (error)
7472 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007473 if (no < 0 || no >= NSUBEXP)
7474 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007475 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007476 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007477 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007479 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007480 if (error)
7481 return;
7482
7483 if (retList == 0)
7484 {
7485 rettv->v_type = VAR_STRING;
7486 rettv->vval.v_string = reg_submatch(no);
7487 }
7488 else
7489 {
7490 rettv->v_type = VAR_LIST;
7491 rettv->vval.v_list = reg_submatch_list(no);
7492 }
7493}
7494
7495/*
7496 * "substitute()" function
7497 */
7498 static void
7499f_substitute(typval_T *argvars, typval_T *rettv)
7500{
7501 char_u patbuf[NUMBUFLEN];
7502 char_u subbuf[NUMBUFLEN];
7503 char_u flagsbuf[NUMBUFLEN];
7504
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007505 char_u *str = tv_get_string_chk(&argvars[0]);
7506 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007507 char_u *sub = NULL;
7508 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007509 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007510
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007511 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7512 expr = &argvars[2];
7513 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007514 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007515
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007516 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007517 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7518 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519 rettv->vval.v_string = NULL;
7520 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007521 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522}
7523
7524/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007525 * "swapinfo(swap_filename)" function
7526 */
7527 static void
7528f_swapinfo(typval_T *argvars, typval_T *rettv)
7529{
7530 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007531 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007532}
7533
7534/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007535 * "swapname(expr)" function
7536 */
7537 static void
7538f_swapname(typval_T *argvars, typval_T *rettv)
7539{
7540 buf_T *buf;
7541
7542 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007543 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007544 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7545 || buf->b_ml.ml_mfp->mf_fname == NULL)
7546 rettv->vval.v_string = NULL;
7547 else
7548 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7549}
7550
7551/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007552 * "synID(lnum, col, trans)" function
7553 */
7554 static void
7555f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7556{
7557 int id = 0;
7558#ifdef FEAT_SYN_HL
7559 linenr_T lnum;
7560 colnr_T col;
7561 int trans;
7562 int transerr = FALSE;
7563
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007564 lnum = tv_get_lnum(argvars); /* -1 on type error */
7565 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7566 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567
7568 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7569 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7570 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7571#endif
7572
7573 rettv->vval.v_number = id;
7574}
7575
7576/*
7577 * "synIDattr(id, what [, mode])" function
7578 */
7579 static void
7580f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7581{
7582 char_u *p = NULL;
7583#ifdef FEAT_SYN_HL
7584 int id;
7585 char_u *what;
7586 char_u *mode;
7587 char_u modebuf[NUMBUFLEN];
7588 int modec;
7589
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007590 id = (int)tv_get_number(&argvars[0]);
7591 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007592 if (argvars[2].v_type != VAR_UNKNOWN)
7593 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007594 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007595 modec = TOLOWER_ASC(mode[0]);
7596 if (modec != 't' && modec != 'c' && modec != 'g')
7597 modec = 0; /* replace invalid with current */
7598 }
7599 else
7600 {
7601#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7602 if (USE_24BIT)
7603 modec = 'g';
7604 else
7605#endif
7606 if (t_colors > 1)
7607 modec = 'c';
7608 else
7609 modec = 't';
7610 }
7611
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007612 switch (TOLOWER_ASC(what[0]))
7613 {
7614 case 'b':
7615 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7616 p = highlight_color(id, what, modec);
7617 else /* bold */
7618 p = highlight_has_attr(id, HL_BOLD, modec);
7619 break;
7620
7621 case 'f': /* fg[#] or font */
7622 p = highlight_color(id, what, modec);
7623 break;
7624
7625 case 'i':
7626 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7627 p = highlight_has_attr(id, HL_INVERSE, modec);
7628 else /* italic */
7629 p = highlight_has_attr(id, HL_ITALIC, modec);
7630 break;
7631
7632 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007633 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007634 break;
7635
7636 case 'r': /* reverse */
7637 p = highlight_has_attr(id, HL_INVERSE, modec);
7638 break;
7639
7640 case 's':
7641 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7642 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007643 /* strikeout */
7644 else if (TOLOWER_ASC(what[1]) == 't' &&
7645 TOLOWER_ASC(what[2]) == 'r')
7646 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 else /* standout */
7648 p = highlight_has_attr(id, HL_STANDOUT, modec);
7649 break;
7650
7651 case 'u':
7652 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7653 /* underline */
7654 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7655 else
7656 /* undercurl */
7657 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7658 break;
7659 }
7660
7661 if (p != NULL)
7662 p = vim_strsave(p);
7663#endif
7664 rettv->v_type = VAR_STRING;
7665 rettv->vval.v_string = p;
7666}
7667
7668/*
7669 * "synIDtrans(id)" function
7670 */
7671 static void
7672f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7673{
7674 int id;
7675
7676#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007677 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007678
7679 if (id > 0)
7680 id = syn_get_final_id(id);
7681 else
7682#endif
7683 id = 0;
7684
7685 rettv->vval.v_number = id;
7686}
7687
7688/*
7689 * "synconcealed(lnum, col)" function
7690 */
7691 static void
7692f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7693{
7694#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7695 linenr_T lnum;
7696 colnr_T col;
7697 int syntax_flags = 0;
7698 int cchar;
7699 int matchid = 0;
7700 char_u str[NUMBUFLEN];
7701#endif
7702
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007703 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007704
7705#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007706 lnum = tv_get_lnum(argvars); /* -1 on type error */
7707 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007708
7709 vim_memset(str, NUL, sizeof(str));
7710
7711 if (rettv_list_alloc(rettv) != FAIL)
7712 {
7713 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7714 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7715 && curwin->w_p_cole > 0)
7716 {
7717 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7718 syntax_flags = get_syntax_info(&matchid);
7719
7720 /* get the conceal character */
7721 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7722 {
7723 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007724 if (cchar == NUL && curwin->w_p_cole == 1)
7725 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726 if (cchar != NUL)
7727 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007728 if (has_mbyte)
7729 (*mb_char2bytes)(cchar, str);
7730 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007731 str[0] = cchar;
7732 }
7733 }
7734 }
7735
7736 list_append_number(rettv->vval.v_list,
7737 (syntax_flags & HL_CONCEAL) != 0);
7738 /* -1 to auto-determine strlen */
7739 list_append_string(rettv->vval.v_list, str, -1);
7740 list_append_number(rettv->vval.v_list, matchid);
7741 }
7742#endif
7743}
7744
7745/*
7746 * "synstack(lnum, col)" function
7747 */
7748 static void
7749f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7750{
7751#ifdef FEAT_SYN_HL
7752 linenr_T lnum;
7753 colnr_T col;
7754 int i;
7755 int id;
7756#endif
7757
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007758 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007759
7760#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007761 lnum = tv_get_lnum(argvars); /* -1 on type error */
7762 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007763
7764 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7765 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7766 && rettv_list_alloc(rettv) != FAIL)
7767 {
7768 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
7769 for (i = 0; ; ++i)
7770 {
7771 id = syn_get_stack_item(i);
7772 if (id < 0)
7773 break;
7774 if (list_append_number(rettv->vval.v_list, id) == FAIL)
7775 break;
7776 }
7777 }
7778#endif
7779}
7780
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007781/*
7782 * "tabpagebuflist()" function
7783 */
7784 static void
7785f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7786{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007787 tabpage_T *tp;
7788 win_T *wp = NULL;
7789
7790 if (argvars[0].v_type == VAR_UNKNOWN)
7791 wp = firstwin;
7792 else
7793 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007794 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007795 if (tp != NULL)
7796 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
7797 }
7798 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
7799 {
7800 for (; wp != NULL; wp = wp->w_next)
7801 if (list_append_number(rettv->vval.v_list,
7802 wp->w_buffer->b_fnum) == FAIL)
7803 break;
7804 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805}
7806
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007807/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007808 * "tagfiles()" function
7809 */
7810 static void
7811f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
7812{
7813 char_u *fname;
7814 tagname_T tn;
7815 int first;
7816
7817 if (rettv_list_alloc(rettv) == FAIL)
7818 return;
7819 fname = alloc(MAXPATHL);
7820 if (fname == NULL)
7821 return;
7822
7823 for (first = TRUE; ; first = FALSE)
7824 if (get_tagfname(&tn, first, fname) == FAIL
7825 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
7826 break;
7827 tagname_free(&tn);
7828 vim_free(fname);
7829}
7830
7831/*
7832 * "taglist()" function
7833 */
7834 static void
7835f_taglist(typval_T *argvars, typval_T *rettv)
7836{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007837 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007838 char_u *tag_pattern;
7839
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007840 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007841
7842 rettv->vval.v_number = FALSE;
7843 if (*tag_pattern == NUL)
7844 return;
7845
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007846 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007847 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007849 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007850}
7851
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007852#ifdef FEAT_FLOAT
7853/*
7854 * "tan()" function
7855 */
7856 static void
7857f_tan(typval_T *argvars, typval_T *rettv)
7858{
7859 float_T f = 0.0;
7860
7861 rettv->v_type = VAR_FLOAT;
7862 if (get_float_arg(argvars, &f) == OK)
7863 rettv->vval.v_float = tan(f);
7864 else
7865 rettv->vval.v_float = 0.0;
7866}
7867
7868/*
7869 * "tanh()" function
7870 */
7871 static void
7872f_tanh(typval_T *argvars, typval_T *rettv)
7873{
7874 float_T f = 0.0;
7875
7876 rettv->v_type = VAR_FLOAT;
7877 if (get_float_arg(argvars, &f) == OK)
7878 rettv->vval.v_float = tanh(f);
7879 else
7880 rettv->vval.v_float = 0.0;
7881}
7882#endif
7883
7884/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885 * "tolower(string)" function
7886 */
7887 static void
7888f_tolower(typval_T *argvars, typval_T *rettv)
7889{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007890 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007891 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007892}
7893
7894/*
7895 * "toupper(string)" function
7896 */
7897 static void
7898f_toupper(typval_T *argvars, typval_T *rettv)
7899{
7900 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007901 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007902}
7903
7904/*
7905 * "tr(string, fromstr, tostr)" function
7906 */
7907 static void
7908f_tr(typval_T *argvars, typval_T *rettv)
7909{
7910 char_u *in_str;
7911 char_u *fromstr;
7912 char_u *tostr;
7913 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914 int inlen;
7915 int fromlen;
7916 int tolen;
7917 int idx;
7918 char_u *cpstr;
7919 int cplen;
7920 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007921 char_u buf[NUMBUFLEN];
7922 char_u buf2[NUMBUFLEN];
7923 garray_T ga;
7924
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007925 in_str = tv_get_string(&argvars[0]);
7926 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
7927 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007928
7929 /* Default return value: empty string. */
7930 rettv->v_type = VAR_STRING;
7931 rettv->vval.v_string = NULL;
7932 if (fromstr == NULL || tostr == NULL)
7933 return; /* type error; errmsg already given */
7934 ga_init2(&ga, (int)sizeof(char), 80);
7935
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007937 /* not multi-byte: fromstr and tostr must be the same length */
7938 if (STRLEN(fromstr) != STRLEN(tostr))
7939 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007940error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007941 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942 ga_clear(&ga);
7943 return;
7944 }
7945
7946 /* fromstr and tostr have to contain the same number of chars */
7947 while (*in_str != NUL)
7948 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007949 if (has_mbyte)
7950 {
7951 inlen = (*mb_ptr2len)(in_str);
7952 cpstr = in_str;
7953 cplen = inlen;
7954 idx = 0;
7955 for (p = fromstr; *p != NUL; p += fromlen)
7956 {
7957 fromlen = (*mb_ptr2len)(p);
7958 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
7959 {
7960 for (p = tostr; *p != NUL; p += tolen)
7961 {
7962 tolen = (*mb_ptr2len)(p);
7963 if (idx-- == 0)
7964 {
7965 cplen = tolen;
7966 cpstr = p;
7967 break;
7968 }
7969 }
7970 if (*p == NUL) /* tostr is shorter than fromstr */
7971 goto error;
7972 break;
7973 }
7974 ++idx;
7975 }
7976
7977 if (first && cpstr == in_str)
7978 {
7979 /* Check that fromstr and tostr have the same number of
7980 * (multi-byte) characters. Done only once when a character
7981 * of in_str doesn't appear in fromstr. */
7982 first = FALSE;
7983 for (p = tostr; *p != NUL; p += tolen)
7984 {
7985 tolen = (*mb_ptr2len)(p);
7986 --idx;
7987 }
7988 if (idx != 0)
7989 goto error;
7990 }
7991
7992 (void)ga_grow(&ga, cplen);
7993 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
7994 ga.ga_len += cplen;
7995
7996 in_str += inlen;
7997 }
7998 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007999 {
8000 /* When not using multi-byte chars we can do it faster. */
8001 p = vim_strchr(fromstr, *in_str);
8002 if (p != NULL)
8003 ga_append(&ga, tostr[p - fromstr]);
8004 else
8005 ga_append(&ga, *in_str);
8006 ++in_str;
8007 }
8008 }
8009
8010 /* add a terminating NUL */
8011 (void)ga_grow(&ga, 1);
8012 ga_append(&ga, NUL);
8013
8014 rettv->vval.v_string = ga.ga_data;
8015}
8016
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008017/*
8018 * "trim({expr})" function
8019 */
8020 static void
8021f_trim(typval_T *argvars, typval_T *rettv)
8022{
8023 char_u buf1[NUMBUFLEN];
8024 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008025 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008026 char_u *mask = NULL;
8027 char_u *tail;
8028 char_u *prev;
8029 char_u *p;
8030 int c1;
8031
8032 rettv->v_type = VAR_STRING;
8033 if (head == NULL)
8034 {
8035 rettv->vval.v_string = NULL;
8036 return;
8037 }
8038
8039 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008040 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008041
8042 while (*head != NUL)
8043 {
8044 c1 = PTR2CHAR(head);
8045 if (mask == NULL)
8046 {
8047 if (c1 > ' ' && c1 != 0xa0)
8048 break;
8049 }
8050 else
8051 {
8052 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8053 if (c1 == PTR2CHAR(p))
8054 break;
8055 if (*p == NUL)
8056 break;
8057 }
8058 MB_PTR_ADV(head);
8059 }
8060
8061 for (tail = head + STRLEN(head); tail > head; tail = prev)
8062 {
8063 prev = tail;
8064 MB_PTR_BACK(head, prev);
8065 c1 = PTR2CHAR(prev);
8066 if (mask == NULL)
8067 {
8068 if (c1 > ' ' && c1 != 0xa0)
8069 break;
8070 }
8071 else
8072 {
8073 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8074 if (c1 == PTR2CHAR(p))
8075 break;
8076 if (*p == NUL)
8077 break;
8078 }
8079 }
8080 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8081}
8082
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083#ifdef FEAT_FLOAT
8084/*
8085 * "trunc({float})" function
8086 */
8087 static void
8088f_trunc(typval_T *argvars, typval_T *rettv)
8089{
8090 float_T f = 0.0;
8091
8092 rettv->v_type = VAR_FLOAT;
8093 if (get_float_arg(argvars, &f) == OK)
8094 /* trunc() is not in C90, use floor() or ceil() instead. */
8095 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8096 else
8097 rettv->vval.v_float = 0.0;
8098}
8099#endif
8100
8101/*
8102 * "type(expr)" function
8103 */
8104 static void
8105f_type(typval_T *argvars, typval_T *rettv)
8106{
8107 int n = -1;
8108
8109 switch (argvars[0].v_type)
8110 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008111 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8112 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008113 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008114 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8115 case VAR_LIST: n = VAR_TYPE_LIST; break;
8116 case VAR_DICT: n = VAR_TYPE_DICT; break;
8117 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118 case VAR_SPECIAL:
8119 if (argvars[0].vval.v_number == VVAL_FALSE
8120 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008121 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008123 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008124 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008125 case VAR_JOB: n = VAR_TYPE_JOB; break;
8126 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008127 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008128 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008129 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008130 n = -1;
8131 break;
8132 }
8133 rettv->vval.v_number = n;
8134}
8135
8136/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008137 * "virtcol(string)" function
8138 */
8139 static void
8140f_virtcol(typval_T *argvars, typval_T *rettv)
8141{
8142 colnr_T vcol = 0;
8143 pos_T *fp;
8144 int fnum = curbuf->b_fnum;
8145
8146 fp = var2fpos(&argvars[0], FALSE, &fnum);
8147 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8148 && fnum == curbuf->b_fnum)
8149 {
8150 getvvcol(curwin, fp, NULL, NULL, &vcol);
8151 ++vcol;
8152 }
8153
8154 rettv->vval.v_number = vcol;
8155}
8156
8157/*
8158 * "visualmode()" function
8159 */
8160 static void
8161f_visualmode(typval_T *argvars, typval_T *rettv)
8162{
8163 char_u str[2];
8164
8165 rettv->v_type = VAR_STRING;
8166 str[0] = curbuf->b_visual_mode_eval;
8167 str[1] = NUL;
8168 rettv->vval.v_string = vim_strsave(str);
8169
8170 /* A non-zero number or non-empty string argument: reset mode. */
8171 if (non_zero_arg(&argvars[0]))
8172 curbuf->b_visual_mode_eval = NUL;
8173}
8174
8175/*
8176 * "wildmenumode()" function
8177 */
8178 static void
8179f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8180{
8181#ifdef FEAT_WILDMENU
8182 if (wild_menu_showing)
8183 rettv->vval.v_number = 1;
8184#endif
8185}
8186
8187/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 * "wordcount()" function
8189 */
8190 static void
8191f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8192{
8193 if (rettv_dict_alloc(rettv) == FAIL)
8194 return;
8195 cursor_pos_info(rettv->vval.v_dict);
8196}
8197
8198/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008199 * "xor(expr, expr)" function
8200 */
8201 static void
8202f_xor(typval_T *argvars, typval_T *rettv)
8203{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008204 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8205 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008206}
8207
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008208#endif /* FEAT_EVAL */