blob: af72edb18d961b59363ac5cbdcc91a2ac443e0ed [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020019#ifdef VMS
20# include <float.h>
21#endif
22
Bram Moolenaard0573012017-10-28 21:11:06 +020023#ifdef MACOS_X
Bram Moolenaar8d71b542019-08-30 15:46:30 +020024# include <time.h> // for time_t
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020025#endif
26
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020027#ifdef FEAT_FLOAT
28static void f_abs(typval_T *argvars, typval_T *rettv);
29static void f_acos(typval_T *argvars, typval_T *rettv);
30#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020031static void f_and(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020032#ifdef FEAT_FLOAT
33static void f_asin(typval_T *argvars, typval_T *rettv);
34static void f_atan(typval_T *argvars, typval_T *rettv);
35static void f_atan2(typval_T *argvars, typval_T *rettv);
36#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010037#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020038static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010039static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010040# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010041static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_byte2line(typval_T *argvars, typval_T *rettv);
45static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
46static void f_byteidx(typval_T *argvars, typval_T *rettv);
47static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
48static void f_call(typval_T *argvars, typval_T *rettv);
49#ifdef FEAT_FLOAT
50static void f_ceil(typval_T *argvars, typval_T *rettv);
51#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_changenr(typval_T *argvars, typval_T *rettv);
53static void f_char2nr(typval_T *argvars, typval_T *rettv);
54static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020056static void f_confirm(typval_T *argvars, typval_T *rettv);
57static void f_copy(typval_T *argvars, typval_T *rettv);
58#ifdef FEAT_FLOAT
59static void f_cos(typval_T *argvars, typval_T *rettv);
60static void f_cosh(typval_T *argvars, typval_T *rettv);
61#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020062static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010063#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020064static void f_debugbreak(typval_T *argvars, typval_T *rettv);
65#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_did_filetype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020068static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020069static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020070static void f_escape(typval_T *argvars, typval_T *rettv);
71static void f_eval(typval_T *argvars, typval_T *rettv);
72static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020074static void f_exists(typval_T *argvars, typval_T *rettv);
75#ifdef FEAT_FLOAT
76static void f_exp(typval_T *argvars, typval_T *rettv);
77#endif
78static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020079static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020081#ifdef FEAT_FLOAT
82static void f_float2nr(typval_T *argvars, typval_T *rettv);
83static void f_floor(typval_T *argvars, typval_T *rettv);
84static void f_fmod(typval_T *argvars, typval_T *rettv);
85#endif
86static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020087static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +020088static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_function(typval_T *argvars, typval_T *rettv);
90static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
91static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +010092static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020094static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020095static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +010097static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020098static void f_getpid(typval_T *argvars, typval_T *rettv);
99static void f_getcurpos(typval_T *argvars, typval_T *rettv);
100static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200101static void f_getreg(typval_T *argvars, typval_T *rettv);
102static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100103static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
106static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200107static void f_hlID(typval_T *argvars, typval_T *rettv);
108static void f_hlexists(typval_T *argvars, typval_T *rettv);
109static void f_hostname(typval_T *argvars, typval_T *rettv);
110static void f_iconv(typval_T *argvars, typval_T *rettv);
111static void f_indent(typval_T *argvars, typval_T *rettv);
112static void f_index(typval_T *argvars, typval_T *rettv);
113static void f_input(typval_T *argvars, typval_T *rettv);
114static void f_inputdialog(typval_T *argvars, typval_T *rettv);
115static void f_inputlist(typval_T *argvars, typval_T *rettv);
116static void f_inputrestore(typval_T *argvars, typval_T *rettv);
117static void f_inputsave(typval_T *argvars, typval_T *rettv);
118static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200119static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200120static void f_islocked(typval_T *argvars, typval_T *rettv);
121#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200122static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200123static void f_isnan(typval_T *argvars, typval_T *rettv);
124#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200125static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
126static void f_len(typval_T *argvars, typval_T *rettv);
127static void f_libcall(typval_T *argvars, typval_T *rettv);
128static void f_libcallnr(typval_T *argvars, typval_T *rettv);
129static void f_line(typval_T *argvars, typval_T *rettv);
130static void f_line2byte(typval_T *argvars, typval_T *rettv);
131static void f_lispindent(typval_T *argvars, typval_T *rettv);
132static void f_localtime(typval_T *argvars, typval_T *rettv);
133#ifdef FEAT_FLOAT
134static void f_log(typval_T *argvars, typval_T *rettv);
135static void f_log10(typval_T *argvars, typval_T *rettv);
136#endif
137#ifdef FEAT_LUA
138static void f_luaeval(typval_T *argvars, typval_T *rettv);
139#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200140static void f_maparg(typval_T *argvars, typval_T *rettv);
141static void f_mapcheck(typval_T *argvars, typval_T *rettv);
142static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200143static void f_matchend(typval_T *argvars, typval_T *rettv);
144static void f_matchlist(typval_T *argvars, typval_T *rettv);
145static void f_matchstr(typval_T *argvars, typval_T *rettv);
146static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
147static void f_max(typval_T *argvars, typval_T *rettv);
148static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200149static void f_mode(typval_T *argvars, typval_T *rettv);
150#ifdef FEAT_MZSCHEME
151static void f_mzeval(typval_T *argvars, typval_T *rettv);
152#endif
153static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
154static void f_nr2char(typval_T *argvars, typval_T *rettv);
155static void f_or(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200156#ifdef FEAT_PERL
157static void f_perleval(typval_T *argvars, typval_T *rettv);
158#endif
159#ifdef FEAT_FLOAT
160static void f_pow(typval_T *argvars, typval_T *rettv);
161#endif
162static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
163static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200164static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200165static void f_pumvisible(typval_T *argvars, typval_T *rettv);
166#ifdef FEAT_PYTHON3
167static void f_py3eval(typval_T *argvars, typval_T *rettv);
168#endif
169#ifdef FEAT_PYTHON
170static void f_pyeval(typval_T *argvars, typval_T *rettv);
171#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100172#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
173static void f_pyxeval(typval_T *argvars, typval_T *rettv);
174#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200175static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200176static void f_reg_executing(typval_T *argvars, typval_T *rettv);
177static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200178static void f_reltime(typval_T *argvars, typval_T *rettv);
179#ifdef FEAT_FLOAT
180static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
181#endif
182static void f_reltimestr(typval_T *argvars, typval_T *rettv);
183static void f_remote_expr(typval_T *argvars, typval_T *rettv);
184static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
185static void f_remote_peek(typval_T *argvars, typval_T *rettv);
186static void f_remote_read(typval_T *argvars, typval_T *rettv);
187static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100188static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200189static void f_rename(typval_T *argvars, typval_T *rettv);
190static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191#ifdef FEAT_FLOAT
192static void f_round(typval_T *argvars, typval_T *rettv);
193#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100194#ifdef FEAT_RUBY
195static void f_rubyeval(typval_T *argvars, typval_T *rettv);
196#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197static void f_screenattr(typval_T *argvars, typval_T *rettv);
198static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100199static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200200static void f_screencol(typval_T *argvars, typval_T *rettv);
201static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100202static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200203static void f_search(typval_T *argvars, typval_T *rettv);
204static void f_searchdecl(typval_T *argvars, typval_T *rettv);
205static void f_searchpair(typval_T *argvars, typval_T *rettv);
206static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
207static void f_searchpos(typval_T *argvars, typval_T *rettv);
208static void f_server2client(typval_T *argvars, typval_T *rettv);
209static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200210static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200211static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200212static void f_setfperm(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200213static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200214static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100215static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200216#ifdef FEAT_CRYPT
217static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200218#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200219static void f_shellescape(typval_T *argvars, typval_T *rettv);
220static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221#ifdef FEAT_FLOAT
222static void f_sin(typval_T *argvars, typval_T *rettv);
223static void f_sinh(typval_T *argvars, typval_T *rettv);
224#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200225static void f_soundfold(typval_T *argvars, typval_T *rettv);
226static void f_spellbadword(typval_T *argvars, typval_T *rettv);
227static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
228static void f_split(typval_T *argvars, typval_T *rettv);
229#ifdef FEAT_FLOAT
230static void f_sqrt(typval_T *argvars, typval_T *rettv);
231static void f_str2float(typval_T *argvars, typval_T *rettv);
232#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200233static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200234static void f_str2nr(typval_T *argvars, typval_T *rettv);
235static void f_strchars(typval_T *argvars, typval_T *rettv);
236#ifdef HAVE_STRFTIME
237static void f_strftime(typval_T *argvars, typval_T *rettv);
238#endif
239static void f_strgetchar(typval_T *argvars, typval_T *rettv);
240static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200241static void f_strlen(typval_T *argvars, typval_T *rettv);
242static void f_strcharpart(typval_T *argvars, typval_T *rettv);
243static void f_strpart(typval_T *argvars, typval_T *rettv);
244static void f_strridx(typval_T *argvars, typval_T *rettv);
245static void f_strtrans(typval_T *argvars, typval_T *rettv);
246static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
247static void f_strwidth(typval_T *argvars, typval_T *rettv);
248static void f_submatch(typval_T *argvars, typval_T *rettv);
249static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200250static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200251static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200252static void f_synID(typval_T *argvars, typval_T *rettv);
253static void f_synIDattr(typval_T *argvars, typval_T *rettv);
254static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
255static void f_synstack(typval_T *argvars, typval_T *rettv);
256static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200257static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200258static void f_taglist(typval_T *argvars, typval_T *rettv);
259static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200260#ifdef FEAT_FLOAT
261static void f_tan(typval_T *argvars, typval_T *rettv);
262static void f_tanh(typval_T *argvars, typval_T *rettv);
263#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264static void f_tolower(typval_T *argvars, typval_T *rettv);
265static void f_toupper(typval_T *argvars, typval_T *rettv);
266static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100267static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200268#ifdef FEAT_FLOAT
269static void f_trunc(typval_T *argvars, typval_T *rettv);
270#endif
271static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200272static void f_virtcol(typval_T *argvars, typval_T *rettv);
273static void f_visualmode(typval_T *argvars, typval_T *rettv);
274static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200275static void f_wordcount(typval_T *argvars, typval_T *rettv);
276static void f_xor(typval_T *argvars, typval_T *rettv);
277
278/*
279 * Array with names and number of arguments of all internal functions
280 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
281 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200282typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200283{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200284 char *f_name; // function name
285 char f_min_argc; // minimal number of arguments
286 char f_max_argc; // maximal number of arguments
287 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200288 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200289 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200290} funcentry_T;
291
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200292// values for f_argtype; zero means it cannot be used as a method
293#define FEARG_1 1 // base is the first argument
294#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200295#define FEARG_3 3 // base is the third argument
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200296#define FEARG_4 4 // base is the fourth argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200297#define FEARG_LAST 9 // base is the last argument
298
Bram Moolenaarac92e252019-08-03 21:58:38 +0200299static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200300{
301#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200302 {"abs", 1, 1, FEARG_1, f_abs},
303 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200304#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200305 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200306 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200307 {"append", 2, 2, FEARG_LAST, f_append},
308 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
309 {"argc", 0, 1, 0, f_argc},
310 {"argidx", 0, 0, 0, f_argidx},
311 {"arglistid", 0, 2, 0, f_arglistid},
312 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200313#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200314 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200315#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200316 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200317 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200318 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200319 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200320 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
321 {"assert_false", 1, 2, FEARG_1, f_assert_false},
322 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
323 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200324 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200325 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200326 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200327 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200328#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200329 {"atan", 1, 1, FEARG_1, f_atan},
330 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200331#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100332#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200333 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200334 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100335# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200336 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100337# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100338#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200339 {"browse", 4, 4, 0, f_browse},
340 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200341 {"bufadd", 1, 1, FEARG_1, f_bufadd},
342 {"bufexists", 1, 1, FEARG_1, f_bufexists},
343 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200344 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
345 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200346 {"buflisted", 1, 1, FEARG_1, f_buflisted},
347 {"bufload", 1, 1, FEARG_1, f_bufload},
348 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200349 {"bufname", 0, 1, FEARG_1, f_bufname},
350 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200351 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
352 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200353 {"byte2line", 1, 1, FEARG_1, f_byte2line},
354 {"byteidx", 2, 2, FEARG_1, f_byteidx},
355 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
356 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200357#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200358 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359#endif
360#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200361 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
362 {"ch_close", 1, 1, FEARG_1, f_ch_close},
363 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
364 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
365 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
366 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
367 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
368 {"ch_info", 1, 1, FEARG_1, f_ch_info},
369 {"ch_log", 1, 2, FEARG_1, f_ch_log},
370 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
371 {"ch_open", 1, 2, FEARG_1, f_ch_open},
372 {"ch_read", 1, 2, FEARG_1, f_ch_read},
373 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
374 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
375 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
376 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
377 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
378 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200379#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200380 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200381 {"char2nr", 1, 2, FEARG_1, f_char2nr},
382 {"chdir", 1, 1, FEARG_1, f_chdir},
383 {"cindent", 1, 1, FEARG_1, f_cindent},
384 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
385 {"col", 1, 1, FEARG_1, f_col},
386 {"complete", 2, 2, FEARG_2, f_complete},
387 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200388 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200389 {"complete_info", 0, 1, FEARG_1, f_complete_info},
390 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200391 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200392#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200393 {"cos", 1, 1, FEARG_1, f_cos},
394 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200395#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200396 {"count", 2, 4, FEARG_1, f_count},
397 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200398 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100399#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200400 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200401#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200402 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
403 {"delete", 1, 2, FEARG_1, f_delete},
404 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200405 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200406 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
407 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200408 {"empty", 1, 1, FEARG_1, f_empty},
409 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200410 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200411 {"eval", 1, 1, FEARG_1, f_eval},
412 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200413 {"executable", 1, 1, FEARG_1, f_executable},
414 {"execute", 1, 2, FEARG_1, f_execute},
415 {"exepath", 1, 1, FEARG_1, f_exepath},
416 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200417#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200418 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200419#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200420 {"expand", 1, 3, FEARG_1, f_expand},
421 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200422 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200423 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
424 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
425 {"filereadable", 1, 1, FEARG_1, f_filereadable},
426 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200427 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200428 {"finddir", 1, 3, FEARG_1, f_finddir},
429 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200430#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200431 {"float2nr", 1, 1, FEARG_1, f_float2nr},
432 {"floor", 1, 1, FEARG_1, f_floor},
433 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200434#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200435 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
436 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
437 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
438 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
439 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200440 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200441 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200442 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200443 {"funcref", 1, 3, FEARG_1, f_funcref},
444 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200445 {"garbagecollect", 0, 1, 0, f_garbagecollect},
446 {"get", 2, 3, FEARG_1, f_get},
447 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200448 {"getbufline", 2, 3, FEARG_1, f_getbufline},
449 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
450 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200451 {"getchar", 0, 1, 0, f_getchar},
452 {"getcharmod", 0, 0, 0, f_getcharmod},
453 {"getcharsearch", 0, 0, 0, f_getcharsearch},
454 {"getcmdline", 0, 0, 0, f_getcmdline},
455 {"getcmdpos", 0, 0, 0, f_getcmdpos},
456 {"getcmdtype", 0, 0, 0, f_getcmdtype},
457 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200458 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200459 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200460 {"getcwd", 0, 2, FEARG_1, f_getcwd},
461 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200462 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200463 {"getfperm", 1, 1, FEARG_1, f_getfperm},
464 {"getfsize", 1, 1, FEARG_1, f_getfsize},
465 {"getftime", 1, 1, FEARG_1, f_getftime},
466 {"getftype", 1, 1, FEARG_1, f_getftype},
Bram Moolenaara3a12462019-09-07 15:08:38 +0200467 {"getimstatus", 0, 0, 0, f_getimstatus},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200468 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
469 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200470 {"getloclist", 1, 2, 0, f_getloclist},
471 {"getmatches", 0, 1, 0, f_getmatches},
472 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200473 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200474 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200475 {"getreg", 0, 3, FEARG_1, f_getreg},
476 {"getregtype", 0, 1, FEARG_1, f_getregtype},
477 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
478 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
479 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200480 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
481 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
482 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200483 {"getwinposx", 0, 0, 0, f_getwinposx},
484 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200485 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
486 {"glob", 1, 4, FEARG_1, f_glob},
487 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
488 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200489 {"has", 1, 1, 0, f_has},
490 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200491 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
492 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
493 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
494 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
495 {"histadd", 2, 2, FEARG_2, f_histadd},
496 {"histdel", 1, 2, FEARG_1, f_histdel},
497 {"histget", 1, 2, FEARG_1, f_histget},
498 {"histnr", 1, 1, FEARG_1, f_histnr},
499 {"hlID", 1, 1, FEARG_1, f_hlID},
500 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200501 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200502 {"iconv", 3, 3, FEARG_1, f_iconv},
503 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200505 {"input", 1, 3, FEARG_1, f_input},
506 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
507 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200508 {"inputrestore", 0, 0, 0, f_inputrestore},
509 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200510 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200511 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200512 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200513 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200514#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200515 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200516#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200517 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200518#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200519 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200520#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200521 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200522#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200523 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
524 {"job_info", 0, 1, FEARG_1, f_job_info},
525 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
526 {"job_start", 1, 2, FEARG_1, f_job_start},
527 {"job_status", 1, 1, FEARG_1, f_job_status},
528 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200529#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200530 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200531 {"js_decode", 1, 1, FEARG_1, f_js_decode},
532 {"js_encode", 1, 1, FEARG_1, f_js_encode},
533 {"json_decode", 1, 1, FEARG_1, f_json_decode},
534 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200535 {"keys", 1, 1, FEARG_1, f_keys},
536 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
537 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200538 {"libcall", 3, 3, FEARG_3, f_libcall},
539 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200540 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200541 {"line2byte", 1, 1, FEARG_1, f_line2byte},
542 {"lispindent", 1, 1, FEARG_1, f_lispindent},
543 {"list2str", 1, 2, FEARG_1, f_list2str},
544 {"listener_add", 1, 2, FEARG_2, f_listener_add},
545 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
546 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200547 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200548#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200549 {"log", 1, 1, FEARG_1, f_log},
550 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200551#endif
552#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200553 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200554#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200555 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200556 {"maparg", 1, 4, FEARG_1, f_maparg},
557 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
558 {"match", 2, 4, FEARG_1, f_match},
559 {"matchadd", 2, 5, FEARG_1, f_matchadd},
560 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
561 {"matcharg", 1, 1, FEARG_1, f_matcharg},
562 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
563 {"matchend", 2, 4, FEARG_1, f_matchend},
564 {"matchlist", 2, 4, FEARG_1, f_matchlist},
565 {"matchstr", 2, 4, FEARG_1, f_matchstr},
566 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200567 {"max", 1, 1, FEARG_1, f_max},
568 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200569 {"mkdir", 1, 3, FEARG_1, f_mkdir},
570 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200571#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200572 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200573#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200574 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
575 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200576 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200577 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200578#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200579 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200580#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200581#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200582 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
583 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200584 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200585 {"popup_close", 1, 2, FEARG_1, f_popup_close},
586 {"popup_create", 2, 2, FEARG_1, f_popup_create},
587 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200588 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
589 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200590 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
591 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200592 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
593 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
594 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200595 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200596 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
597 {"popup_move", 2, 2, FEARG_1, f_popup_move},
598 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
599 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
600 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
601 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200602#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200604 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200605#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200606 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200607 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200608#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200609 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
610 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
611 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200612#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100613#ifdef FEAT_TEXT_PROP
Bram Moolenaara5a78822019-09-04 21:57:18 +0200614 {"prop_add", 3, 3, FEARG_1, f_prop_add},
615 {"prop_clear", 1, 3, FEARG_1, f_prop_clear},
616 {"prop_list", 1, 2, FEARG_1, f_prop_list},
617 {"prop_remove", 1, 3, FEARG_1, f_prop_remove},
618 {"prop_type_add", 2, 2, FEARG_1, f_prop_type_add},
619 {"prop_type_change", 2, 2, FEARG_1, f_prop_type_change},
620 {"prop_type_delete", 1, 2, FEARG_1, f_prop_type_delete},
621 {"prop_type_get", 1, 2, FEARG_1, f_prop_type_get},
622 {"prop_type_list", 0, 1, FEARG_1, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100623#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200624 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200625 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200626#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200627 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200628#endif
629#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200630 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200631#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100632#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200633 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100634#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200635 {"range", 1, 3, FEARG_1, f_range},
636 {"readdir", 1, 2, FEARG_1, f_readdir},
637 {"readfile", 1, 3, FEARG_1, f_readfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200638 {"reg_executing", 0, 0, 0, f_reg_executing},
639 {"reg_recording", 0, 0, 0, f_reg_recording},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200640 {"reltime", 0, 2, FEARG_1, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200641#ifdef FEAT_FLOAT
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200642 {"reltimefloat", 1, 1, FEARG_1, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643#endif
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200644 {"reltimestr", 1, 1, FEARG_1, f_reltimestr},
645 {"remote_expr", 2, 4, FEARG_1, f_remote_expr},
646 {"remote_foreground", 1, 1, FEARG_1, f_remote_foreground},
647 {"remote_peek", 1, 2, FEARG_1, f_remote_peek},
648 {"remote_read", 1, 2, FEARG_1, f_remote_read},
649 {"remote_send", 2, 3, FEARG_1, f_remote_send},
650 {"remote_startserver", 1, 1, FEARG_1, f_remote_startserver},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200651 {"remove", 2, 3, FEARG_1, f_remove},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200652 {"rename", 2, 2, FEARG_1, f_rename},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200653 {"repeat", 2, 2, FEARG_1, f_repeat},
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200654 {"resolve", 1, 1, FEARG_1, f_resolve},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200655 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200656#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200657 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100659#ifdef FEAT_RUBY
Bram Moolenaara0d1fef2019-09-04 22:29:14 +0200660 {"rubyeval", 1, 1, FEARG_1, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100661#endif
Bram Moolenaar196b4662019-09-06 21:34:30 +0200662 {"screenattr", 2, 2, FEARG_1, f_screenattr},
663 {"screenchar", 2, 2, FEARG_1, f_screenchar},
664 {"screenchars", 2, 2, FEARG_1, f_screenchars},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200665 {"screencol", 0, 0, 0, f_screencol},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200666 {"screenpos", 3, 3, FEARG_1, f_screenpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200667 {"screenrow", 0, 0, 0, f_screenrow},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200668 {"screenstring", 2, 2, FEARG_1, f_screenstring},
669 {"search", 1, 4, FEARG_1, f_search},
670 {"searchdecl", 1, 3, FEARG_1, f_searchdecl},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200671 {"searchpair", 3, 7, 0, f_searchpair},
672 {"searchpairpos", 3, 7, 0, f_searchpairpos},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200673 {"searchpos", 1, 4, FEARG_1, f_searchpos},
674 {"server2client", 2, 2, FEARG_1, f_server2client},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200675 {"serverlist", 0, 0, 0, f_serverlist},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200676 {"setbufline", 3, 3, FEARG_3, f_setbufline},
677 {"setbufvar", 3, 3, FEARG_3, f_setbufvar},
678 {"setcharsearch", 1, 1, FEARG_1, f_setcharsearch},
679 {"setcmdpos", 1, 1, FEARG_1, f_setcmdpos},
680 {"setenv", 2, 2, FEARG_2, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200681 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar196b4662019-09-06 21:34:30 +0200682 {"setline", 2, 2, FEARG_2, f_setline},
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200683 {"setloclist", 2, 4, FEARG_2, f_setloclist},
684 {"setmatches", 1, 2, FEARG_1, f_setmatches},
685 {"setpos", 2, 2, FEARG_2, f_setpos},
686 {"setqflist", 1, 3, FEARG_1, f_setqflist},
687 {"setreg", 2, 3, FEARG_2, f_setreg},
688 {"settabvar", 3, 3, FEARG_3, f_settabvar},
689 {"settabwinvar", 4, 4, FEARG_4, f_settabwinvar},
690 {"settagstack", 2, 3, FEARG_2, f_settagstack},
691 {"setwinvar", 3, 3, FEARG_3, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200692#ifdef FEAT_CRYPT
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200693 {"sha256", 1, 1, FEARG_1, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200694#endif
Bram Moolenaaraad222c2019-09-06 22:46:09 +0200695 {"shellescape", 1, 2, FEARG_1, f_shellescape},
696 {"shiftwidth", 0, 1, FEARG_1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100697#ifdef FEAT_SIGNS
Bram Moolenaar93476fd2019-09-06 22:00:54 +0200698 {"sign_define", 1, 2, FEARG_1, f_sign_define},
699 {"sign_getdefined", 0, 1, FEARG_1, f_sign_getdefined},
700 {"sign_getplaced", 0, 2, FEARG_1, f_sign_getplaced},
701 {"sign_jump", 3, 3, FEARG_1, f_sign_jump},
702 {"sign_place", 4, 5, FEARG_1, f_sign_place},
703 {"sign_placelist", 1, 1, FEARG_1, f_sign_placelist},
704 {"sign_undefine", 0, 1, FEARG_1, f_sign_undefine},
705 {"sign_unplace", 1, 2, FEARG_1, f_sign_unplace},
706 {"sign_unplacelist", 1, 2, FEARG_1, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100707#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200708 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200709#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200710 {"sin", 1, 1, FEARG_1, f_sin},
711 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200712#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200713 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200714#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200715 {"sound_clear", 0, 0, 0, f_sound_clear},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200716 {"sound_playevent", 1, 2, FEARG_1, f_sound_playevent},
717 {"sound_playfile", 1, 2, FEARG_1, f_sound_playfile},
718 {"sound_stop", 1, 1, FEARG_1, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200719#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200720 {"soundfold", 1, 1, FEARG_1, f_soundfold},
721 {"spellbadword", 0, 1, FEARG_1, f_spellbadword},
722 {"spellsuggest", 1, 3, FEARG_1, f_spellsuggest},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200723 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200724#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200725 {"sqrt", 1, 1, FEARG_1, f_sqrt},
726 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200727#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200728 {"str2list", 1, 2, FEARG_1, f_str2list},
Bram Moolenaar60a8de22019-09-15 14:33:22 +0200729 {"str2nr", 1, 3, FEARG_1, f_str2nr},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200730 {"strcharpart", 2, 3, FEARG_1, f_strcharpart},
731 {"strchars", 1, 2, FEARG_1, f_strchars},
732 {"strdisplaywidth", 1, 2, FEARG_1, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200733#ifdef HAVE_STRFTIME
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200734 {"strftime", 1, 2, FEARG_1, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200735#endif
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200736 {"strgetchar", 2, 2, FEARG_1, f_strgetchar},
737 {"stridx", 2, 3, FEARG_1, f_stridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200738 {"string", 1, 1, FEARG_1, f_string},
739 {"strlen", 1, 1, FEARG_1, f_strlen},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200740 {"strpart", 2, 3, FEARG_1, f_strpart},
741 {"strridx", 2, 3, FEARG_1, f_strridx},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200742 {"strtrans", 1, 1, FEARG_1, f_strtrans},
743 {"strwidth", 1, 1, FEARG_1, f_strwidth},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200744 {"submatch", 1, 2, FEARG_1, f_submatch},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200745 {"substitute", 4, 4, FEARG_1, f_substitute},
Bram Moolenaarf6ed61e2019-09-07 19:05:09 +0200746 {"swapinfo", 1, 1, FEARG_1, f_swapinfo},
747 {"swapname", 1, 1, FEARG_1, f_swapname},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200748 {"synID", 3, 3, 0, f_synID},
749 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
750 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
751 {"synconcealed", 2, 2, 0, f_synconcealed},
752 {"synstack", 2, 2, 0, f_synstack},
753 {"system", 1, 2, FEARG_1, f_system},
754 {"systemlist", 1, 2, FEARG_1, f_systemlist},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200755 {"tabpagebuflist", 0, 1, FEARG_1, f_tabpagebuflist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200756 {"tabpagenr", 0, 1, 0, f_tabpagenr},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200757 {"tabpagewinnr", 1, 2, FEARG_1, f_tabpagewinnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200758 {"tagfiles", 0, 0, 0, f_tagfiles},
Bram Moolenaarce90e362019-09-08 18:58:44 +0200759 {"taglist", 1, 2, FEARG_1, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200760#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200761 {"tan", 1, 1, FEARG_1, f_tan},
762 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200763#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200764 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200765#ifdef FEAT_TERMINAL
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200766 {"term_dumpdiff", 2, 3, FEARG_1, f_term_dumpdiff},
767 {"term_dumpload", 1, 2, FEARG_1, f_term_dumpload},
768 {"term_dumpwrite", 2, 3, FEARG_2, f_term_dumpwrite},
769 {"term_getaltscreen", 1, 1, FEARG_1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200770# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200771 {"term_getansicolors", 1, 1, FEARG_1, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200772# endif
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200773 {"term_getattr", 2, 2, FEARG_1, f_term_getattr},
774 {"term_getcursor", 1, 1, FEARG_1, f_term_getcursor},
775 {"term_getjob", 1, 1, FEARG_1, f_term_getjob},
776 {"term_getline", 2, 2, FEARG_1, f_term_getline},
777 {"term_getscrolled", 1, 1, FEARG_1, f_term_getscrolled},
778 {"term_getsize", 1, 1, FEARG_1, f_term_getsize},
779 {"term_getstatus", 1, 1, FEARG_1, f_term_getstatus},
780 {"term_gettitle", 1, 1, FEARG_1, f_term_gettitle},
781 {"term_gettty", 1, 2, FEARG_1, f_term_gettty},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200782 {"term_list", 0, 0, 0, f_term_list},
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200783 {"term_scrape", 2, 2, FEARG_1, f_term_scrape},
784 {"term_sendkeys", 2, 2, FEARG_1, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200785# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7ee80f72019-09-08 20:55:06 +0200786 {"term_setansicolors", 2, 2, FEARG_1, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200787# endif
Bram 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 */
1049 static int
1050non_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
1491/*
1492 * "cindent(lnum)" function
1493 */
1494 static void
1495f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1496{
1497#ifdef FEAT_CINDENT
1498 pos_T pos;
1499 linenr_T lnum;
1500
1501 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001502 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001503 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1504 {
1505 curwin->w_cursor.lnum = lnum;
1506 rettv->vval.v_number = get_c_indent();
1507 curwin->w_cursor = pos;
1508 }
1509 else
1510#endif
1511 rettv->vval.v_number = -1;
1512}
1513
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001514 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001515get_optional_window(typval_T *argvars, int idx)
1516{
1517 win_T *win = curwin;
1518
1519 if (argvars[idx].v_type != VAR_UNKNOWN)
1520 {
1521 win = find_win_by_nr_or_id(&argvars[idx]);
1522 if (win == NULL)
1523 {
1524 emsg(_(e_invalwindow));
1525 return NULL;
1526 }
1527 }
1528 return win;
1529}
1530
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001531/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001532 * "col(string)" function
1533 */
1534 static void
1535f_col(typval_T *argvars, typval_T *rettv)
1536{
1537 colnr_T col = 0;
1538 pos_T *fp;
1539 int fnum = curbuf->b_fnum;
1540
1541 fp = var2fpos(&argvars[0], FALSE, &fnum);
1542 if (fp != NULL && fnum == curbuf->b_fnum)
1543 {
1544 if (fp->col == MAXCOL)
1545 {
1546 /* '> can be MAXCOL, get the length of the line then */
1547 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1548 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1549 else
1550 col = MAXCOL;
1551 }
1552 else
1553 {
1554 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001555 /* col(".") when the cursor is on the NUL at the end of the line
1556 * because of "coladd" can be seen as an extra column. */
1557 if (virtual_active() && fp == &curwin->w_cursor)
1558 {
1559 char_u *p = ml_get_cursor();
1560
1561 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1562 curwin->w_virtcol - curwin->w_cursor.coladd))
1563 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001564 int l;
1565
1566 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1567 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001568 }
1569 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001570 }
1571 }
1572 rettv->vval.v_number = col;
1573}
1574
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001575/*
1576 * "confirm(message, buttons[, default [, type]])" function
1577 */
1578 static void
1579f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1580{
1581#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
1582 char_u *message;
1583 char_u *buttons = NULL;
1584 char_u buf[NUMBUFLEN];
1585 char_u buf2[NUMBUFLEN];
1586 int def = 1;
1587 int type = VIM_GENERIC;
1588 char_u *typestr;
1589 int error = FALSE;
1590
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001591 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001592 if (message == NULL)
1593 error = TRUE;
1594 if (argvars[1].v_type != VAR_UNKNOWN)
1595 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001596 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001597 if (buttons == NULL)
1598 error = TRUE;
1599 if (argvars[2].v_type != VAR_UNKNOWN)
1600 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001601 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001602 if (argvars[3].v_type != VAR_UNKNOWN)
1603 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001604 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001605 if (typestr == NULL)
1606 error = TRUE;
1607 else
1608 {
1609 switch (TOUPPER_ASC(*typestr))
1610 {
1611 case 'E': type = VIM_ERROR; break;
1612 case 'Q': type = VIM_QUESTION; break;
1613 case 'I': type = VIM_INFO; break;
1614 case 'W': type = VIM_WARNING; break;
1615 case 'G': type = VIM_GENERIC; break;
1616 }
1617 }
1618 }
1619 }
1620 }
1621
1622 if (buttons == NULL || *buttons == NUL)
1623 buttons = (char_u *)_("&Ok");
1624
1625 if (!error)
1626 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
1627 def, NULL, FALSE);
1628#endif
1629}
1630
1631/*
1632 * "copy()" function
1633 */
1634 static void
1635f_copy(typval_T *argvars, typval_T *rettv)
1636{
1637 item_copy(&argvars[0], rettv, FALSE, 0);
1638}
1639
1640#ifdef FEAT_FLOAT
1641/*
1642 * "cos()" function
1643 */
1644 static void
1645f_cos(typval_T *argvars, typval_T *rettv)
1646{
1647 float_T f = 0.0;
1648
1649 rettv->v_type = VAR_FLOAT;
1650 if (get_float_arg(argvars, &f) == OK)
1651 rettv->vval.v_float = cos(f);
1652 else
1653 rettv->vval.v_float = 0.0;
1654}
1655
1656/*
1657 * "cosh()" function
1658 */
1659 static void
1660f_cosh(typval_T *argvars, typval_T *rettv)
1661{
1662 float_T f = 0.0;
1663
1664 rettv->v_type = VAR_FLOAT;
1665 if (get_float_arg(argvars, &f) == OK)
1666 rettv->vval.v_float = cosh(f);
1667 else
1668 rettv->vval.v_float = 0.0;
1669}
1670#endif
1671
1672/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001673 * "cursor(lnum, col)" function, or
1674 * "cursor(list)"
1675 *
1676 * Moves the cursor to the specified line and column.
1677 * Returns 0 when the position could be set, -1 otherwise.
1678 */
1679 static void
1680f_cursor(typval_T *argvars, typval_T *rettv)
1681{
1682 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001683 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001684 int set_curswant = TRUE;
1685
1686 rettv->vval.v_number = -1;
1687 if (argvars[1].v_type == VAR_UNKNOWN)
1688 {
1689 pos_T pos;
1690 colnr_T curswant = -1;
1691
1692 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
1693 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001694 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001695 return;
1696 }
1697 line = pos.lnum;
1698 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001699 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001700 if (curswant >= 0)
1701 {
1702 curwin->w_curswant = curswant - 1;
1703 set_curswant = FALSE;
1704 }
1705 }
1706 else
1707 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001708 line = tv_get_lnum(argvars);
1709 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001710 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001711 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01001713 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 return; /* type error; errmsg already given */
1715 if (line > 0)
1716 curwin->w_cursor.lnum = line;
1717 if (col > 0)
1718 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001719 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001720
1721 /* Make sure the cursor is in a valid position. */
1722 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001723 /* Correct cursor for multi-byte character. */
1724 if (has_mbyte)
1725 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001726
1727 curwin->w_set_curswant = set_curswant;
1728 rettv->vval.v_number = 0;
1729}
1730
Bram Moolenaar4f974752019-02-17 17:44:42 +01001731#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001732/*
1733 * "debugbreak()" function
1734 */
1735 static void
1736f_debugbreak(typval_T *argvars, typval_T *rettv)
1737{
1738 int pid;
1739
1740 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001741 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001742 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001743 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02001744 else
1745 {
1746 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
1747
1748 if (hProcess != NULL)
1749 {
1750 DebugBreakProcess(hProcess);
1751 CloseHandle(hProcess);
1752 rettv->vval.v_number = OK;
1753 }
1754 }
1755}
1756#endif
1757
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001758/*
1759 * "deepcopy()" function
1760 */
1761 static void
1762f_deepcopy(typval_T *argvars, typval_T *rettv)
1763{
1764 int noref = 0;
1765 int copyID;
1766
1767 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001768 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001769 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001770 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001771 else
1772 {
1773 copyID = get_copyID();
1774 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
1775 }
1776}
1777
1778/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001779 * "did_filetype()" function
1780 */
1781 static void
1782f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
1783{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001784 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001785}
1786
1787/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001788 * "empty({expr})" function
1789 */
1790 static void
1791f_empty(typval_T *argvars, typval_T *rettv)
1792{
1793 int n = FALSE;
1794
1795 switch (argvars[0].v_type)
1796 {
1797 case VAR_STRING:
1798 case VAR_FUNC:
1799 n = argvars[0].vval.v_string == NULL
1800 || *argvars[0].vval.v_string == NUL;
1801 break;
1802 case VAR_PARTIAL:
1803 n = FALSE;
1804 break;
1805 case VAR_NUMBER:
1806 n = argvars[0].vval.v_number == 0;
1807 break;
1808 case VAR_FLOAT:
1809#ifdef FEAT_FLOAT
1810 n = argvars[0].vval.v_float == 0.0;
1811 break;
1812#endif
1813 case VAR_LIST:
1814 n = argvars[0].vval.v_list == NULL
1815 || argvars[0].vval.v_list->lv_first == NULL;
1816 break;
1817 case VAR_DICT:
1818 n = argvars[0].vval.v_dict == NULL
1819 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
1820 break;
1821 case VAR_SPECIAL:
1822 n = argvars[0].vval.v_number != VVAL_TRUE;
1823 break;
1824
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001825 case VAR_BLOB:
1826 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001827 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
1828 break;
1829
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001830 case VAR_JOB:
1831#ifdef FEAT_JOB_CHANNEL
1832 n = argvars[0].vval.v_job == NULL
1833 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
1834 break;
1835#endif
1836 case VAR_CHANNEL:
1837#ifdef FEAT_JOB_CHANNEL
1838 n = argvars[0].vval.v_channel == NULL
1839 || !channel_is_open(argvars[0].vval.v_channel);
1840 break;
1841#endif
1842 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01001843 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844 n = TRUE;
1845 break;
1846 }
1847
1848 rettv->vval.v_number = n;
1849}
1850
1851/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02001852 * "environ()" function
1853 */
1854 static void
1855f_environ(typval_T *argvars UNUSED, typval_T *rettv)
1856{
1857#if !defined(AMIGA)
1858 int i = 0;
1859 char_u *entry, *value;
1860# ifdef MSWIN
1861 extern wchar_t **_wenviron;
1862# else
1863 extern char **environ;
1864# endif
1865
1866 if (rettv_dict_alloc(rettv) != OK)
1867 return;
1868
1869# ifdef MSWIN
1870 if (*_wenviron == NULL)
1871 return;
1872# else
1873 if (*environ == NULL)
1874 return;
1875# endif
1876
1877 for (i = 0; ; ++i)
1878 {
1879# ifdef MSWIN
1880 short_u *p;
1881
1882 if ((p = (short_u *)_wenviron[i]) == NULL)
1883 return;
1884 entry = utf16_to_enc(p, NULL);
1885# else
1886 if ((entry = (char_u *)environ[i]) == NULL)
1887 return;
1888 entry = vim_strsave(entry);
1889# endif
1890 if (entry == NULL) // out of memory
1891 return;
1892 if ((value = vim_strchr(entry, '=')) == NULL)
1893 {
1894 vim_free(entry);
1895 continue;
1896 }
1897 *value++ = NUL;
1898 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
1899 vim_free(entry);
1900 }
1901#endif
1902}
1903
1904/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001905 * "escape({string}, {chars})" function
1906 */
1907 static void
1908f_escape(typval_T *argvars, typval_T *rettv)
1909{
1910 char_u buf[NUMBUFLEN];
1911
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001912 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
1913 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001914 rettv->v_type = VAR_STRING;
1915}
1916
1917/*
1918 * "eval()" function
1919 */
1920 static void
1921f_eval(typval_T *argvars, typval_T *rettv)
1922{
1923 char_u *s, *p;
1924
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001925 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001926 if (s != NULL)
1927 s = skipwhite(s);
1928
1929 p = s;
1930 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
1931 {
1932 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001933 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001934 need_clr_eos = FALSE;
1935 rettv->v_type = VAR_NUMBER;
1936 rettv->vval.v_number = 0;
1937 }
1938 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001939 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001940}
1941
1942/*
1943 * "eventhandler()" function
1944 */
1945 static void
1946f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
1947{
1948 rettv->vval.v_number = vgetc_busy;
1949}
1950
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001951static garray_T redir_execute_ga;
1952
1953/*
1954 * Append "value[value_len]" to the execute() output.
1955 */
1956 void
1957execute_redir_str(char_u *value, int value_len)
1958{
1959 int len;
1960
1961 if (value_len == -1)
1962 len = (int)STRLEN(value); /* Append the entire string */
1963 else
1964 len = value_len; /* Append only "value_len" characters */
1965 if (ga_grow(&redir_execute_ga, len) == OK)
1966 {
1967 mch_memmove((char *)redir_execute_ga.ga_data
1968 + redir_execute_ga.ga_len, value, len);
1969 redir_execute_ga.ga_len += len;
1970 }
1971}
1972
1973/*
1974 * Get next line from a list.
1975 * Called by do_cmdline() to get the next line.
1976 * Returns allocated string, or NULL for end of function.
1977 */
1978
1979 static char_u *
1980get_list_line(
1981 int c UNUSED,
1982 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02001983 int indent UNUSED,
1984 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001985{
1986 listitem_T **p = (listitem_T **)cookie;
1987 listitem_T *item = *p;
1988 char_u buf[NUMBUFLEN];
1989 char_u *s;
1990
1991 if (item == NULL)
1992 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001993 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001994 *p = item->li_next;
1995 return s == NULL ? NULL : vim_strsave(s);
1996}
1997
1998/*
1999 * "execute()" function
2000 */
Bram Moolenaar261f3462019-09-07 15:45:32 +02002001 void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002002execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002003{
2004 char_u *cmd = NULL;
2005 list_T *list = NULL;
2006 int save_msg_silent = msg_silent;
2007 int save_emsg_silent = emsg_silent;
2008 int save_emsg_noredir = emsg_noredir;
2009 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002010 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002011 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002012 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002013 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002014
2015 rettv->vval.v_string = NULL;
2016 rettv->v_type = VAR_STRING;
2017
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002018 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002019 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002020 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002021 if (list == NULL || list->lv_first == NULL)
2022 /* empty list, no commands, empty output */
2023 return;
2024 ++list->lv_refcount;
2025 }
2026 else
2027 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002028 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002029 if (cmd == NULL)
2030 return;
2031 }
2032
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002033 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002034 {
2035 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002036 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002037
2038 if (s == NULL)
2039 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002040 if (*s == NUL)
2041 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002042 if (STRNCMP(s, "silent", 6) == 0)
2043 ++msg_silent;
2044 if (STRCMP(s, "silent!") == 0)
2045 {
2046 emsg_silent = TRUE;
2047 emsg_noredir = TRUE;
2048 }
2049 }
2050 else
2051 ++msg_silent;
2052
2053 if (redir_execute)
2054 save_ga = redir_execute_ga;
2055 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2056 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002057 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002058 if (!echo_output)
2059 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002060
2061 if (cmd != NULL)
2062 do_cmdline_cmd(cmd);
2063 else
2064 {
2065 listitem_T *item = list->lv_first;
2066
2067 do_cmdline(NULL, get_list_line, (void *)&item,
2068 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2069 --list->lv_refcount;
2070 }
2071
Bram Moolenaard297f352017-01-29 20:31:21 +01002072 /* Need to append a NUL to the result. */
2073 if (ga_grow(&redir_execute_ga, 1) == OK)
2074 {
2075 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2076 rettv->vval.v_string = redir_execute_ga.ga_data;
2077 }
2078 else
2079 {
2080 ga_clear(&redir_execute_ga);
2081 rettv->vval.v_string = NULL;
2082 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002083 msg_silent = save_msg_silent;
2084 emsg_silent = save_emsg_silent;
2085 emsg_noredir = save_emsg_noredir;
2086
2087 redir_execute = save_redir_execute;
2088 if (redir_execute)
2089 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002090 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002091
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002092 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002093 if (echo_output)
2094 // When not working silently: put it in column zero. A following
2095 // "echon" will overwrite the message, unavoidably.
2096 msg_col = 0;
2097 else
2098 // When working silently: Put it back where it was, since nothing
2099 // should have been written.
2100 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002101}
2102
2103/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002104 * "execute()" function
2105 */
2106 static void
2107f_execute(typval_T *argvars, typval_T *rettv)
2108{
2109 execute_common(argvars, rettv, 0);
2110}
2111
2112/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002113 * "exists()" function
2114 */
2115 static void
2116f_exists(typval_T *argvars, typval_T *rettv)
2117{
2118 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002119 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002121 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002122 if (*p == '$') /* environment variable */
2123 {
2124 /* first try "normal" environment variables (fast) */
2125 if (mch_getenv(p + 1) != NULL)
2126 n = TRUE;
2127 else
2128 {
2129 /* try expanding things like $VIM and ${HOME} */
2130 p = expand_env_save(p);
2131 if (p != NULL && *p != '$')
2132 n = TRUE;
2133 vim_free(p);
2134 }
2135 }
2136 else if (*p == '&' || *p == '+') /* option */
2137 {
2138 n = (get_option_tv(&p, NULL, TRUE) == OK);
2139 if (*skipwhite(p) != NUL)
2140 n = FALSE; /* trailing garbage */
2141 }
2142 else if (*p == '*') /* internal or user defined function */
2143 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002144 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002145 }
2146 else if (*p == ':')
2147 {
2148 n = cmd_exists(p + 1);
2149 }
2150 else if (*p == '#')
2151 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002152 if (p[1] == '#')
2153 n = autocmd_supported(p + 2);
2154 else
2155 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002156 }
2157 else /* internal variable */
2158 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002159 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002160 }
2161
2162 rettv->vval.v_number = n;
2163}
2164
2165#ifdef FEAT_FLOAT
2166/*
2167 * "exp()" function
2168 */
2169 static void
2170f_exp(typval_T *argvars, typval_T *rettv)
2171{
2172 float_T f = 0.0;
2173
2174 rettv->v_type = VAR_FLOAT;
2175 if (get_float_arg(argvars, &f) == OK)
2176 rettv->vval.v_float = exp(f);
2177 else
2178 rettv->vval.v_float = 0.0;
2179}
2180#endif
2181
2182/*
2183 * "expand()" function
2184 */
2185 static void
2186f_expand(typval_T *argvars, typval_T *rettv)
2187{
2188 char_u *s;
2189 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002190 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002191 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2192 expand_T xpc;
2193 int error = FALSE;
2194 char_u *result;
2195
2196 rettv->v_type = VAR_STRING;
2197 if (argvars[1].v_type != VAR_UNKNOWN
2198 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002199 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002200 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002201 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002202
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002203 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204 if (*s == '%' || *s == '#' || *s == '<')
2205 {
2206 ++emsg_off;
2207 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2208 --emsg_off;
2209 if (rettv->v_type == VAR_LIST)
2210 {
2211 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2212 list_append_string(rettv->vval.v_list, result, -1);
2213 else
2214 vim_free(result);
2215 }
2216 else
2217 rettv->vval.v_string = result;
2218 }
2219 else
2220 {
2221 /* When the optional second argument is non-zero, don't remove matches
2222 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2223 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002224 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002225 options |= WILD_KEEP_ALL;
2226 if (!error)
2227 {
2228 ExpandInit(&xpc);
2229 xpc.xp_context = EXPAND_FILES;
2230 if (p_wic)
2231 options += WILD_ICASE;
2232 if (rettv->v_type == VAR_STRING)
2233 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2234 options, WILD_ALL);
2235 else if (rettv_list_alloc(rettv) != FAIL)
2236 {
2237 int i;
2238
2239 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2240 for (i = 0; i < xpc.xp_numfiles; i++)
2241 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2242 ExpandCleanup(&xpc);
2243 }
2244 }
2245 else
2246 rettv->vval.v_string = NULL;
2247 }
2248}
2249
2250/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002251 * "expandcmd()" function
2252 * Expand all the special characters in a command string.
2253 */
2254 static void
2255f_expandcmd(typval_T *argvars, typval_T *rettv)
2256{
2257 exarg_T eap;
2258 char_u *cmdstr;
2259 char *errormsg = NULL;
2260
2261 rettv->v_type = VAR_STRING;
2262 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2263
2264 memset(&eap, 0, sizeof(eap));
2265 eap.cmd = cmdstr;
2266 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002267 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002268 eap.usefilter = FALSE;
2269 eap.nextcmd = NULL;
2270 eap.cmdidx = CMD_USER;
2271
2272 expand_filename(&eap, &cmdstr, &errormsg);
2273 if (errormsg != NULL && *errormsg != NUL)
2274 emsg(errormsg);
2275
2276 rettv->vval.v_string = cmdstr;
2277}
2278
2279/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002280 * "feedkeys()" function
2281 */
2282 static void
2283f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2284{
2285 int remap = TRUE;
2286 int insert = FALSE;
2287 char_u *keys, *flags;
2288 char_u nbuf[NUMBUFLEN];
2289 int typed = FALSE;
2290 int execute = FALSE;
2291 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002292 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002293 char_u *keys_esc;
2294
2295 /* This is not allowed in the sandbox. If the commands would still be
2296 * executed in the sandbox it would be OK, but it probably happens later,
2297 * when "sandbox" is no longer set. */
2298 if (check_secure())
2299 return;
2300
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002301 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002302
2303 if (argvars[1].v_type != VAR_UNKNOWN)
2304 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002305 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002306 for ( ; *flags != NUL; ++flags)
2307 {
2308 switch (*flags)
2309 {
2310 case 'n': remap = FALSE; break;
2311 case 'm': remap = TRUE; break;
2312 case 't': typed = TRUE; break;
2313 case 'i': insert = TRUE; break;
2314 case 'x': execute = TRUE; break;
2315 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002316 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002317 }
2318 }
2319 }
2320
2321 if (*keys != NUL || execute)
2322 {
2323 /* Need to escape K_SPECIAL and CSI before putting the string in the
2324 * typeahead buffer. */
2325 keys_esc = vim_strsave_escape_csi(keys);
2326 if (keys_esc != NULL)
2327 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002328 if (lowlevel)
2329 {
2330#ifdef USE_INPUT_BUF
2331 add_to_input_buf(keys, (int)STRLEN(keys));
2332#else
2333 emsg(_("E980: lowlevel input not supported"));
2334#endif
2335 }
2336 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002337 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002338 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002339 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002340 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002341#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002342 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002343#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002344 )
2345 typebuf_was_filled = TRUE;
2346 }
2347 vim_free(keys_esc);
2348
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002349 if (execute)
2350 {
2351 int save_msg_scroll = msg_scroll;
2352
2353 /* Avoid a 1 second delay when the keys start Insert mode. */
2354 msg_scroll = FALSE;
2355
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002356 if (!dangerous)
2357 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002358 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002359 if (!dangerous)
2360 --ex_normal_busy;
2361
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002362 msg_scroll |= save_msg_scroll;
2363 }
2364 }
2365 }
2366}
2367
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002368#ifdef FEAT_FLOAT
2369/*
2370 * "float2nr({float})" function
2371 */
2372 static void
2373f_float2nr(typval_T *argvars, typval_T *rettv)
2374{
2375 float_T f = 0.0;
2376
2377 if (get_float_arg(argvars, &f) == OK)
2378 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002379 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002380 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002381 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002382 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002383 else
2384 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002385 }
2386}
2387
2388/*
2389 * "floor({float})" function
2390 */
2391 static void
2392f_floor(typval_T *argvars, typval_T *rettv)
2393{
2394 float_T f = 0.0;
2395
2396 rettv->v_type = VAR_FLOAT;
2397 if (get_float_arg(argvars, &f) == OK)
2398 rettv->vval.v_float = floor(f);
2399 else
2400 rettv->vval.v_float = 0.0;
2401}
2402
2403/*
2404 * "fmod()" function
2405 */
2406 static void
2407f_fmod(typval_T *argvars, typval_T *rettv)
2408{
2409 float_T fx = 0.0, fy = 0.0;
2410
2411 rettv->v_type = VAR_FLOAT;
2412 if (get_float_arg(argvars, &fx) == OK
2413 && get_float_arg(&argvars[1], &fy) == OK)
2414 rettv->vval.v_float = fmod(fx, fy);
2415 else
2416 rettv->vval.v_float = 0.0;
2417}
2418#endif
2419
2420/*
2421 * "fnameescape({string})" function
2422 */
2423 static void
2424f_fnameescape(typval_T *argvars, typval_T *rettv)
2425{
2426 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002427 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002428 rettv->v_type = VAR_STRING;
2429}
2430
2431/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002432 * "foreground()" function
2433 */
2434 static void
2435f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2436{
2437#ifdef FEAT_GUI
2438 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002439 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02002441 return;
2442 }
2443#endif
2444#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002445 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446#endif
2447}
2448
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002449 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002450common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002451{
2452 char_u *s;
2453 char_u *name;
2454 int use_string = FALSE;
2455 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002456 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002457
2458 if (argvars[0].v_type == VAR_FUNC)
2459 {
2460 /* function(MyFunc, [arg], dict) */
2461 s = argvars[0].vval.v_string;
2462 }
2463 else if (argvars[0].v_type == VAR_PARTIAL
2464 && argvars[0].vval.v_partial != NULL)
2465 {
2466 /* function(dict.MyFunc, [arg]) */
2467 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002468 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002469 }
2470 else
2471 {
2472 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002473 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002474 use_string = TRUE;
2475 }
2476
Bram Moolenaar843b8842016-08-21 14:36:15 +02002477 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002478 {
2479 name = s;
2480 trans_name = trans_function_name(&name, FALSE,
2481 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
2482 if (*name != NUL)
2483 s = NULL;
2484 }
2485
Bram Moolenaar843b8842016-08-21 14:36:15 +02002486 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
2487 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002488 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002489 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002490 else if (trans_name != NULL && (is_funcref
2491 ? find_func(trans_name) == NULL
2492 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002493 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002494 else
2495 {
2496 int dict_idx = 0;
2497 int arg_idx = 0;
2498 list_T *list = NULL;
2499
2500 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
2501 {
2502 char sid_buf[25];
2503 int off = *s == 's' ? 2 : 5;
2504
2505 /* Expand s: and <SID> into <SNR>nr_, so that the function can
2506 * also be called from another script. Using trans_function_name()
2507 * would also work, but some plugins depend on the name being
2508 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02002509 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02002510 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002511 if (name != NULL)
2512 {
2513 STRCPY(name, sid_buf);
2514 STRCAT(name, s + off);
2515 }
2516 }
2517 else
2518 name = vim_strsave(s);
2519
2520 if (argvars[1].v_type != VAR_UNKNOWN)
2521 {
2522 if (argvars[2].v_type != VAR_UNKNOWN)
2523 {
2524 /* function(name, [args], dict) */
2525 arg_idx = 1;
2526 dict_idx = 2;
2527 }
2528 else if (argvars[1].v_type == VAR_DICT)
2529 /* function(name, dict) */
2530 dict_idx = 1;
2531 else
2532 /* function(name, [args]) */
2533 arg_idx = 1;
2534 if (dict_idx > 0)
2535 {
2536 if (argvars[dict_idx].v_type != VAR_DICT)
2537 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002538 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002539 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002540 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 }
2542 if (argvars[dict_idx].vval.v_dict == NULL)
2543 dict_idx = 0;
2544 }
2545 if (arg_idx > 0)
2546 {
2547 if (argvars[arg_idx].v_type != VAR_LIST)
2548 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002549 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002550 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002551 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002552 }
2553 list = argvars[arg_idx].vval.v_list;
2554 if (list == NULL || list->lv_len == 0)
2555 arg_idx = 0;
2556 }
2557 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002558 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002559 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002560 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002561
2562 /* result is a VAR_PARTIAL */
2563 if (pt == NULL)
2564 vim_free(name);
2565 else
2566 {
2567 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
2568 {
2569 listitem_T *li;
2570 int i = 0;
2571 int arg_len = 0;
2572 int lv_len = 0;
2573
2574 if (arg_pt != NULL)
2575 arg_len = arg_pt->pt_argc;
2576 if (list != NULL)
2577 lv_len = list->lv_len;
2578 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02002579 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002580 if (pt->pt_argv == NULL)
2581 {
2582 vim_free(pt);
2583 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002584 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002585 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002586 for (i = 0; i < arg_len; i++)
2587 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
2588 if (lv_len > 0)
2589 for (li = list->lv_first; li != NULL;
2590 li = li->li_next)
2591 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002592 }
2593
2594 /* For "function(dict.func, [], dict)" and "func" is a partial
2595 * use "dict". That is backwards compatible. */
2596 if (dict_idx > 0)
2597 {
2598 /* The dict is bound explicitly, pt_auto is FALSE. */
2599 pt->pt_dict = argvars[dict_idx].vval.v_dict;
2600 ++pt->pt_dict->dv_refcount;
2601 }
2602 else if (arg_pt != NULL)
2603 {
2604 /* If the dict was bound automatically the result is also
2605 * bound automatically. */
2606 pt->pt_dict = arg_pt->pt_dict;
2607 pt->pt_auto = arg_pt->pt_auto;
2608 if (pt->pt_dict != NULL)
2609 ++pt->pt_dict->dv_refcount;
2610 }
2611
2612 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002613 if (arg_pt != NULL && arg_pt->pt_func != NULL)
2614 {
2615 pt->pt_func = arg_pt->pt_func;
2616 func_ptr_ref(pt->pt_func);
2617 vim_free(name);
2618 }
2619 else if (is_funcref)
2620 {
2621 pt->pt_func = find_func(trans_name);
2622 func_ptr_ref(pt->pt_func);
2623 vim_free(name);
2624 }
2625 else
2626 {
2627 pt->pt_name = name;
2628 func_ref(name);
2629 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002630 }
2631 rettv->v_type = VAR_PARTIAL;
2632 rettv->vval.v_partial = pt;
2633 }
2634 else
2635 {
2636 /* result is a VAR_FUNC */
2637 rettv->v_type = VAR_FUNC;
2638 rettv->vval.v_string = name;
2639 func_ref(name);
2640 }
2641 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002642theend:
2643 vim_free(trans_name);
2644}
2645
2646/*
2647 * "funcref()" function
2648 */
2649 static void
2650f_funcref(typval_T *argvars, typval_T *rettv)
2651{
2652 common_function(argvars, rettv, TRUE);
2653}
2654
2655/*
2656 * "function()" function
2657 */
2658 static void
2659f_function(typval_T *argvars, typval_T *rettv)
2660{
2661 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002662}
2663
2664/*
2665 * "garbagecollect()" function
2666 */
2667 static void
2668f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
2669{
2670 /* This is postponed until we are back at the toplevel, because we may be
2671 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
2672 want_garbage_collect = TRUE;
2673
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002674 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002675 garbage_collect_at_exit = TRUE;
2676}
2677
2678/*
2679 * "get()" function
2680 */
2681 static void
2682f_get(typval_T *argvars, typval_T *rettv)
2683{
2684 listitem_T *li;
2685 list_T *l;
2686 dictitem_T *di;
2687 dict_T *d;
2688 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002689 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002690
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002691 if (argvars[0].v_type == VAR_BLOB)
2692 {
2693 int error = FALSE;
2694 int idx = tv_get_number_chk(&argvars[1], &error);
2695
2696 if (!error)
2697 {
2698 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002699 if (idx < 0)
2700 idx = blob_len(argvars[0].vval.v_blob) + idx;
2701 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
2702 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002703 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002704 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002705 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01002706 tv = rettv;
2707 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002708 }
2709 }
2710 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002711 {
2712 if ((l = argvars[0].vval.v_list) != NULL)
2713 {
2714 int error = FALSE;
2715
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002716 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002717 if (!error && li != NULL)
2718 tv = &li->li_tv;
2719 }
2720 }
2721 else if (argvars[0].v_type == VAR_DICT)
2722 {
2723 if ((d = argvars[0].vval.v_dict) != NULL)
2724 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002725 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002726 if (di != NULL)
2727 tv = &di->di_tv;
2728 }
2729 }
2730 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
2731 {
2732 partial_T *pt;
2733 partial_T fref_pt;
2734
2735 if (argvars[0].v_type == VAR_PARTIAL)
2736 pt = argvars[0].vval.v_partial;
2737 else
2738 {
2739 vim_memset(&fref_pt, 0, sizeof(fref_pt));
2740 fref_pt.pt_name = argvars[0].vval.v_string;
2741 pt = &fref_pt;
2742 }
2743
2744 if (pt != NULL)
2745 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002746 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002747 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002748
2749 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
2750 {
2751 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002752 n = partial_name(pt);
2753 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002754 rettv->vval.v_string = NULL;
2755 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002756 {
2757 rettv->vval.v_string = vim_strsave(n);
2758 if (rettv->v_type == VAR_FUNC)
2759 func_ref(rettv->vval.v_string);
2760 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002761 }
2762 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002763 {
2764 what_is_dict = TRUE;
2765 if (pt->pt_dict != NULL)
2766 rettv_dict_set(rettv, pt->pt_dict);
2767 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002768 else if (STRCMP(what, "args") == 0)
2769 {
2770 rettv->v_type = VAR_LIST;
2771 if (rettv_list_alloc(rettv) == OK)
2772 {
2773 int i;
2774
2775 for (i = 0; i < pt->pt_argc; ++i)
2776 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
2777 }
2778 }
2779 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002780 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02002781
2782 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
2783 // third argument
2784 if (!what_is_dict)
2785 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002786 }
2787 }
2788 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01002789 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002790
2791 if (tv == NULL)
2792 {
2793 if (argvars[2].v_type != VAR_UNKNOWN)
2794 copy_tv(&argvars[2], rettv);
2795 }
2796 else
2797 copy_tv(tv, rettv);
2798}
2799
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02002800/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002801 * "getchangelist()" function
2802 */
2803 static void
2804f_getchangelist(typval_T *argvars, typval_T *rettv)
2805{
2806#ifdef FEAT_JUMPLIST
2807 buf_T *buf;
2808 int i;
2809 list_T *l;
2810 dict_T *d;
2811#endif
2812
2813 if (rettv_list_alloc(rettv) != OK)
2814 return;
2815
2816#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02002817 if (argvars[0].v_type == VAR_UNKNOWN)
2818 buf = curbuf;
2819 else
2820 {
2821 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
2822 ++emsg_off;
2823 buf = tv_get_buf(&argvars[0], FALSE);
2824 --emsg_off;
2825 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002826 if (buf == NULL)
2827 return;
2828
2829 l = list_alloc();
2830 if (l == NULL)
2831 return;
2832
2833 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2834 return;
2835 /*
2836 * The current window change list index tracks only the position in the
2837 * current buffer change list. For other buffers, use the change list
2838 * length as the current index.
2839 */
2840 list_append_number(rettv->vval.v_list,
2841 (varnumber_T)((buf == curwin->w_buffer)
2842 ? curwin->w_changelistidx : buf->b_changelistlen));
2843
2844 for (i = 0; i < buf->b_changelistlen; ++i)
2845 {
2846 if (buf->b_changelist[i].lnum == 0)
2847 continue;
2848 if ((d = dict_alloc()) == NULL)
2849 return;
2850 if (list_append_dict(l, d) == FAIL)
2851 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002852 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
2853 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002854 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01002855 }
2856#endif
2857}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002858
2859/*
2860 * "getcharsearch()" function
2861 */
2862 static void
2863f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
2864{
2865 if (rettv_dict_alloc(rettv) != FAIL)
2866 {
2867 dict_T *dict = rettv->vval.v_dict;
2868
Bram Moolenaare0be1672018-07-08 16:50:37 +02002869 dict_add_string(dict, "char", last_csearch());
2870 dict_add_number(dict, "forward", last_csearch_forward());
2871 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002872 }
2873}
2874
2875/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002876 * "getcmdwintype()" function
2877 */
2878 static void
2879f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
2880{
2881 rettv->v_type = VAR_STRING;
2882 rettv->vval.v_string = NULL;
2883#ifdef FEAT_CMDWIN
2884 rettv->vval.v_string = alloc(2);
2885 if (rettv->vval.v_string != NULL)
2886 {
2887 rettv->vval.v_string[0] = cmdwin_type;
2888 rettv->vval.v_string[1] = NUL;
2889 }
2890#endif
2891}
2892
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002893/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002894 * "getenv()" function
2895 */
2896 static void
2897f_getenv(typval_T *argvars, typval_T *rettv)
2898{
2899 int mustfree = FALSE;
2900 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
2901
2902 if (p == NULL)
2903 {
2904 rettv->v_type = VAR_SPECIAL;
2905 rettv->vval.v_number = VVAL_NULL;
2906 return;
2907 }
2908 if (!mustfree)
2909 p = vim_strsave(p);
2910 rettv->vval.v_string = p;
2911 rettv->v_type = VAR_STRING;
2912}
2913
2914/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002915 * "getfontname()" function
2916 */
2917 static void
2918f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
2919{
2920 rettv->v_type = VAR_STRING;
2921 rettv->vval.v_string = NULL;
2922#ifdef FEAT_GUI
2923 if (gui.in_use)
2924 {
2925 GuiFont font;
2926 char_u *name = NULL;
2927
2928 if (argvars[0].v_type == VAR_UNKNOWN)
2929 {
2930 /* Get the "Normal" font. Either the name saved by
2931 * hl_set_font_name() or from the font ID. */
2932 font = gui.norm_font;
2933 name = hl_get_font_name();
2934 }
2935 else
2936 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002937 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002938 if (STRCMP(name, "*") == 0) /* don't use font dialog */
2939 return;
2940 font = gui_mch_get_font(name, FALSE);
2941 if (font == NOFONT)
2942 return; /* Invalid font name, return empty string. */
2943 }
2944 rettv->vval.v_string = gui_mch_get_fontname(font, name);
2945 if (argvars[0].v_type != VAR_UNKNOWN)
2946 gui_mch_free_font(font);
2947 }
2948#endif
2949}
2950
2951/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01002952 * "getjumplist()" function
2953 */
2954 static void
2955f_getjumplist(typval_T *argvars, typval_T *rettv)
2956{
2957#ifdef FEAT_JUMPLIST
2958 win_T *wp;
2959 int i;
2960 list_T *l;
2961 dict_T *d;
2962#endif
2963
2964 if (rettv_list_alloc(rettv) != OK)
2965 return;
2966
2967#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02002968 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002969 if (wp == NULL)
2970 return;
2971
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01002972 cleanup_jumplist(wp, TRUE);
2973
Bram Moolenaar4f505882018-02-10 21:06:32 +01002974 l = list_alloc();
2975 if (l == NULL)
2976 return;
2977
2978 if (list_append_list(rettv->vval.v_list, l) == FAIL)
2979 return;
2980 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
2981
2982 for (i = 0; i < wp->w_jumplistlen; ++i)
2983 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002984 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
2985 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01002986 if ((d = dict_alloc()) == NULL)
2987 return;
2988 if (list_append_dict(l, d) == FAIL)
2989 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02002990 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
2991 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002992 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02002993 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01002994 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02002995 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01002996 }
2997#endif
2998}
2999
3000/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003001 * "getpid()" function
3002 */
3003 static void
3004f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3005{
3006 rettv->vval.v_number = mch_get_pid();
3007}
3008
3009 static void
3010getpos_both(
3011 typval_T *argvars,
3012 typval_T *rettv,
3013 int getcurpos)
3014{
3015 pos_T *fp;
3016 list_T *l;
3017 int fnum = -1;
3018
3019 if (rettv_list_alloc(rettv) == OK)
3020 {
3021 l = rettv->vval.v_list;
3022 if (getcurpos)
3023 fp = &curwin->w_cursor;
3024 else
3025 fp = var2fpos(&argvars[0], TRUE, &fnum);
3026 if (fnum != -1)
3027 list_append_number(l, (varnumber_T)fnum);
3028 else
3029 list_append_number(l, (varnumber_T)0);
3030 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3031 : (varnumber_T)0);
3032 list_append_number(l, (fp != NULL)
3033 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3034 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003035 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 (varnumber_T)0);
3037 if (getcurpos)
3038 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01003039 int save_set_curswant = curwin->w_set_curswant;
3040 colnr_T save_curswant = curwin->w_curswant;
3041 colnr_T save_virtcol = curwin->w_virtcol;
3042
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003043 update_curswant();
3044 list_append_number(l, curwin->w_curswant == MAXCOL ?
3045 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01003046
3047 // Do not change "curswant", as it is unexpected that a get
3048 // function has a side effect.
3049 if (save_set_curswant)
3050 {
3051 curwin->w_set_curswant = save_set_curswant;
3052 curwin->w_curswant = save_curswant;
3053 curwin->w_virtcol = save_virtcol;
3054 curwin->w_valid &= ~VALID_VIRTCOL;
3055 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003056 }
3057 }
3058 else
3059 rettv->vval.v_number = FALSE;
3060}
3061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062/*
3063 * "getcurpos()" function
3064 */
3065 static void
3066f_getcurpos(typval_T *argvars, typval_T *rettv)
3067{
3068 getpos_both(argvars, rettv, TRUE);
3069}
3070
3071/*
3072 * "getpos(string)" function
3073 */
3074 static void
3075f_getpos(typval_T *argvars, typval_T *rettv)
3076{
3077 getpos_both(argvars, rettv, FALSE);
3078}
3079
3080/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003081 * "getreg()" function
3082 */
3083 static void
3084f_getreg(typval_T *argvars, typval_T *rettv)
3085{
3086 char_u *strregname;
3087 int regname;
3088 int arg2 = FALSE;
3089 int return_list = FALSE;
3090 int error = FALSE;
3091
3092 if (argvars[0].v_type != VAR_UNKNOWN)
3093 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003094 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003095 error = strregname == NULL;
3096 if (argvars[1].v_type != VAR_UNKNOWN)
3097 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003098 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003099 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003100 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003101 }
3102 }
3103 else
3104 strregname = get_vim_var_str(VV_REG);
3105
3106 if (error)
3107 return;
3108
3109 regname = (strregname == NULL ? '"' : *strregname);
3110 if (regname == 0)
3111 regname = '"';
3112
3113 if (return_list)
3114 {
3115 rettv->v_type = VAR_LIST;
3116 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
3117 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
3118 if (rettv->vval.v_list == NULL)
3119 (void)rettv_list_alloc(rettv);
3120 else
3121 ++rettv->vval.v_list->lv_refcount;
3122 }
3123 else
3124 {
3125 rettv->v_type = VAR_STRING;
3126 rettv->vval.v_string = get_reg_contents(regname,
3127 arg2 ? GREG_EXPR_SRC : 0);
3128 }
3129}
3130
3131/*
3132 * "getregtype()" function
3133 */
3134 static void
3135f_getregtype(typval_T *argvars, typval_T *rettv)
3136{
3137 char_u *strregname;
3138 int regname;
3139 char_u buf[NUMBUFLEN + 2];
3140 long reglen = 0;
3141
3142 if (argvars[0].v_type != VAR_UNKNOWN)
3143 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003144 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003145 if (strregname == NULL) /* type error; errmsg already given */
3146 {
3147 rettv->v_type = VAR_STRING;
3148 rettv->vval.v_string = NULL;
3149 return;
3150 }
3151 }
3152 else
3153 /* Default to v:register */
3154 strregname = get_vim_var_str(VV_REG);
3155
3156 regname = (strregname == NULL ? '"' : *strregname);
3157 if (regname == 0)
3158 regname = '"';
3159
3160 buf[0] = NUL;
3161 buf[1] = NUL;
3162 switch (get_reg_type(regname, &reglen))
3163 {
3164 case MLINE: buf[0] = 'V'; break;
3165 case MCHAR: buf[0] = 'v'; break;
3166 case MBLOCK:
3167 buf[0] = Ctrl_V;
3168 sprintf((char *)buf + 1, "%ld", reglen + 1);
3169 break;
3170 }
3171 rettv->v_type = VAR_STRING;
3172 rettv->vval.v_string = vim_strsave(buf);
3173}
3174
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003175/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01003176 * "gettagstack()" function
3177 */
3178 static void
3179f_gettagstack(typval_T *argvars, typval_T *rettv)
3180{
3181 win_T *wp = curwin; // default is current window
3182
3183 if (rettv_dict_alloc(rettv) != OK)
3184 return;
3185
3186 if (argvars[0].v_type != VAR_UNKNOWN)
3187 {
3188 wp = find_win_by_nr_or_id(&argvars[0]);
3189 if (wp == NULL)
3190 return;
3191 }
3192
3193 get_tagstack(wp, rettv->vval.v_dict);
3194}
3195
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003196/* for VIM_VERSION_ defines */
3197#include "version.h"
3198
3199/*
3200 * "has()" function
3201 */
3202 static void
3203f_has(typval_T *argvars, typval_T *rettv)
3204{
3205 int i;
3206 char_u *name;
3207 int n = FALSE;
3208 static char *(has_list[]) =
3209 {
3210#ifdef AMIGA
3211 "amiga",
3212# ifdef FEAT_ARP
3213 "arp",
3214# endif
3215#endif
3216#ifdef __BEOS__
3217 "beos",
3218#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003219#if defined(BSD) && !defined(MACOS_X)
3220 "bsd",
3221#endif
3222#ifdef hpux
3223 "hpux",
3224#endif
3225#ifdef __linux__
3226 "linux",
3227#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02003228#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01003229 "mac", /* Mac OS X (and, once, Mac OS Classic) */
3230 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02003231# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01003232 "macunix", /* Mac OS X, with the darwin feature */
3233 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02003234# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003235#endif
3236#ifdef __QNX__
3237 "qnx",
3238#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003239#ifdef SUN_SYSTEM
3240 "sun",
3241#else
3242 "moon",
3243#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003244#ifdef UNIX
3245 "unix",
3246#endif
3247#ifdef VMS
3248 "vms",
3249#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003250#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003251 "win32",
3252#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01003253#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003254 "win32unix",
3255#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01003256#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003257 "win64",
3258#endif
3259#ifdef EBCDIC
3260 "ebcdic",
3261#endif
3262#ifndef CASE_INSENSITIVE_FILENAME
3263 "fname_case",
3264#endif
3265#ifdef HAVE_ACL
3266 "acl",
3267#endif
3268#ifdef FEAT_ARABIC
3269 "arabic",
3270#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003271 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003272#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01003273 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02003274#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01003275#ifdef FEAT_AUTOSERVERNAME
3276 "autoservername",
3277#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003278#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003279 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01003280# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003281 "balloon_multiline",
3282# endif
3283#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01003284#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01003285 "balloon_eval_term",
3286#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003287#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
3288 "builtin_terms",
3289# ifdef ALL_BUILTIN_TCAPS
3290 "all_builtin_terms",
3291# endif
3292#endif
3293#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01003294 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003295 || defined(FEAT_GUI_MOTIF))
3296 "browsefilter",
3297#endif
3298#ifdef FEAT_BYTEOFF
3299 "byte_offset",
3300#endif
3301#ifdef FEAT_JOB_CHANNEL
3302 "channel",
3303#endif
3304#ifdef FEAT_CINDENT
3305 "cindent",
3306#endif
3307#ifdef FEAT_CLIENTSERVER
3308 "clientserver",
3309#endif
3310#ifdef FEAT_CLIPBOARD
3311 "clipboard",
3312#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003313 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003314 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003315#ifdef FEAT_COMMENTS
3316 "comments",
3317#endif
3318#ifdef FEAT_CONCEAL
3319 "conceal",
3320#endif
3321#ifdef FEAT_CRYPT
3322 "cryptv",
3323 "crypt-blowfish",
3324 "crypt-blowfish2",
3325#endif
3326#ifdef FEAT_CSCOPE
3327 "cscope",
3328#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003329 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003330#ifdef CURSOR_SHAPE
3331 "cursorshape",
3332#endif
3333#ifdef DEBUG
3334 "debug",
3335#endif
3336#ifdef FEAT_CON_DIALOG
3337 "dialog_con",
3338#endif
3339#ifdef FEAT_GUI_DIALOG
3340 "dialog_gui",
3341#endif
3342#ifdef FEAT_DIFF
3343 "diff",
3344#endif
3345#ifdef FEAT_DIGRAPHS
3346 "digraphs",
3347#endif
3348#ifdef FEAT_DIRECTX
3349 "directx",
3350#endif
3351#ifdef FEAT_DND
3352 "dnd",
3353#endif
3354#ifdef FEAT_EMACS_TAGS
3355 "emacs_tags",
3356#endif
3357 "eval", /* always present, of course! */
3358 "ex_extra", /* graduated feature */
3359#ifdef FEAT_SEARCH_EXTRA
3360 "extra_search",
3361#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003362#ifdef FEAT_SEARCHPATH
3363 "file_in_path",
3364#endif
3365#ifdef FEAT_FILTERPIPE
3366 "filterpipe",
3367#endif
3368#ifdef FEAT_FIND_ID
3369 "find_in_path",
3370#endif
3371#ifdef FEAT_FLOAT
3372 "float",
3373#endif
3374#ifdef FEAT_FOLDING
3375 "folding",
3376#endif
3377#ifdef FEAT_FOOTER
3378 "footer",
3379#endif
3380#if !defined(USE_SYSTEM) && defined(UNIX)
3381 "fork",
3382#endif
3383#ifdef FEAT_GETTEXT
3384 "gettext",
3385#endif
3386#ifdef FEAT_GUI
3387 "gui",
3388#endif
3389#ifdef FEAT_GUI_ATHENA
3390# ifdef FEAT_GUI_NEXTAW
3391 "gui_neXtaw",
3392# else
3393 "gui_athena",
3394# endif
3395#endif
3396#ifdef FEAT_GUI_GTK
3397 "gui_gtk",
3398# ifdef USE_GTK3
3399 "gui_gtk3",
3400# else
3401 "gui_gtk2",
3402# endif
3403#endif
3404#ifdef FEAT_GUI_GNOME
3405 "gui_gnome",
3406#endif
3407#ifdef FEAT_GUI_MAC
3408 "gui_mac",
3409#endif
3410#ifdef FEAT_GUI_MOTIF
3411 "gui_motif",
3412#endif
3413#ifdef FEAT_GUI_PHOTON
3414 "gui_photon",
3415#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003416#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003417 "gui_win32",
3418#endif
3419#ifdef FEAT_HANGULIN
3420 "hangul_input",
3421#endif
3422#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
3423 "iconv",
3424#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003425 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003426#ifdef FEAT_JOB_CHANNEL
3427 "job",
3428#endif
3429#ifdef FEAT_JUMPLIST
3430 "jumplist",
3431#endif
3432#ifdef FEAT_KEYMAP
3433 "keymap",
3434#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02003435 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003436#ifdef FEAT_LANGMAP
3437 "langmap",
3438#endif
3439#ifdef FEAT_LIBCALL
3440 "libcall",
3441#endif
3442#ifdef FEAT_LINEBREAK
3443 "linebreak",
3444#endif
3445#ifdef FEAT_LISP
3446 "lispindent",
3447#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003448 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003449 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003450#ifdef FEAT_LUA
3451# ifndef DYNAMIC_LUA
3452 "lua",
3453# endif
3454#endif
3455#ifdef FEAT_MENU
3456 "menu",
3457#endif
3458#ifdef FEAT_SESSION
3459 "mksession",
3460#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003461 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003462#ifdef FEAT_MOUSE
3463 "mouse",
3464#endif
3465#ifdef FEAT_MOUSESHAPE
3466 "mouseshape",
3467#endif
3468#if defined(UNIX) || defined(VMS)
3469# ifdef FEAT_MOUSE_DEC
3470 "mouse_dec",
3471# endif
3472# ifdef FEAT_MOUSE_GPM
3473 "mouse_gpm",
3474# endif
3475# ifdef FEAT_MOUSE_JSB
3476 "mouse_jsbterm",
3477# endif
3478# ifdef FEAT_MOUSE_NET
3479 "mouse_netterm",
3480# endif
3481# ifdef FEAT_MOUSE_PTERM
3482 "mouse_pterm",
3483# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01003484# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003485 "mouse_sgr",
3486# endif
3487# ifdef FEAT_SYSMOUSE
3488 "mouse_sysmouse",
3489# endif
3490# ifdef FEAT_MOUSE_URXVT
3491 "mouse_urxvt",
3492# endif
3493# ifdef FEAT_MOUSE_XTERM
3494 "mouse_xterm",
3495# endif
3496#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003497 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003498#ifdef FEAT_MBYTE_IME
3499 "multi_byte_ime",
3500#endif
3501#ifdef FEAT_MULTI_LANG
3502 "multi_lang",
3503#endif
3504#ifdef FEAT_MZSCHEME
3505#ifndef DYNAMIC_MZSCHEME
3506 "mzscheme",
3507#endif
3508#endif
3509#ifdef FEAT_NUM64
3510 "num64",
3511#endif
3512#ifdef FEAT_OLE
3513 "ole",
3514#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003515#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003516 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02003517#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003518#ifdef FEAT_PATH_EXTRA
3519 "path_extra",
3520#endif
3521#ifdef FEAT_PERL
3522#ifndef DYNAMIC_PERL
3523 "perl",
3524#endif
3525#endif
3526#ifdef FEAT_PERSISTENT_UNDO
3527 "persistent_undo",
3528#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003529#if defined(FEAT_PYTHON)
3530 "python_compiled",
3531# if defined(DYNAMIC_PYTHON)
3532 "python_dynamic",
3533# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003534 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003535 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003536# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003537#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003538#if defined(FEAT_PYTHON3)
3539 "python3_compiled",
3540# if defined(DYNAMIC_PYTHON3)
3541 "python3_dynamic",
3542# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003543 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003544 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01003545# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546#endif
3547#ifdef FEAT_POSTSCRIPT
3548 "postscript",
3549#endif
3550#ifdef FEAT_PRINTER
3551 "printer",
3552#endif
3553#ifdef FEAT_PROFILE
3554 "profile",
3555#endif
3556#ifdef FEAT_RELTIME
3557 "reltime",
3558#endif
3559#ifdef FEAT_QUICKFIX
3560 "quickfix",
3561#endif
3562#ifdef FEAT_RIGHTLEFT
3563 "rightleft",
3564#endif
3565#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
3566 "ruby",
3567#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003568 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003569#ifdef FEAT_CMDL_INFO
3570 "showcmd",
3571 "cmdline_info",
3572#endif
3573#ifdef FEAT_SIGNS
3574 "signs",
3575#endif
3576#ifdef FEAT_SMARTINDENT
3577 "smartindent",
3578#endif
3579#ifdef STARTUPTIME
3580 "startuptime",
3581#endif
3582#ifdef FEAT_STL_OPT
3583 "statusline",
3584#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003585#ifdef FEAT_NETBEANS_INTG
3586 "netbeans_intg",
3587#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02003588#ifdef FEAT_SOUND
3589 "sound",
3590#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003591#ifdef FEAT_SPELL
3592 "spell",
3593#endif
3594#ifdef FEAT_SYN_HL
3595 "syntax",
3596#endif
3597#if defined(USE_SYSTEM) || !defined(UNIX)
3598 "system",
3599#endif
3600#ifdef FEAT_TAG_BINS
3601 "tag_binary",
3602#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003603#ifdef FEAT_TCL
3604# ifndef DYNAMIC_TCL
3605 "tcl",
3606# endif
3607#endif
3608#ifdef FEAT_TERMGUICOLORS
3609 "termguicolors",
3610#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003611#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02003612 "terminal",
3613#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003614#ifdef TERMINFO
3615 "terminfo",
3616#endif
3617#ifdef FEAT_TERMRESPONSE
3618 "termresponse",
3619#endif
3620#ifdef FEAT_TEXTOBJ
3621 "textobjects",
3622#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01003623#ifdef FEAT_TEXT_PROP
3624 "textprop",
3625#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003626#ifdef HAVE_TGETENT
3627 "tgetent",
3628#endif
3629#ifdef FEAT_TIMERS
3630 "timers",
3631#endif
3632#ifdef FEAT_TITLE
3633 "title",
3634#endif
3635#ifdef FEAT_TOOLBAR
3636 "toolbar",
3637#endif
3638#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3639 "unnamedplus",
3640#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003641 "user-commands", /* was accidentally included in 5.4 */
3642 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02003643#ifdef FEAT_VARTABS
3644 "vartabs",
3645#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003646 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003647#ifdef FEAT_VIMINFO
3648 "viminfo",
3649#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02003650 "vimscript-1",
3651 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02003652 "vimscript-3",
Bram Moolenaaraf914382019-09-15 17:49:10 +02003653 "vimscript-4",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003654 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003655 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003656 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003657 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01003658#ifdef FEAT_VTP
3659 "vtp",
3660#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003661#ifdef FEAT_WILDIGN
3662 "wildignore",
3663#endif
3664#ifdef FEAT_WILDMENU
3665 "wildmenu",
3666#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003667 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003668#ifdef FEAT_WAK
3669 "winaltkeys",
3670#endif
3671#ifdef FEAT_WRITEBACKUP
3672 "writebackup",
3673#endif
3674#ifdef FEAT_XIM
3675 "xim",
3676#endif
3677#ifdef FEAT_XFONTSET
3678 "xfontset",
3679#endif
3680#ifdef FEAT_XPM_W32
3681 "xpm",
3682 "xpm_w32", /* for backward compatibility */
3683#else
3684# if defined(HAVE_XPM)
3685 "xpm",
3686# endif
3687#endif
3688#ifdef USE_XSMP
3689 "xsmp",
3690#endif
3691#ifdef USE_XSMP_INTERACT
3692 "xsmp_interact",
3693#endif
3694#ifdef FEAT_XCLIPBOARD
3695 "xterm_clipboard",
3696#endif
3697#ifdef FEAT_XTERM_SAVE
3698 "xterm_save",
3699#endif
3700#if defined(UNIX) && defined(FEAT_X11)
3701 "X11",
3702#endif
3703 NULL
3704 };
3705
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003706 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003707 for (i = 0; has_list[i] != NULL; ++i)
3708 if (STRICMP(name, has_list[i]) == 0)
3709 {
3710 n = TRUE;
3711 break;
3712 }
3713
3714 if (n == FALSE)
3715 {
3716 if (STRNICMP(name, "patch", 5) == 0)
3717 {
3718 if (name[5] == '-'
3719 && STRLEN(name) >= 11
3720 && vim_isdigit(name[6])
3721 && vim_isdigit(name[8])
3722 && vim_isdigit(name[10]))
3723 {
3724 int major = atoi((char *)name + 6);
3725 int minor = atoi((char *)name + 8);
3726
3727 /* Expect "patch-9.9.01234". */
3728 n = (major < VIM_VERSION_MAJOR
3729 || (major == VIM_VERSION_MAJOR
3730 && (minor < VIM_VERSION_MINOR
3731 || (minor == VIM_VERSION_MINOR
3732 && has_patch(atoi((char *)name + 10))))));
3733 }
3734 else
3735 n = has_patch(atoi((char *)name + 5));
3736 }
3737 else if (STRICMP(name, "vim_starting") == 0)
3738 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01003739 else if (STRICMP(name, "ttyin") == 0)
3740 n = mch_input_isatty();
3741 else if (STRICMP(name, "ttyout") == 0)
3742 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003743 else if (STRICMP(name, "multi_byte_encoding") == 0)
3744 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01003745#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003746 else if (STRICMP(name, "balloon_multiline") == 0)
3747 n = multiline_balloon_available();
3748#endif
3749#ifdef DYNAMIC_TCL
3750 else if (STRICMP(name, "tcl") == 0)
3751 n = tcl_enabled(FALSE);
3752#endif
3753#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
3754 else if (STRICMP(name, "iconv") == 0)
3755 n = iconv_enabled(FALSE);
3756#endif
3757#ifdef DYNAMIC_LUA
3758 else if (STRICMP(name, "lua") == 0)
3759 n = lua_enabled(FALSE);
3760#endif
3761#ifdef DYNAMIC_MZSCHEME
3762 else if (STRICMP(name, "mzscheme") == 0)
3763 n = mzscheme_enabled(FALSE);
3764#endif
3765#ifdef DYNAMIC_RUBY
3766 else if (STRICMP(name, "ruby") == 0)
3767 n = ruby_enabled(FALSE);
3768#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003769#ifdef DYNAMIC_PYTHON
3770 else if (STRICMP(name, "python") == 0)
3771 n = python_enabled(FALSE);
3772#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003773#ifdef DYNAMIC_PYTHON3
3774 else if (STRICMP(name, "python3") == 0)
3775 n = python3_enabled(FALSE);
3776#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01003777#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
3778 else if (STRICMP(name, "pythonx") == 0)
3779 {
3780# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
3781 if (p_pyx == 0)
3782 n = python3_enabled(FALSE) || python_enabled(FALSE);
3783 else if (p_pyx == 3)
3784 n = python3_enabled(FALSE);
3785 else if (p_pyx == 2)
3786 n = python_enabled(FALSE);
3787# elif defined(DYNAMIC_PYTHON)
3788 n = python_enabled(FALSE);
3789# elif defined(DYNAMIC_PYTHON3)
3790 n = python3_enabled(FALSE);
3791# endif
3792 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003793#endif
3794#ifdef DYNAMIC_PERL
3795 else if (STRICMP(name, "perl") == 0)
3796 n = perl_enabled(FALSE);
3797#endif
3798#ifdef FEAT_GUI
3799 else if (STRICMP(name, "gui_running") == 0)
3800 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003801# ifdef FEAT_BROWSE
3802 else if (STRICMP(name, "browse") == 0)
3803 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
3804# endif
3805#endif
3806#ifdef FEAT_SYN_HL
3807 else if (STRICMP(name, "syntax_items") == 0)
3808 n = syntax_present(curwin);
3809#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01003810#ifdef FEAT_VTP
3811 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02003812 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003813#endif
3814#ifdef FEAT_NETBEANS_INTG
3815 else if (STRICMP(name, "netbeans_enabled") == 0)
3816 n = netbeans_active();
3817#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02003818#ifdef FEAT_MOUSE_GPM
3819 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
3820 n = gpm_enabled();
3821#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003822#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02003823 else if (STRICMP(name, "terminal") == 0)
3824 n = terminal_enabled();
3825#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01003826#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01003827 else if (STRICMP(name, "conpty") == 0)
3828 n = use_conpty();
3829#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02003830#ifdef FEAT_CLIPBOARD
3831 else if (STRICMP(name, "clipboard_working") == 0)
3832 n = clip_star.available;
3833#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003834 }
3835
3836 rettv->vval.v_number = n;
3837}
3838
3839/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003840 * "haslocaldir()" function
3841 */
3842 static void
3843f_haslocaldir(typval_T *argvars, typval_T *rettv)
3844{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003845 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003846 win_T *wp = NULL;
3847
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003848 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
3849
3850 // Check for window-local and tab-local directories
3851 if (wp != NULL && wp->w_localdir != NULL)
3852 rettv->vval.v_number = 1;
3853 else if (tp != NULL && tp->tp_localdir != NULL)
3854 rettv->vval.v_number = 2;
3855 else
3856 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003857}
3858
3859/*
3860 * "hasmapto()" function
3861 */
3862 static void
3863f_hasmapto(typval_T *argvars, typval_T *rettv)
3864{
3865 char_u *name;
3866 char_u *mode;
3867 char_u buf[NUMBUFLEN];
3868 int abbr = FALSE;
3869
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003870 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003871 if (argvars[1].v_type == VAR_UNKNOWN)
3872 mode = (char_u *)"nvo";
3873 else
3874 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003875 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003876 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003877 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003878 }
3879
3880 if (map_to_exists(name, mode, abbr))
3881 rettv->vval.v_number = TRUE;
3882 else
3883 rettv->vval.v_number = FALSE;
3884}
3885
3886/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003887 * "highlightID(name)" function
3888 */
3889 static void
3890f_hlID(typval_T *argvars, typval_T *rettv)
3891{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003892 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003893}
3894
3895/*
3896 * "highlight_exists()" function
3897 */
3898 static void
3899f_hlexists(typval_T *argvars, typval_T *rettv)
3900{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003901 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003902}
3903
3904/*
3905 * "hostname()" function
3906 */
3907 static void
3908f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
3909{
3910 char_u hostname[256];
3911
3912 mch_get_host_name(hostname, 256);
3913 rettv->v_type = VAR_STRING;
3914 rettv->vval.v_string = vim_strsave(hostname);
3915}
3916
3917/*
3918 * iconv() function
3919 */
3920 static void
3921f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
3922{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003923 char_u buf1[NUMBUFLEN];
3924 char_u buf2[NUMBUFLEN];
3925 char_u *from, *to, *str;
3926 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003927
3928 rettv->v_type = VAR_STRING;
3929 rettv->vval.v_string = NULL;
3930
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003931 str = tv_get_string(&argvars[0]);
3932 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
3933 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003934 vimconv.vc_type = CONV_NONE;
3935 convert_setup(&vimconv, from, to);
3936
3937 /* If the encodings are equal, no conversion needed. */
3938 if (vimconv.vc_type == CONV_NONE)
3939 rettv->vval.v_string = vim_strsave(str);
3940 else
3941 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
3942
3943 convert_setup(&vimconv, NULL, NULL);
3944 vim_free(from);
3945 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003946}
3947
3948/*
3949 * "indent()" function
3950 */
3951 static void
3952f_indent(typval_T *argvars, typval_T *rettv)
3953{
3954 linenr_T lnum;
3955
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003956 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003957 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3958 rettv->vval.v_number = get_indent_lnum(lnum);
3959 else
3960 rettv->vval.v_number = -1;
3961}
3962
3963/*
3964 * "index()" function
3965 */
3966 static void
3967f_index(typval_T *argvars, typval_T *rettv)
3968{
3969 list_T *l;
3970 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003971 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003972 long idx = 0;
3973 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003974 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003975
3976 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003977 if (argvars[0].v_type == VAR_BLOB)
3978 {
3979 typval_T tv;
3980 int start = 0;
3981
3982 if (argvars[2].v_type != VAR_UNKNOWN)
3983 {
3984 start = tv_get_number_chk(&argvars[2], &error);
3985 if (error)
3986 return;
3987 }
3988 b = argvars[0].vval.v_blob;
3989 if (b == NULL)
3990 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01003991 if (start < 0)
3992 {
3993 start = blob_len(b) + start;
3994 if (start < 0)
3995 start = 0;
3996 }
3997
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003998 for (idx = start; idx < blob_len(b); ++idx)
3999 {
4000 tv.v_type = VAR_NUMBER;
4001 tv.vval.v_number = blob_get(b, idx);
4002 if (tv_equal(&tv, &argvars[1], ic, FALSE))
4003 {
4004 rettv->vval.v_number = idx;
4005 return;
4006 }
4007 }
4008 return;
4009 }
4010 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004011 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004012 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 return;
4014 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004015
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004016 l = argvars[0].vval.v_list;
4017 if (l != NULL)
4018 {
4019 item = l->lv_first;
4020 if (argvars[2].v_type != VAR_UNKNOWN)
4021 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004022 /* Start at specified item. Use the cached index that list_find()
4023 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004024 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004025 idx = l->lv_idx;
4026 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004027 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004028 if (error)
4029 item = NULL;
4030 }
4031
4032 for ( ; item != NULL; item = item->li_next, ++idx)
4033 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
4034 {
4035 rettv->vval.v_number = idx;
4036 break;
4037 }
4038 }
4039}
4040
4041static int inputsecret_flag = 0;
4042
4043/*
4044 * "input()" function
4045 * Also handles inputsecret() when inputsecret is set.
4046 */
4047 static void
4048f_input(typval_T *argvars, typval_T *rettv)
4049{
4050 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
4051}
4052
4053/*
4054 * "inputdialog()" function
4055 */
4056 static void
4057f_inputdialog(typval_T *argvars, typval_T *rettv)
4058{
4059#if defined(FEAT_GUI_TEXTDIALOG)
4060 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
4061 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
4062 {
4063 char_u *message;
4064 char_u buf[NUMBUFLEN];
4065 char_u *defstr = (char_u *)"";
4066
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004067 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004068 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004069 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004070 vim_strncpy(IObuff, defstr, IOSIZE - 1);
4071 else
4072 IObuff[0] = NUL;
4073 if (message != NULL && defstr != NULL
4074 && do_dialog(VIM_QUESTION, NULL, message,
4075 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
4076 rettv->vval.v_string = vim_strsave(IObuff);
4077 else
4078 {
4079 if (message != NULL && defstr != NULL
4080 && argvars[1].v_type != VAR_UNKNOWN
4081 && argvars[2].v_type != VAR_UNKNOWN)
4082 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004083 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004084 else
4085 rettv->vval.v_string = NULL;
4086 }
4087 rettv->v_type = VAR_STRING;
4088 }
4089 else
4090#endif
4091 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
4092}
4093
4094/*
4095 * "inputlist()" function
4096 */
4097 static void
4098f_inputlist(typval_T *argvars, typval_T *rettv)
4099{
4100 listitem_T *li;
4101 int selected;
4102 int mouse_used;
4103
4104#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02004105 /* While starting up, there is no place to enter text. When running tests
4106 * with --not-a-term we assume feedkeys() will be used. */
4107 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004108 return;
4109#endif
4110 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
4111 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004112 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004113 return;
4114 }
4115
4116 msg_start();
4117 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
4118 lines_left = Rows; /* avoid more prompt */
4119 msg_scroll = TRUE;
4120 msg_clr_eos();
4121
4122 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
4123 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004124 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004125 msg_putchar('\n');
4126 }
4127
4128 /* Ask for choice. */
4129 selected = prompt_for_number(&mouse_used);
4130 if (mouse_used)
4131 selected -= lines_left;
4132
4133 rettv->vval.v_number = selected;
4134}
4135
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004136static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
4137
4138/*
4139 * "inputrestore()" function
4140 */
4141 static void
4142f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
4143{
4144 if (ga_userinput.ga_len > 0)
4145 {
4146 --ga_userinput.ga_len;
4147 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
4148 + ga_userinput.ga_len);
4149 /* default return is zero == OK */
4150 }
4151 else if (p_verbose > 1)
4152 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01004153 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004154 rettv->vval.v_number = 1; /* Failed */
4155 }
4156}
4157
4158/*
4159 * "inputsave()" function
4160 */
4161 static void
4162f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
4163{
4164 /* Add an entry to the stack of typeahead storage. */
4165 if (ga_grow(&ga_userinput, 1) == OK)
4166 {
4167 save_typeahead((tasave_T *)(ga_userinput.ga_data)
4168 + ga_userinput.ga_len);
4169 ++ga_userinput.ga_len;
4170 /* default return is zero == OK */
4171 }
4172 else
4173 rettv->vval.v_number = 1; /* Failed */
4174}
4175
4176/*
4177 * "inputsecret()" function
4178 */
4179 static void
4180f_inputsecret(typval_T *argvars, typval_T *rettv)
4181{
4182 ++cmdline_star;
4183 ++inputsecret_flag;
4184 f_input(argvars, rettv);
4185 --cmdline_star;
4186 --inputsecret_flag;
4187}
4188
4189/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004190 * "invert(expr)" function
4191 */
4192 static void
4193f_invert(typval_T *argvars, typval_T *rettv)
4194{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004195 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004196}
4197
4198/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004199 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
4200 * or it refers to a List or Dictionary that is locked.
4201 */
4202 static int
4203tv_islocked(typval_T *tv)
4204{
4205 return (tv->v_lock & VAR_LOCKED)
4206 || (tv->v_type == VAR_LIST
4207 && tv->vval.v_list != NULL
4208 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
4209 || (tv->v_type == VAR_DICT
4210 && tv->vval.v_dict != NULL
4211 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
4212}
4213
4214/*
4215 * "islocked()" function
4216 */
4217 static void
4218f_islocked(typval_T *argvars, typval_T *rettv)
4219{
4220 lval_T lv;
4221 char_u *end;
4222 dictitem_T *di;
4223
4224 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004225 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01004226 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004227 if (end != NULL && lv.ll_name != NULL)
4228 {
4229 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004230 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004231 else
4232 {
4233 if (lv.ll_tv == NULL)
4234 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004235 di = find_var(lv.ll_name, NULL, TRUE);
4236 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004237 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01004238 /* Consider a variable locked when:
4239 * 1. the variable itself is locked
4240 * 2. the value of the variable is locked.
4241 * 3. the List or Dict value is locked.
4242 */
4243 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
4244 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004245 }
4246 }
4247 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004248 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004249 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004250 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004251 else if (lv.ll_list != NULL)
4252 /* List item. */
4253 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
4254 else
4255 /* Dictionary item. */
4256 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
4257 }
4258 }
4259
4260 clear_lval(&lv);
4261}
4262
4263#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
4264/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02004265 * "isinf()" function
4266 */
4267 static void
4268f_isinf(typval_T *argvars, typval_T *rettv)
4269{
4270 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
4271 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
4272}
4273
4274/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004275 * "isnan()" function
4276 */
4277 static void
4278f_isnan(typval_T *argvars, typval_T *rettv)
4279{
4280 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
4281 && isnan(argvars[0].vval.v_float);
4282}
4283#endif
4284
4285/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004286 * "last_buffer_nr()" function.
4287 */
4288 static void
4289f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
4290{
4291 int n = 0;
4292 buf_T *buf;
4293
Bram Moolenaar29323592016-07-24 22:04:11 +02004294 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004295 if (n < buf->b_fnum)
4296 n = buf->b_fnum;
4297
4298 rettv->vval.v_number = n;
4299}
4300
4301/*
4302 * "len()" function
4303 */
4304 static void
4305f_len(typval_T *argvars, typval_T *rettv)
4306{
4307 switch (argvars[0].v_type)
4308 {
4309 case VAR_STRING:
4310 case VAR_NUMBER:
4311 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004312 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004313 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004314 case VAR_BLOB:
4315 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
4316 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004317 case VAR_LIST:
4318 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
4319 break;
4320 case VAR_DICT:
4321 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
4322 break;
4323 case VAR_UNKNOWN:
4324 case VAR_SPECIAL:
4325 case VAR_FLOAT:
4326 case VAR_FUNC:
4327 case VAR_PARTIAL:
4328 case VAR_JOB:
4329 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004330 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004331 break;
4332 }
4333}
4334
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004335 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01004336libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004337{
4338#ifdef FEAT_LIBCALL
4339 char_u *string_in;
4340 char_u **string_result;
4341 int nr_result;
4342#endif
4343
4344 rettv->v_type = type;
4345 if (type != VAR_NUMBER)
4346 rettv->vval.v_string = NULL;
4347
4348 if (check_restricted() || check_secure())
4349 return;
4350
4351#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02004352 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004353 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
4354 {
4355 string_in = NULL;
4356 if (argvars[2].v_type == VAR_STRING)
4357 string_in = argvars[2].vval.v_string;
4358 if (type == VAR_NUMBER)
4359 string_result = NULL;
4360 else
4361 string_result = &rettv->vval.v_string;
4362 if (mch_libcall(argvars[0].vval.v_string,
4363 argvars[1].vval.v_string,
4364 string_in,
4365 argvars[2].vval.v_number,
4366 string_result,
4367 &nr_result) == OK
4368 && type == VAR_NUMBER)
4369 rettv->vval.v_number = nr_result;
4370 }
4371#endif
4372}
4373
4374/*
4375 * "libcall()" function
4376 */
4377 static void
4378f_libcall(typval_T *argvars, typval_T *rettv)
4379{
4380 libcall_common(argvars, rettv, VAR_STRING);
4381}
4382
4383/*
4384 * "libcallnr()" function
4385 */
4386 static void
4387f_libcallnr(typval_T *argvars, typval_T *rettv)
4388{
4389 libcall_common(argvars, rettv, VAR_NUMBER);
4390}
4391
4392/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004393 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004394 */
4395 static void
4396f_line(typval_T *argvars, typval_T *rettv)
4397{
4398 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004399 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004400 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004401 int id;
4402 tabpage_T *tp;
4403 win_T *wp;
4404 win_T *save_curwin;
4405 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004406
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02004407 if (argvars[1].v_type != VAR_UNKNOWN)
4408 {
4409 // use window specified in the second argument
4410 id = (int)tv_get_number(&argvars[1]);
4411 wp = win_id2wp_tp(id, &tp);
4412 if (wp != NULL && tp != NULL)
4413 {
4414 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
4415 == OK)
4416 {
4417 check_cursor();
4418 fp = var2fpos(&argvars[0], TRUE, &fnum);
4419 }
4420 restore_win_noblock(save_curwin, save_curtab, TRUE);
4421 }
4422 }
4423 else
4424 // use current window
4425 fp = var2fpos(&argvars[0], TRUE, &fnum);
4426
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004427 if (fp != NULL)
4428 lnum = fp->lnum;
4429 rettv->vval.v_number = lnum;
4430}
4431
4432/*
4433 * "line2byte(lnum)" function
4434 */
4435 static void
4436f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
4437{
4438#ifndef FEAT_BYTEOFF
4439 rettv->vval.v_number = -1;
4440#else
4441 linenr_T lnum;
4442
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004443 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004444 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
4445 rettv->vval.v_number = -1;
4446 else
4447 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
4448 if (rettv->vval.v_number >= 0)
4449 ++rettv->vval.v_number;
4450#endif
4451}
4452
4453/*
4454 * "lispindent(lnum)" function
4455 */
4456 static void
4457f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
4458{
4459#ifdef FEAT_LISP
4460 pos_T pos;
4461 linenr_T lnum;
4462
4463 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004464 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004465 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4466 {
4467 curwin->w_cursor.lnum = lnum;
4468 rettv->vval.v_number = get_lisp_indent();
4469 curwin->w_cursor = pos;
4470 }
4471 else
4472#endif
4473 rettv->vval.v_number = -1;
4474}
4475
4476/*
4477 * "localtime()" function
4478 */
4479 static void
4480f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
4481{
4482 rettv->vval.v_number = (varnumber_T)time(NULL);
4483}
4484
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004485#ifdef FEAT_FLOAT
4486/*
4487 * "log()" function
4488 */
4489 static void
4490f_log(typval_T *argvars, typval_T *rettv)
4491{
4492 float_T f = 0.0;
4493
4494 rettv->v_type = VAR_FLOAT;
4495 if (get_float_arg(argvars, &f) == OK)
4496 rettv->vval.v_float = log(f);
4497 else
4498 rettv->vval.v_float = 0.0;
4499}
4500
4501/*
4502 * "log10()" function
4503 */
4504 static void
4505f_log10(typval_T *argvars, typval_T *rettv)
4506{
4507 float_T f = 0.0;
4508
4509 rettv->v_type = VAR_FLOAT;
4510 if (get_float_arg(argvars, &f) == OK)
4511 rettv->vval.v_float = log10(f);
4512 else
4513 rettv->vval.v_float = 0.0;
4514}
4515#endif
4516
4517#ifdef FEAT_LUA
4518/*
4519 * "luaeval()" function
4520 */
4521 static void
4522f_luaeval(typval_T *argvars, typval_T *rettv)
4523{
4524 char_u *str;
4525 char_u buf[NUMBUFLEN];
4526
Bram Moolenaar8c62a082019-02-08 14:34:10 +01004527 if (check_restricted() || check_secure())
4528 return;
4529
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004530 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004531 do_luaeval(str, argvars + 1, rettv);
4532}
4533#endif
4534
4535/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004536 * "maparg()" function
4537 */
4538 static void
4539f_maparg(typval_T *argvars, typval_T *rettv)
4540{
4541 get_maparg(argvars, rettv, TRUE);
4542}
4543
4544/*
4545 * "mapcheck()" function
4546 */
4547 static void
4548f_mapcheck(typval_T *argvars, typval_T *rettv)
4549{
4550 get_maparg(argvars, rettv, FALSE);
4551}
4552
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004553typedef enum
4554{
4555 MATCH_END, /* matchend() */
4556 MATCH_MATCH, /* match() */
4557 MATCH_STR, /* matchstr() */
4558 MATCH_LIST, /* matchlist() */
4559 MATCH_POS /* matchstrpos() */
4560} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004561
4562 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004563find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004564{
4565 char_u *str = NULL;
4566 long len = 0;
4567 char_u *expr = NULL;
4568 char_u *pat;
4569 regmatch_T regmatch;
4570 char_u patbuf[NUMBUFLEN];
4571 char_u strbuf[NUMBUFLEN];
4572 char_u *save_cpo;
4573 long start = 0;
4574 long nth = 1;
4575 colnr_T startcol = 0;
4576 int match = 0;
4577 list_T *l = NULL;
4578 listitem_T *li = NULL;
4579 long idx = 0;
4580 char_u *tofree = NULL;
4581
4582 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
4583 save_cpo = p_cpo;
4584 p_cpo = (char_u *)"";
4585
4586 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004587 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004588 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004589 /* type MATCH_LIST: return empty list when there are no matches.
4590 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004591 if (rettv_list_alloc(rettv) == FAIL)
4592 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004593 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004594 && (list_append_string(rettv->vval.v_list,
4595 (char_u *)"", 0) == FAIL
4596 || list_append_number(rettv->vval.v_list,
4597 (varnumber_T)-1) == FAIL
4598 || list_append_number(rettv->vval.v_list,
4599 (varnumber_T)-1) == FAIL
4600 || list_append_number(rettv->vval.v_list,
4601 (varnumber_T)-1) == FAIL))
4602 {
4603 list_free(rettv->vval.v_list);
4604 rettv->vval.v_list = NULL;
4605 goto theend;
4606 }
4607 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004608 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004609 {
4610 rettv->v_type = VAR_STRING;
4611 rettv->vval.v_string = NULL;
4612 }
4613
4614 if (argvars[0].v_type == VAR_LIST)
4615 {
4616 if ((l = argvars[0].vval.v_list) == NULL)
4617 goto theend;
4618 li = l->lv_first;
4619 }
4620 else
4621 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004622 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004623 len = (long)STRLEN(str);
4624 }
4625
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004626 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004627 if (pat == NULL)
4628 goto theend;
4629
4630 if (argvars[2].v_type != VAR_UNKNOWN)
4631 {
4632 int error = FALSE;
4633
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004634 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004635 if (error)
4636 goto theend;
4637 if (l != NULL)
4638 {
4639 li = list_find(l, start);
4640 if (li == NULL)
4641 goto theend;
4642 idx = l->lv_idx; /* use the cached index */
4643 }
4644 else
4645 {
4646 if (start < 0)
4647 start = 0;
4648 if (start > len)
4649 goto theend;
4650 /* When "count" argument is there ignore matches before "start",
4651 * otherwise skip part of the string. Differs when pattern is "^"
4652 * or "\<". */
4653 if (argvars[3].v_type != VAR_UNKNOWN)
4654 startcol = start;
4655 else
4656 {
4657 str += start;
4658 len -= start;
4659 }
4660 }
4661
4662 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004663 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004664 if (error)
4665 goto theend;
4666 }
4667
4668 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
4669 if (regmatch.regprog != NULL)
4670 {
4671 regmatch.rm_ic = p_ic;
4672
4673 for (;;)
4674 {
4675 if (l != NULL)
4676 {
4677 if (li == NULL)
4678 {
4679 match = FALSE;
4680 break;
4681 }
4682 vim_free(tofree);
4683 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
4684 if (str == NULL)
4685 break;
4686 }
4687
4688 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
4689
4690 if (match && --nth <= 0)
4691 break;
4692 if (l == NULL && !match)
4693 break;
4694
4695 /* Advance to just after the match. */
4696 if (l != NULL)
4697 {
4698 li = li->li_next;
4699 ++idx;
4700 }
4701 else
4702 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004703 startcol = (colnr_T)(regmatch.startp[0]
4704 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004705 if (startcol > (colnr_T)len
4706 || str + startcol <= regmatch.startp[0])
4707 {
4708 match = FALSE;
4709 break;
4710 }
4711 }
4712 }
4713
4714 if (match)
4715 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004716 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004717 {
4718 listitem_T *li1 = rettv->vval.v_list->lv_first;
4719 listitem_T *li2 = li1->li_next;
4720 listitem_T *li3 = li2->li_next;
4721 listitem_T *li4 = li3->li_next;
4722
4723 vim_free(li1->li_tv.vval.v_string);
4724 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
4725 (int)(regmatch.endp[0] - regmatch.startp[0]));
4726 li3->li_tv.vval.v_number =
4727 (varnumber_T)(regmatch.startp[0] - expr);
4728 li4->li_tv.vval.v_number =
4729 (varnumber_T)(regmatch.endp[0] - expr);
4730 if (l != NULL)
4731 li2->li_tv.vval.v_number = (varnumber_T)idx;
4732 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004733 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 {
4735 int i;
4736
4737 /* return list with matched string and submatches */
4738 for (i = 0; i < NSUBEXP; ++i)
4739 {
4740 if (regmatch.endp[i] == NULL)
4741 {
4742 if (list_append_string(rettv->vval.v_list,
4743 (char_u *)"", 0) == FAIL)
4744 break;
4745 }
4746 else if (list_append_string(rettv->vval.v_list,
4747 regmatch.startp[i],
4748 (int)(regmatch.endp[i] - regmatch.startp[i]))
4749 == FAIL)
4750 break;
4751 }
4752 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004753 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004754 {
4755 /* return matched string */
4756 if (l != NULL)
4757 copy_tv(&li->li_tv, rettv);
4758 else
4759 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
4760 (int)(regmatch.endp[0] - regmatch.startp[0]));
4761 }
4762 else if (l != NULL)
4763 rettv->vval.v_number = idx;
4764 else
4765 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004766 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004767 rettv->vval.v_number =
4768 (varnumber_T)(regmatch.startp[0] - str);
4769 else
4770 rettv->vval.v_number =
4771 (varnumber_T)(regmatch.endp[0] - str);
4772 rettv->vval.v_number += (varnumber_T)(str - expr);
4773 }
4774 }
4775 vim_regfree(regmatch.regprog);
4776 }
4777
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004778theend:
4779 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004780 /* matchstrpos() without a list: drop the second item. */
4781 listitem_remove(rettv->vval.v_list,
4782 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004783 vim_free(tofree);
4784 p_cpo = save_cpo;
4785}
4786
4787/*
4788 * "match()" function
4789 */
4790 static void
4791f_match(typval_T *argvars, typval_T *rettv)
4792{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004793 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004794}
4795
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004796/*
4797 * "matchend()" function
4798 */
4799 static void
4800f_matchend(typval_T *argvars, typval_T *rettv)
4801{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004802 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004803}
4804
4805/*
4806 * "matchlist()" function
4807 */
4808 static void
4809f_matchlist(typval_T *argvars, typval_T *rettv)
4810{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004811 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004812}
4813
4814/*
4815 * "matchstr()" function
4816 */
4817 static void
4818f_matchstr(typval_T *argvars, typval_T *rettv)
4819{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004820 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004821}
4822
4823/*
4824 * "matchstrpos()" function
4825 */
4826 static void
4827f_matchstrpos(typval_T *argvars, typval_T *rettv)
4828{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02004829 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004830}
4831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004832 static void
4833max_min(typval_T *argvars, typval_T *rettv, int domax)
4834{
4835 varnumber_T n = 0;
4836 varnumber_T i;
4837 int error = FALSE;
4838
4839 if (argvars[0].v_type == VAR_LIST)
4840 {
4841 list_T *l;
4842 listitem_T *li;
4843
4844 l = argvars[0].vval.v_list;
4845 if (l != NULL)
4846 {
4847 li = l->lv_first;
4848 if (li != NULL)
4849 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004850 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004851 for (;;)
4852 {
4853 li = li->li_next;
4854 if (li == NULL)
4855 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004856 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004857 if (domax ? i > n : i < n)
4858 n = i;
4859 }
4860 }
4861 }
4862 }
4863 else if (argvars[0].v_type == VAR_DICT)
4864 {
4865 dict_T *d;
4866 int first = TRUE;
4867 hashitem_T *hi;
4868 int todo;
4869
4870 d = argvars[0].vval.v_dict;
4871 if (d != NULL)
4872 {
4873 todo = (int)d->dv_hashtab.ht_used;
4874 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
4875 {
4876 if (!HASHITEM_EMPTY(hi))
4877 {
4878 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004879 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004880 if (first)
4881 {
4882 n = i;
4883 first = FALSE;
4884 }
4885 else if (domax ? i > n : i < n)
4886 n = i;
4887 }
4888 }
4889 }
4890 }
4891 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004892 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004893 rettv->vval.v_number = error ? 0 : n;
4894}
4895
4896/*
4897 * "max()" function
4898 */
4899 static void
4900f_max(typval_T *argvars, typval_T *rettv)
4901{
4902 max_min(argvars, rettv, TRUE);
4903}
4904
4905/*
4906 * "min()" function
4907 */
4908 static void
4909f_min(typval_T *argvars, typval_T *rettv)
4910{
4911 max_min(argvars, rettv, FALSE);
4912}
4913
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004914/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915 * "mode()" function
4916 */
4917 static void
4918f_mode(typval_T *argvars, typval_T *rettv)
4919{
Bram Moolenaar612cc382018-07-29 15:34:26 +02004920 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004921
Bram Moolenaar612cc382018-07-29 15:34:26 +02004922 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004923
4924 if (time_for_testing == 93784)
4925 {
4926 /* Testing the two-character code. */
4927 buf[0] = 'x';
4928 buf[1] = '!';
4929 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02004930#ifdef FEAT_TERMINAL
4931 else if (term_use_loop())
4932 buf[0] = 't';
4933#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004934 else if (VIsual_active)
4935 {
4936 if (VIsual_select)
4937 buf[0] = VIsual_mode + 's' - 'v';
4938 else
4939 buf[0] = VIsual_mode;
4940 }
4941 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
4942 || State == CONFIRM)
4943 {
4944 buf[0] = 'r';
4945 if (State == ASKMORE)
4946 buf[1] = 'm';
4947 else if (State == CONFIRM)
4948 buf[1] = '?';
4949 }
4950 else if (State == EXTERNCMD)
4951 buf[0] = '!';
4952 else if (State & INSERT)
4953 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004954 if (State & VREPLACE_FLAG)
4955 {
4956 buf[0] = 'R';
4957 buf[1] = 'v';
4958 }
4959 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01004960 {
4961 if (State & REPLACE_FLAG)
4962 buf[0] = 'R';
4963 else
4964 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01004965 if (ins_compl_active())
4966 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01004967 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01004968 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01004969 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004970 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01004971 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004972 {
4973 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01004974 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004975 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01004976 else if (exmode_active == EXMODE_NORMAL)
4977 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004978 }
4979 else
4980 {
4981 buf[0] = 'n';
4982 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01004983 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004984 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01004985 // to be able to detect force-linewise/blockwise/characterwise operations
4986 buf[2] = motion_force;
4987 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02004988 else if (restart_edit == 'I' || restart_edit == 'R'
4989 || restart_edit == 'V')
4990 {
4991 buf[1] = 'i';
4992 buf[2] = restart_edit;
4993 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004994 }
4995
4996 /* Clear out the minor mode when the argument is not a non-zero number or
4997 * non-empty string. */
4998 if (!non_zero_arg(&argvars[0]))
4999 buf[1] = NUL;
5000
5001 rettv->vval.v_string = vim_strsave(buf);
5002 rettv->v_type = VAR_STRING;
5003}
5004
5005#if defined(FEAT_MZSCHEME) || defined(PROTO)
5006/*
5007 * "mzeval()" function
5008 */
5009 static void
5010f_mzeval(typval_T *argvars, typval_T *rettv)
5011{
5012 char_u *str;
5013 char_u buf[NUMBUFLEN];
5014
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005015 if (check_restricted() || check_secure())
5016 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005017 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005018 do_mzeval(str, rettv);
5019}
5020
5021 void
5022mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
5023{
5024 typval_T argvars[3];
5025
5026 argvars[0].v_type = VAR_STRING;
5027 argvars[0].vval.v_string = name;
5028 copy_tv(args, &argvars[1]);
5029 argvars[2].v_type = VAR_UNKNOWN;
5030 f_call(argvars, rettv);
5031 clear_tv(&argvars[1]);
5032}
5033#endif
5034
5035/*
5036 * "nextnonblank()" function
5037 */
5038 static void
5039f_nextnonblank(typval_T *argvars, typval_T *rettv)
5040{
5041 linenr_T lnum;
5042
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005043 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005044 {
5045 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
5046 {
5047 lnum = 0;
5048 break;
5049 }
5050 if (*skipwhite(ml_get(lnum)) != NUL)
5051 break;
5052 }
5053 rettv->vval.v_number = lnum;
5054}
5055
5056/*
5057 * "nr2char()" function
5058 */
5059 static void
5060f_nr2char(typval_T *argvars, typval_T *rettv)
5061{
5062 char_u buf[NUMBUFLEN];
5063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005064 if (has_mbyte)
5065 {
5066 int utf8 = 0;
5067
5068 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005069 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005070 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01005071 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005072 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005073 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005074 }
5075 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005076 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005077 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005078 buf[1] = NUL;
5079 }
5080 rettv->v_type = VAR_STRING;
5081 rettv->vval.v_string = vim_strsave(buf);
5082}
5083
5084/*
5085 * "or(expr, expr)" function
5086 */
5087 static void
5088f_or(typval_T *argvars, typval_T *rettv)
5089{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005090 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
5091 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005092}
5093
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005094#ifdef FEAT_PERL
5095/*
5096 * "perleval()" function
5097 */
5098 static void
5099f_perleval(typval_T *argvars, typval_T *rettv)
5100{
5101 char_u *str;
5102 char_u buf[NUMBUFLEN];
5103
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005104 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105 do_perleval(str, rettv);
5106}
5107#endif
5108
5109#ifdef FEAT_FLOAT
5110/*
5111 * "pow()" function
5112 */
5113 static void
5114f_pow(typval_T *argvars, typval_T *rettv)
5115{
5116 float_T fx = 0.0, fy = 0.0;
5117
5118 rettv->v_type = VAR_FLOAT;
5119 if (get_float_arg(argvars, &fx) == OK
5120 && get_float_arg(&argvars[1], &fy) == OK)
5121 rettv->vval.v_float = pow(fx, fy);
5122 else
5123 rettv->vval.v_float = 0.0;
5124}
5125#endif
5126
5127/*
5128 * "prevnonblank()" function
5129 */
5130 static void
5131f_prevnonblank(typval_T *argvars, typval_T *rettv)
5132{
5133 linenr_T lnum;
5134
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005135 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005136 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
5137 lnum = 0;
5138 else
5139 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
5140 --lnum;
5141 rettv->vval.v_number = lnum;
5142}
5143
5144/* This dummy va_list is here because:
5145 * - passing a NULL pointer doesn't work when va_list isn't a pointer
5146 * - locally in the function results in a "used before set" warning
5147 * - using va_start() to initialize it gives "function with fixed args" error */
5148static va_list ap;
5149
5150/*
5151 * "printf()" function
5152 */
5153 static void
5154f_printf(typval_T *argvars, typval_T *rettv)
5155{
5156 char_u buf[NUMBUFLEN];
5157 int len;
5158 char_u *s;
5159 int saved_did_emsg = did_emsg;
5160 char *fmt;
5161
5162 rettv->v_type = VAR_STRING;
5163 rettv->vval.v_string = NULL;
5164
5165 /* Get the required length, allocate the buffer and do it for real. */
5166 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005167 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005168 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005169 if (!did_emsg)
5170 {
5171 s = alloc(len + 1);
5172 if (s != NULL)
5173 {
5174 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02005175 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
5176 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005177 }
5178 }
5179 did_emsg |= saved_did_emsg;
5180}
5181
5182/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005183 * "pum_getpos()" function
5184 */
5185 static void
5186f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5187{
5188 if (rettv_dict_alloc(rettv) != OK)
5189 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005190 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02005191}
5192
5193/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005194 * "pumvisible()" function
5195 */
5196 static void
5197f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5198{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 if (pum_visible())
5200 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201}
5202
5203#ifdef FEAT_PYTHON3
5204/*
5205 * "py3eval()" function
5206 */
5207 static void
5208f_py3eval(typval_T *argvars, typval_T *rettv)
5209{
5210 char_u *str;
5211 char_u buf[NUMBUFLEN];
5212
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005213 if (check_restricted() || check_secure())
5214 return;
5215
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005216 if (p_pyx == 0)
5217 p_pyx = 3;
5218
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005219 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005220 do_py3eval(str, rettv);
5221}
5222#endif
5223
5224#ifdef FEAT_PYTHON
5225/*
5226 * "pyeval()" function
5227 */
5228 static void
5229f_pyeval(typval_T *argvars, typval_T *rettv)
5230{
5231 char_u *str;
5232 char_u buf[NUMBUFLEN];
5233
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005234 if (check_restricted() || check_secure())
5235 return;
5236
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005237 if (p_pyx == 0)
5238 p_pyx = 2;
5239
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005240 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005241 do_pyeval(str, rettv);
5242}
5243#endif
5244
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005245#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
5246/*
5247 * "pyxeval()" function
5248 */
5249 static void
5250f_pyxeval(typval_T *argvars, typval_T *rettv)
5251{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005252 if (check_restricted() || check_secure())
5253 return;
5254
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005255# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
5256 init_pyxversion();
5257 if (p_pyx == 2)
5258 f_pyeval(argvars, rettv);
5259 else
5260 f_py3eval(argvars, rettv);
5261# elif defined(FEAT_PYTHON)
5262 f_pyeval(argvars, rettv);
5263# elif defined(FEAT_PYTHON3)
5264 f_py3eval(argvars, rettv);
5265# endif
5266}
5267#endif
5268
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005269/*
5270 * "range()" function
5271 */
5272 static void
5273f_range(typval_T *argvars, typval_T *rettv)
5274{
5275 varnumber_T start;
5276 varnumber_T end;
5277 varnumber_T stride = 1;
5278 varnumber_T i;
5279 int error = FALSE;
5280
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005281 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005282 if (argvars[1].v_type == VAR_UNKNOWN)
5283 {
5284 end = start - 1;
5285 start = 0;
5286 }
5287 else
5288 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005289 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005290 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005291 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 }
5293
5294 if (error)
5295 return; /* type error; errmsg already given */
5296 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005297 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005299 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005300 else
5301 {
5302 if (rettv_list_alloc(rettv) == OK)
5303 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
5304 if (list_append_number(rettv->vval.v_list,
5305 (varnumber_T)i) == FAIL)
5306 break;
5307 }
5308}
5309
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02005310 static void
5311return_register(int regname, typval_T *rettv)
5312{
5313 char_u buf[2] = {0, 0};
5314
5315 buf[0] = (char_u)regname;
5316 rettv->v_type = VAR_STRING;
5317 rettv->vval.v_string = vim_strsave(buf);
5318}
5319
5320/*
5321 * "reg_executing()" function
5322 */
5323 static void
5324f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
5325{
5326 return_register(reg_executing, rettv);
5327}
5328
5329/*
5330 * "reg_recording()" function
5331 */
5332 static void
5333f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
5334{
5335 return_register(reg_recording, rettv);
5336}
5337
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005338#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005339/*
5340 * Convert a List to proftime_T.
5341 * Return FAIL when there is something wrong.
5342 */
5343 static int
5344list2proftime(typval_T *arg, proftime_T *tm)
5345{
5346 long n1, n2;
5347 int error = FALSE;
5348
5349 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
5350 || arg->vval.v_list->lv_len != 2)
5351 return FAIL;
5352 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
5353 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005354# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005355 tm->HighPart = n1;
5356 tm->LowPart = n2;
5357# else
5358 tm->tv_sec = n1;
5359 tm->tv_usec = n2;
5360# endif
5361 return error ? FAIL : OK;
5362}
5363#endif /* FEAT_RELTIME */
5364
5365/*
5366 * "reltime()" function
5367 */
5368 static void
5369f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5370{
5371#ifdef FEAT_RELTIME
5372 proftime_T res;
5373 proftime_T start;
5374
5375 if (argvars[0].v_type == VAR_UNKNOWN)
5376 {
5377 /* No arguments: get current time. */
5378 profile_start(&res);
5379 }
5380 else if (argvars[1].v_type == VAR_UNKNOWN)
5381 {
5382 if (list2proftime(&argvars[0], &res) == FAIL)
5383 return;
5384 profile_end(&res);
5385 }
5386 else
5387 {
5388 /* Two arguments: compute the difference. */
5389 if (list2proftime(&argvars[0], &start) == FAIL
5390 || list2proftime(&argvars[1], &res) == FAIL)
5391 return;
5392 profile_sub(&res, &start);
5393 }
5394
5395 if (rettv_list_alloc(rettv) == OK)
5396 {
5397 long n1, n2;
5398
Bram Moolenaar4f974752019-02-17 17:44:42 +01005399# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005400 n1 = res.HighPart;
5401 n2 = res.LowPart;
5402# else
5403 n1 = res.tv_sec;
5404 n2 = res.tv_usec;
5405# endif
5406 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
5407 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
5408 }
5409#endif
5410}
5411
5412#ifdef FEAT_FLOAT
5413/*
5414 * "reltimefloat()" function
5415 */
5416 static void
5417f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
5418{
5419# ifdef FEAT_RELTIME
5420 proftime_T tm;
5421# endif
5422
5423 rettv->v_type = VAR_FLOAT;
5424 rettv->vval.v_float = 0;
5425# ifdef FEAT_RELTIME
5426 if (list2proftime(&argvars[0], &tm) == OK)
5427 rettv->vval.v_float = profile_float(&tm);
5428# endif
5429}
5430#endif
5431
5432/*
5433 * "reltimestr()" function
5434 */
5435 static void
5436f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
5437{
5438#ifdef FEAT_RELTIME
5439 proftime_T tm;
5440#endif
5441
5442 rettv->v_type = VAR_STRING;
5443 rettv->vval.v_string = NULL;
5444#ifdef FEAT_RELTIME
5445 if (list2proftime(&argvars[0], &tm) == OK)
5446 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
5447#endif
5448}
5449
5450#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005451 static void
5452make_connection(void)
5453{
5454 if (X_DISPLAY == NULL
5455# ifdef FEAT_GUI
5456 && !gui.in_use
5457# endif
5458 )
5459 {
5460 x_force_connect = TRUE;
5461 setup_term_clip();
5462 x_force_connect = FALSE;
5463 }
5464}
5465
5466 static int
5467check_connection(void)
5468{
5469 make_connection();
5470 if (X_DISPLAY == NULL)
5471 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005472 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005473 return FAIL;
5474 }
5475 return OK;
5476}
5477#endif
5478
5479#ifdef FEAT_CLIENTSERVER
5480 static void
5481remote_common(typval_T *argvars, typval_T *rettv, int expr)
5482{
5483 char_u *server_name;
5484 char_u *keys;
5485 char_u *r = NULL;
5486 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005487 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005488# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005489 HWND w;
5490# else
5491 Window w;
5492# endif
5493
5494 if (check_restricted() || check_secure())
5495 return;
5496
5497# ifdef FEAT_X11
5498 if (check_connection() == FAIL)
5499 return;
5500# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005501 if (argvars[2].v_type != VAR_UNKNOWN
5502 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005503 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005505 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005506 if (server_name == NULL)
5507 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005508 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01005509# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005510 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005511# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005512 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
5513 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005514# endif
5515 {
5516 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005517 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005518 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005519 vim_free(r);
5520 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005521 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005522 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005523 return;
5524 }
5525
5526 rettv->vval.v_string = r;
5527
5528 if (argvars[2].v_type != VAR_UNKNOWN)
5529 {
5530 dictitem_T v;
5531 char_u str[30];
5532 char_u *idvar;
5533
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005534 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005535 if (idvar != NULL && *idvar != NUL)
5536 {
5537 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
5538 v.di_tv.v_type = VAR_STRING;
5539 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005540 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005541 vim_free(v.di_tv.vval.v_string);
5542 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005543 }
5544}
5545#endif
5546
5547/*
5548 * "remote_expr()" function
5549 */
5550 static void
5551f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
5552{
5553 rettv->v_type = VAR_STRING;
5554 rettv->vval.v_string = NULL;
5555#ifdef FEAT_CLIENTSERVER
5556 remote_common(argvars, rettv, TRUE);
5557#endif
5558}
5559
5560/*
5561 * "remote_foreground()" function
5562 */
5563 static void
5564f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5565{
5566#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01005567# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005568 /* On Win32 it's done in this application. */
5569 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005570 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005571
5572 if (server_name != NULL)
5573 serverForeground(server_name);
5574 }
5575# else
5576 /* Send a foreground() expression to the server. */
5577 argvars[1].v_type = VAR_STRING;
5578 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
5579 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02005580 rettv->v_type = VAR_STRING;
5581 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005582 remote_common(argvars, rettv, TRUE);
5583 vim_free(argvars[1].vval.v_string);
5584# endif
5585#endif
5586}
5587
5588 static void
5589f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
5590{
5591#ifdef FEAT_CLIENTSERVER
5592 dictitem_T v;
5593 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005594# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005595 long_u n = 0;
5596# endif
5597 char_u *serverid;
5598
5599 if (check_restricted() || check_secure())
5600 {
5601 rettv->vval.v_number = -1;
5602 return;
5603 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005604 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005605 if (serverid == NULL)
5606 {
5607 rettv->vval.v_number = -1;
5608 return; /* type error; errmsg already given */
5609 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01005610# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005611 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
5612 if (n == 0)
5613 rettv->vval.v_number = -1;
5614 else
5615 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005616 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005617 rettv->vval.v_number = (s != NULL);
5618 }
5619# else
5620 if (check_connection() == FAIL)
5621 return;
5622
5623 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
5624 serverStrToWin(serverid), &s);
5625# endif
5626
5627 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
5628 {
5629 char_u *retvar;
5630
5631 v.di_tv.v_type = VAR_STRING;
5632 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005633 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005634 if (retvar != NULL)
5635 set_var(retvar, &v.di_tv, FALSE);
5636 vim_free(v.di_tv.vval.v_string);
5637 }
5638#else
5639 rettv->vval.v_number = -1;
5640#endif
5641}
5642
5643 static void
5644f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
5645{
5646 char_u *r = NULL;
5647
5648#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005649 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005650
5651 if (serverid != NULL && !check_restricted() && !check_secure())
5652 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005653 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005654# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01005655 /* The server's HWND is encoded in the 'id' parameter */
5656 long_u n = 0;
5657# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005658
5659 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005660 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005661
Bram Moolenaar4f974752019-02-17 17:44:42 +01005662# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005663 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
5664 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005665 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005666 if (r == NULL)
5667# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01005668 if (check_connection() == FAIL
5669 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
5670 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005671# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005672 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005673 }
5674#endif
5675 rettv->v_type = VAR_STRING;
5676 rettv->vval.v_string = r;
5677}
5678
5679/*
5680 * "remote_send()" function
5681 */
5682 static void
5683f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
5684{
5685 rettv->v_type = VAR_STRING;
5686 rettv->vval.v_string = NULL;
5687#ifdef FEAT_CLIENTSERVER
5688 remote_common(argvars, rettv, FALSE);
5689#endif
5690}
5691
5692/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005693 * "remote_startserver()" function
5694 */
5695 static void
5696f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5697{
5698#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005699 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005700
5701 if (server == NULL)
5702 return; /* type error; errmsg already given */
5703 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005704 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005705 else
5706 {
5707# ifdef FEAT_X11
5708 if (check_connection() == OK)
5709 serverRegisterName(X_DISPLAY, server);
5710# else
5711 serverSetName(server);
5712# endif
5713 }
5714#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005715 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01005716#endif
5717}
5718
5719/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005720 * "rename({from}, {to})" function
5721 */
5722 static void
5723f_rename(typval_T *argvars, typval_T *rettv)
5724{
5725 char_u buf[NUMBUFLEN];
5726
5727 if (check_restricted() || check_secure())
5728 rettv->vval.v_number = -1;
5729 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005730 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
5731 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005732}
5733
5734/*
5735 * "repeat()" function
5736 */
5737 static void
5738f_repeat(typval_T *argvars, typval_T *rettv)
5739{
5740 char_u *p;
5741 int n;
5742 int slen;
5743 int len;
5744 char_u *r;
5745 int i;
5746
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005747 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005748 if (argvars[0].v_type == VAR_LIST)
5749 {
5750 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
5751 while (n-- > 0)
5752 if (list_extend(rettv->vval.v_list,
5753 argvars[0].vval.v_list, NULL) == FAIL)
5754 break;
5755 }
5756 else
5757 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005758 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005759 rettv->v_type = VAR_STRING;
5760 rettv->vval.v_string = NULL;
5761
5762 slen = (int)STRLEN(p);
5763 len = slen * n;
5764 if (len <= 0)
5765 return;
5766
5767 r = alloc(len + 1);
5768 if (r != NULL)
5769 {
5770 for (i = 0; i < n; i++)
5771 mch_memmove(r + i * slen, p, (size_t)slen);
5772 r[len] = NUL;
5773 }
5774
5775 rettv->vval.v_string = r;
5776 }
5777}
5778
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005779#define SP_NOMOVE 0x01 /* don't move cursor */
5780#define SP_REPEAT 0x02 /* repeat to find outer pair */
5781#define SP_RETCOUNT 0x04 /* return matchcount */
5782#define SP_SETPCMARK 0x08 /* set previous context mark */
5783#define SP_START 0x10 /* accept match at start position */
5784#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
5785#define SP_END 0x40 /* leave cursor at end of match */
5786#define SP_COLUMN 0x80 /* start at cursor column */
5787
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005788/*
5789 * Get flags for a search function.
5790 * Possibly sets "p_ws".
5791 * Returns BACKWARD, FORWARD or zero (for an error).
5792 */
5793 static int
5794get_search_arg(typval_T *varp, int *flagsp)
5795{
5796 int dir = FORWARD;
5797 char_u *flags;
5798 char_u nbuf[NUMBUFLEN];
5799 int mask;
5800
5801 if (varp->v_type != VAR_UNKNOWN)
5802 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005803 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005804 if (flags == NULL)
5805 return 0; /* type error; errmsg already given */
5806 while (*flags != NUL)
5807 {
5808 switch (*flags)
5809 {
5810 case 'b': dir = BACKWARD; break;
5811 case 'w': p_ws = TRUE; break;
5812 case 'W': p_ws = FALSE; break;
5813 default: mask = 0;
5814 if (flagsp != NULL)
5815 switch (*flags)
5816 {
5817 case 'c': mask = SP_START; break;
5818 case 'e': mask = SP_END; break;
5819 case 'm': mask = SP_RETCOUNT; break;
5820 case 'n': mask = SP_NOMOVE; break;
5821 case 'p': mask = SP_SUBPAT; break;
5822 case 'r': mask = SP_REPEAT; break;
5823 case 's': mask = SP_SETPCMARK; break;
5824 case 'z': mask = SP_COLUMN; break;
5825 }
5826 if (mask == 0)
5827 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005828 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829 dir = 0;
5830 }
5831 else
5832 *flagsp |= mask;
5833 }
5834 if (dir == 0)
5835 break;
5836 ++flags;
5837 }
5838 }
5839 return dir;
5840}
5841
5842/*
5843 * Shared by search() and searchpos() functions.
5844 */
5845 static int
5846search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
5847{
5848 int flags;
5849 char_u *pat;
5850 pos_T pos;
5851 pos_T save_cursor;
5852 int save_p_ws = p_ws;
5853 int dir;
5854 int retval = 0; /* default: FAIL */
5855 long lnum_stop = 0;
5856 proftime_T tm;
5857#ifdef FEAT_RELTIME
5858 long time_limit = 0;
5859#endif
5860 int options = SEARCH_KEEP;
5861 int subpatnum;
5862
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005863 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005864 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
5865 if (dir == 0)
5866 goto theend;
5867 flags = *flagsp;
5868 if (flags & SP_START)
5869 options |= SEARCH_START;
5870 if (flags & SP_END)
5871 options |= SEARCH_END;
5872 if (flags & SP_COLUMN)
5873 options |= SEARCH_COL;
5874
5875 /* Optional arguments: line number to stop searching and timeout. */
5876 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
5877 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005878 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005879 if (lnum_stop < 0)
5880 goto theend;
5881#ifdef FEAT_RELTIME
5882 if (argvars[3].v_type != VAR_UNKNOWN)
5883 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005884 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005885 if (time_limit < 0)
5886 goto theend;
5887 }
5888#endif
5889 }
5890
5891#ifdef FEAT_RELTIME
5892 /* Set the time limit, if there is one. */
5893 profile_setlimit(time_limit, &tm);
5894#endif
5895
5896 /*
5897 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
5898 * Check to make sure only those flags are set.
5899 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
5900 * flags cannot be set. Check for that condition also.
5901 */
5902 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
5903 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
5904 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005905 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005906 goto theend;
5907 }
5908
5909 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01005910 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02005911 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005912 if (subpatnum != FAIL)
5913 {
5914 if (flags & SP_SUBPAT)
5915 retval = subpatnum;
5916 else
5917 retval = pos.lnum;
5918 if (flags & SP_SETPCMARK)
5919 setpcmark();
5920 curwin->w_cursor = pos;
5921 if (match_pos != NULL)
5922 {
5923 /* Store the match cursor position */
5924 match_pos->lnum = pos.lnum;
5925 match_pos->col = pos.col + 1;
5926 }
5927 /* "/$" will put the cursor after the end of the line, may need to
5928 * correct that here */
5929 check_cursor();
5930 }
5931
5932 /* If 'n' flag is used: restore cursor position. */
5933 if (flags & SP_NOMOVE)
5934 curwin->w_cursor = save_cursor;
5935 else
5936 curwin->w_set_curswant = TRUE;
5937theend:
5938 p_ws = save_p_ws;
5939
5940 return retval;
5941}
5942
5943#ifdef FEAT_FLOAT
5944
5945/*
5946 * round() is not in C90, use ceil() or floor() instead.
5947 */
5948 float_T
5949vim_round(float_T f)
5950{
5951 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
5952}
5953
5954/*
5955 * "round({float})" function
5956 */
5957 static void
5958f_round(typval_T *argvars, typval_T *rettv)
5959{
5960 float_T f = 0.0;
5961
5962 rettv->v_type = VAR_FLOAT;
5963 if (get_float_arg(argvars, &f) == OK)
5964 rettv->vval.v_float = vim_round(f);
5965 else
5966 rettv->vval.v_float = 0.0;
5967}
5968#endif
5969
Bram Moolenaare99be0e2019-03-26 22:51:09 +01005970#ifdef FEAT_RUBY
5971/*
5972 * "rubyeval()" function
5973 */
5974 static void
5975f_rubyeval(typval_T *argvars, typval_T *rettv)
5976{
5977 char_u *str;
5978 char_u buf[NUMBUFLEN];
5979
5980 str = tv_get_string_buf(&argvars[0], buf);
5981 do_rubyeval(str, rettv);
5982}
5983#endif
5984
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005985/*
5986 * "screenattr()" function
5987 */
5988 static void
5989f_screenattr(typval_T *argvars, typval_T *rettv)
5990{
5991 int row;
5992 int col;
5993 int c;
5994
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005995 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
5996 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005997 if (row < 0 || row >= screen_Rows
5998 || col < 0 || col >= screen_Columns)
5999 c = -1;
6000 else
6001 c = ScreenAttrs[LineOffset[row] + col];
6002 rettv->vval.v_number = c;
6003}
6004
6005/*
6006 * "screenchar()" function
6007 */
6008 static void
6009f_screenchar(typval_T *argvars, typval_T *rettv)
6010{
6011 int row;
6012 int col;
6013 int off;
6014 int c;
6015
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006016 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6017 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006018 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006019 c = -1;
6020 else
6021 {
6022 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 if (enc_utf8 && ScreenLinesUC[off] != 0)
6024 c = ScreenLinesUC[off];
6025 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006026 c = ScreenLines[off];
6027 }
6028 rettv->vval.v_number = c;
6029}
6030
6031/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006032 * "screenchars()" function
6033 */
6034 static void
6035f_screenchars(typval_T *argvars, typval_T *rettv)
6036{
6037 int row;
6038 int col;
6039 int off;
6040 int c;
6041 int i;
6042
6043 if (rettv_list_alloc(rettv) == FAIL)
6044 return;
6045 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6046 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6047 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6048 return;
6049
6050 off = LineOffset[row] + col;
6051 if (enc_utf8 && ScreenLinesUC[off] != 0)
6052 c = ScreenLinesUC[off];
6053 else
6054 c = ScreenLines[off];
6055 list_append_number(rettv->vval.v_list, (varnumber_T)c);
6056
6057 if (enc_utf8)
6058
6059 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6060 list_append_number(rettv->vval.v_list,
6061 (varnumber_T)ScreenLinesC[i][off]);
6062}
6063
6064/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065 * "screencol()" function
6066 *
6067 * First column is 1 to be consistent with virtcol().
6068 */
6069 static void
6070f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
6071{
6072 rettv->vval.v_number = screen_screencol() + 1;
6073}
6074
6075/*
6076 * "screenrow()" function
6077 */
6078 static void
6079f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
6080{
6081 rettv->vval.v_number = screen_screenrow() + 1;
6082}
6083
6084/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01006085 * "screenstring()" function
6086 */
6087 static void
6088f_screenstring(typval_T *argvars, typval_T *rettv)
6089{
6090 int row;
6091 int col;
6092 int off;
6093 int c;
6094 int i;
6095 char_u buf[MB_MAXBYTES + 1];
6096 int buflen = 0;
6097
6098 rettv->vval.v_string = NULL;
6099 rettv->v_type = VAR_STRING;
6100
6101 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
6102 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
6103 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
6104 return;
6105
6106 off = LineOffset[row] + col;
6107 if (enc_utf8 && ScreenLinesUC[off] != 0)
6108 c = ScreenLinesUC[off];
6109 else
6110 c = ScreenLines[off];
6111 buflen += mb_char2bytes(c, buf);
6112
6113 if (enc_utf8)
6114 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
6115 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
6116
6117 buf[buflen] = NUL;
6118 rettv->vval.v_string = vim_strsave(buf);
6119}
6120
6121/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006122 * "search()" function
6123 */
6124 static void
6125f_search(typval_T *argvars, typval_T *rettv)
6126{
6127 int flags = 0;
6128
6129 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
6130}
6131
6132/*
6133 * "searchdecl()" function
6134 */
6135 static void
6136f_searchdecl(typval_T *argvars, typval_T *rettv)
6137{
6138 int locally = 1;
6139 int thisblock = 0;
6140 int error = FALSE;
6141 char_u *name;
6142
6143 rettv->vval.v_number = 1; /* default: FAIL */
6144
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006145 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006146 if (argvars[1].v_type != VAR_UNKNOWN)
6147 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006148 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006149 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006150 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006151 }
6152 if (!error && name != NULL)
6153 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
6154 locally, thisblock, SEARCH_KEEP) == FAIL;
6155}
6156
6157/*
6158 * Used by searchpair() and searchpairpos()
6159 */
6160 static int
6161searchpair_cmn(typval_T *argvars, pos_T *match_pos)
6162{
6163 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01006164 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006165 int save_p_ws = p_ws;
6166 int dir;
6167 int flags = 0;
6168 char_u nbuf1[NUMBUFLEN];
6169 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006170 int retval = 0; /* default: FAIL */
6171 long lnum_stop = 0;
6172 long time_limit = 0;
6173
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006174 /* Get the three pattern arguments: start, middle, end. Will result in an
6175 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006176 spat = tv_get_string_chk(&argvars[0]);
6177 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
6178 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006179 if (spat == NULL || mpat == NULL || epat == NULL)
6180 goto theend; /* type error */
6181
6182 /* Handle the optional fourth argument: flags */
6183 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
6184 if (dir == 0)
6185 goto theend;
6186
6187 /* Don't accept SP_END or SP_SUBPAT.
6188 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
6189 */
6190 if ((flags & (SP_END | SP_SUBPAT)) != 0
6191 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
6192 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006193 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 goto theend;
6195 }
6196
6197 /* Using 'r' implies 'W', otherwise it doesn't work. */
6198 if (flags & SP_REPEAT)
6199 p_ws = FALSE;
6200
6201 /* Optional fifth argument: skip expression */
6202 if (argvars[3].v_type == VAR_UNKNOWN
6203 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01006204 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006205 else
6206 {
Bram Moolenaar48570482017-10-30 21:48:41 +01006207 skip = &argvars[4];
6208 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
6209 && skip->v_type != VAR_STRING)
6210 {
6211 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006212 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01006213 goto theend;
6214 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006215 if (argvars[5].v_type != VAR_UNKNOWN)
6216 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006217 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006218 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006219 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006220 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006221 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006222 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006223#ifdef FEAT_RELTIME
6224 if (argvars[6].v_type != VAR_UNKNOWN)
6225 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006226 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006227 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006228 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006229 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006230 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02006231 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006232 }
6233#endif
6234 }
6235 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006236
6237 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
6238 match_pos, lnum_stop, time_limit);
6239
6240theend:
6241 p_ws = save_p_ws;
6242
6243 return retval;
6244}
6245
6246/*
6247 * "searchpair()" function
6248 */
6249 static void
6250f_searchpair(typval_T *argvars, typval_T *rettv)
6251{
6252 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
6253}
6254
6255/*
6256 * "searchpairpos()" function
6257 */
6258 static void
6259f_searchpairpos(typval_T *argvars, typval_T *rettv)
6260{
6261 pos_T match_pos;
6262 int lnum = 0;
6263 int col = 0;
6264
6265 if (rettv_list_alloc(rettv) == FAIL)
6266 return;
6267
6268 if (searchpair_cmn(argvars, &match_pos) > 0)
6269 {
6270 lnum = match_pos.lnum;
6271 col = match_pos.col;
6272 }
6273
6274 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6275 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6276}
6277
6278/*
6279 * Search for a start/middle/end thing.
6280 * Used by searchpair(), see its documentation for the details.
6281 * Returns 0 or -1 for no match,
6282 */
6283 long
6284do_searchpair(
6285 char_u *spat, /* start pattern */
6286 char_u *mpat, /* middle pattern */
6287 char_u *epat, /* end pattern */
6288 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01006289 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006290 int flags, /* SP_SETPCMARK and other SP_ values */
6291 pos_T *match_pos,
6292 linenr_T lnum_stop, /* stop at this line if not zero */
6293 long time_limit UNUSED) /* stop after this many msec */
6294{
6295 char_u *save_cpo;
6296 char_u *pat, *pat2 = NULL, *pat3 = NULL;
6297 long retval = 0;
6298 pos_T pos;
6299 pos_T firstpos;
6300 pos_T foundpos;
6301 pos_T save_cursor;
6302 pos_T save_pos;
6303 int n;
6304 int r;
6305 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01006306 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006307 int err;
6308 int options = SEARCH_KEEP;
6309 proftime_T tm;
6310
6311 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6312 save_cpo = p_cpo;
6313 p_cpo = empty_option;
6314
6315#ifdef FEAT_RELTIME
6316 /* Set the time limit, if there is one. */
6317 profile_setlimit(time_limit, &tm);
6318#endif
6319
6320 /* Make two search patterns: start/end (pat2, for in nested pairs) and
6321 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02006322 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
6323 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006324 if (pat2 == NULL || pat3 == NULL)
6325 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006326 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006327 if (*mpat == NUL)
6328 STRCPY(pat3, pat2);
6329 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01006330 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006331 spat, epat, mpat);
6332 if (flags & SP_START)
6333 options |= SEARCH_START;
6334
Bram Moolenaar48570482017-10-30 21:48:41 +01006335 if (skip != NULL)
6336 {
6337 /* Empty string means to not use the skip expression. */
6338 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
6339 use_skip = skip->vval.v_string != NULL
6340 && *skip->vval.v_string != NUL;
6341 }
6342
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343 save_cursor = curwin->w_cursor;
6344 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006345 CLEAR_POS(&firstpos);
6346 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006347 pat = pat3;
6348 for (;;)
6349 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01006350 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02006351 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006352 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006353 /* didn't find it or found the first match again: FAIL */
6354 break;
6355
6356 if (firstpos.lnum == 0)
6357 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01006358 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006359 {
6360 /* Found the same position again. Can happen with a pattern that
6361 * has "\zs" at the end and searching backwards. Advance one
6362 * character and try again. */
6363 if (dir == BACKWARD)
6364 decl(&pos);
6365 else
6366 incl(&pos);
6367 }
6368 foundpos = pos;
6369
6370 /* clear the start flag to avoid getting stuck here */
6371 options &= ~SEARCH_START;
6372
6373 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01006374 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006375 {
6376 save_pos = curwin->w_cursor;
6377 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01006378 err = FALSE;
6379 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006380 curwin->w_cursor = save_pos;
6381 if (err)
6382 {
6383 /* Evaluating {skip} caused an error, break here. */
6384 curwin->w_cursor = save_cursor;
6385 retval = -1;
6386 break;
6387 }
6388 if (r)
6389 continue;
6390 }
6391
6392 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
6393 {
6394 /* Found end when searching backwards or start when searching
6395 * forward: nested pair. */
6396 ++nest;
6397 pat = pat2; /* nested, don't search for middle */
6398 }
6399 else
6400 {
6401 /* Found end when searching forward or start when searching
6402 * backward: end of (nested) pair; or found middle in outer pair. */
6403 if (--nest == 1)
6404 pat = pat3; /* outer level, search for middle */
6405 }
6406
6407 if (nest == 0)
6408 {
6409 /* Found the match: return matchcount or line number. */
6410 if (flags & SP_RETCOUNT)
6411 ++retval;
6412 else
6413 retval = pos.lnum;
6414 if (flags & SP_SETPCMARK)
6415 setpcmark();
6416 curwin->w_cursor = pos;
6417 if (!(flags & SP_REPEAT))
6418 break;
6419 nest = 1; /* search for next unmatched */
6420 }
6421 }
6422
6423 if (match_pos != NULL)
6424 {
6425 /* Store the match cursor position */
6426 match_pos->lnum = curwin->w_cursor.lnum;
6427 match_pos->col = curwin->w_cursor.col + 1;
6428 }
6429
6430 /* If 'n' flag is used or search failed: restore cursor position. */
6431 if ((flags & SP_NOMOVE) || retval == 0)
6432 curwin->w_cursor = save_cursor;
6433
6434theend:
6435 vim_free(pat2);
6436 vim_free(pat3);
6437 if (p_cpo == empty_option)
6438 p_cpo = save_cpo;
6439 else
6440 /* Darn, evaluating the {skip} expression changed the value. */
6441 free_string_option(save_cpo);
6442
6443 return retval;
6444}
6445
6446/*
6447 * "searchpos()" function
6448 */
6449 static void
6450f_searchpos(typval_T *argvars, typval_T *rettv)
6451{
6452 pos_T match_pos;
6453 int lnum = 0;
6454 int col = 0;
6455 int n;
6456 int flags = 0;
6457
6458 if (rettv_list_alloc(rettv) == FAIL)
6459 return;
6460
6461 n = search_cmn(argvars, &match_pos, &flags);
6462 if (n > 0)
6463 {
6464 lnum = match_pos.lnum;
6465 col = match_pos.col;
6466 }
6467
6468 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
6469 list_append_number(rettv->vval.v_list, (varnumber_T)col);
6470 if (flags & SP_SUBPAT)
6471 list_append_number(rettv->vval.v_list, (varnumber_T)n);
6472}
6473
6474 static void
6475f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
6476{
6477#ifdef FEAT_CLIENTSERVER
6478 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006479 char_u *server = tv_get_string_chk(&argvars[0]);
6480 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006481
6482 rettv->vval.v_number = -1;
6483 if (server == NULL || reply == NULL)
6484 return;
6485 if (check_restricted() || check_secure())
6486 return;
6487# ifdef FEAT_X11
6488 if (check_connection() == FAIL)
6489 return;
6490# endif
6491
6492 if (serverSendReply(server, reply) < 0)
6493 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006494 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006495 return;
6496 }
6497 rettv->vval.v_number = 0;
6498#else
6499 rettv->vval.v_number = -1;
6500#endif
6501}
6502
6503 static void
6504f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
6505{
6506 char_u *r = NULL;
6507
6508#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006509# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006510 r = serverGetVimNames();
6511# else
6512 make_connection();
6513 if (X_DISPLAY != NULL)
6514 r = serverGetVimNames(X_DISPLAY);
6515# endif
6516#endif
6517 rettv->v_type = VAR_STRING;
6518 rettv->vval.v_string = r;
6519}
6520
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006521 static void
6522f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
6523{
6524 dict_T *d;
6525 dictitem_T *di;
6526 char_u *csearch;
6527
6528 if (argvars[0].v_type != VAR_DICT)
6529 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006530 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006531 return;
6532 }
6533
6534 if ((d = argvars[0].vval.v_dict) != NULL)
6535 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01006536 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006537 if (csearch != NULL)
6538 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006539 if (enc_utf8)
6540 {
6541 int pcc[MAX_MCO];
6542 int c = utfc_ptr2char(csearch, pcc);
6543
6544 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
6545 }
6546 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006547 set_last_csearch(PTR2CHAR(csearch),
6548 csearch, MB_PTR2LEN(csearch));
6549 }
6550
6551 di = dict_find(d, (char_u *)"forward", -1);
6552 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006553 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006554 ? FORWARD : BACKWARD);
6555
6556 di = dict_find(d, (char_u *)"until", -1);
6557 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006558 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006559 }
6560}
6561
6562/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02006563 * "setenv()" function
6564 */
6565 static void
6566f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
6567{
6568 char_u namebuf[NUMBUFLEN];
6569 char_u valbuf[NUMBUFLEN];
6570 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
6571
6572 if (argvars[1].v_type == VAR_SPECIAL
6573 && argvars[1].vval.v_number == VVAL_NULL)
6574 vim_unsetenv(name);
6575 else
6576 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
6577}
6578
6579/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006580 * "setfperm({fname}, {mode})" function
6581 */
6582 static void
6583f_setfperm(typval_T *argvars, typval_T *rettv)
6584{
6585 char_u *fname;
6586 char_u modebuf[NUMBUFLEN];
6587 char_u *mode_str;
6588 int i;
6589 int mask;
6590 int mode = 0;
6591
6592 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006593 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006594 if (fname == NULL)
6595 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006596 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006597 if (mode_str == NULL)
6598 return;
6599 if (STRLEN(mode_str) != 9)
6600 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006601 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006602 return;
6603 }
6604
6605 mask = 1;
6606 for (i = 8; i >= 0; --i)
6607 {
6608 if (mode_str[i] != '-')
6609 mode |= mask;
6610 mask = mask << 1;
6611 }
6612 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
6613}
6614
6615/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006616 * "setpos()" function
6617 */
6618 static void
6619f_setpos(typval_T *argvars, typval_T *rettv)
6620{
6621 pos_T pos;
6622 int fnum;
6623 char_u *name;
6624 colnr_T curswant = -1;
6625
6626 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006627 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006628 if (name != NULL)
6629 {
6630 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
6631 {
6632 if (--pos.col < 0)
6633 pos.col = 0;
6634 if (name[0] == '.' && name[1] == NUL)
6635 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006636 /* set cursor; "fnum" is ignored */
6637 curwin->w_cursor = pos;
6638 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006639 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006640 curwin->w_curswant = curswant - 1;
6641 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006642 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01006643 check_cursor();
6644 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006645 }
6646 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
6647 {
6648 /* set mark */
6649 if (setmark_pos(name[1], &pos, fnum) == OK)
6650 rettv->vval.v_number = 0;
6651 }
6652 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006653 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006654 }
6655 }
6656}
6657
6658/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006659 * "setreg()" function
6660 */
6661 static void
6662f_setreg(typval_T *argvars, typval_T *rettv)
6663{
6664 int regname;
6665 char_u *strregname;
6666 char_u *stropt;
6667 char_u *strval;
6668 int append;
6669 char_u yank_type;
6670 long block_len;
6671
6672 block_len = -1;
6673 yank_type = MAUTO;
6674 append = FALSE;
6675
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006676 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006677 rettv->vval.v_number = 1; /* FAIL is default */
6678
6679 if (strregname == NULL)
6680 return; /* type error; errmsg already given */
6681 regname = *strregname;
6682 if (regname == 0 || regname == '@')
6683 regname = '"';
6684
6685 if (argvars[2].v_type != VAR_UNKNOWN)
6686 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006687 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688 if (stropt == NULL)
6689 return; /* type error */
6690 for (; *stropt != NUL; ++stropt)
6691 switch (*stropt)
6692 {
6693 case 'a': case 'A': /* append */
6694 append = TRUE;
6695 break;
6696 case 'v': case 'c': /* character-wise selection */
6697 yank_type = MCHAR;
6698 break;
6699 case 'V': case 'l': /* line-wise selection */
6700 yank_type = MLINE;
6701 break;
6702 case 'b': case Ctrl_V: /* block-wise selection */
6703 yank_type = MBLOCK;
6704 if (VIM_ISDIGIT(stropt[1]))
6705 {
6706 ++stropt;
6707 block_len = getdigits(&stropt) - 1;
6708 --stropt;
6709 }
6710 break;
6711 }
6712 }
6713
6714 if (argvars[1].v_type == VAR_LIST)
6715 {
6716 char_u **lstval;
6717 char_u **allocval;
6718 char_u buf[NUMBUFLEN];
6719 char_u **curval;
6720 char_u **curallocval;
6721 list_T *ll = argvars[1].vval.v_list;
6722 listitem_T *li;
6723 int len;
6724
6725 /* If the list is NULL handle like an empty list. */
6726 len = ll == NULL ? 0 : ll->lv_len;
6727
6728 /* First half: use for pointers to result lines; second half: use for
6729 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02006730 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006731 if (lstval == NULL)
6732 return;
6733 curval = lstval;
6734 allocval = lstval + len + 2;
6735 curallocval = allocval;
6736
6737 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
6738 li = li->li_next)
6739 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006740 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741 if (strval == NULL)
6742 goto free_lstval;
6743 if (strval == buf)
6744 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006745 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006746 * overwrite the string. */
6747 strval = vim_strsave(buf);
6748 if (strval == NULL)
6749 goto free_lstval;
6750 *curallocval++ = strval;
6751 }
6752 *curval++ = strval;
6753 }
6754 *curval++ = NULL;
6755
6756 write_reg_contents_lst(regname, lstval, -1,
6757 append, yank_type, block_len);
6758free_lstval:
6759 while (curallocval > allocval)
6760 vim_free(*--curallocval);
6761 vim_free(lstval);
6762 }
6763 else
6764 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006765 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006766 if (strval == NULL)
6767 return;
6768 write_reg_contents_ex(regname, strval, -1,
6769 append, yank_type, block_len);
6770 }
6771 rettv->vval.v_number = 0;
6772}
6773
6774/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006775 * "settagstack()" function
6776 */
6777 static void
6778f_settagstack(typval_T *argvars, typval_T *rettv)
6779{
6780 static char *e_invact2 = N_("E962: Invalid action: '%s'");
6781 win_T *wp;
6782 dict_T *d;
6783 int action = 'r';
6784
6785 rettv->vval.v_number = -1;
6786
6787 // first argument: window number or id
6788 wp = find_win_by_nr_or_id(&argvars[0]);
6789 if (wp == NULL)
6790 return;
6791
6792 // second argument: dict with items to set in the tag stack
6793 if (argvars[1].v_type != VAR_DICT)
6794 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006795 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006796 return;
6797 }
6798 d = argvars[1].vval.v_dict;
6799 if (d == NULL)
6800 return;
6801
6802 // third argument: action - 'a' for append and 'r' for replace.
6803 // default is to replace the stack.
6804 if (argvars[2].v_type == VAR_UNKNOWN)
6805 action = 'r';
6806 else if (argvars[2].v_type == VAR_STRING)
6807 {
6808 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006809 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006810 if (actstr == NULL)
6811 return;
6812 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
6813 action = *actstr;
6814 else
6815 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006816 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006817 return;
6818 }
6819 }
6820 else
6821 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006822 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01006823 return;
6824 }
6825
6826 if (set_tagstack(wp, d, action) == OK)
6827 rettv->vval.v_number = 0;
6828}
6829
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830#ifdef FEAT_CRYPT
6831/*
6832 * "sha256({string})" function
6833 */
6834 static void
6835f_sha256(typval_T *argvars, typval_T *rettv)
6836{
6837 char_u *p;
6838
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006839 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006840 rettv->vval.v_string = vim_strsave(
6841 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
6842 rettv->v_type = VAR_STRING;
6843}
6844#endif /* FEAT_CRYPT */
6845
6846/*
6847 * "shellescape({string})" function
6848 */
6849 static void
6850f_shellescape(typval_T *argvars, typval_T *rettv)
6851{
Bram Moolenaar20615522017-06-05 18:46:26 +02006852 int do_special = non_zero_arg(&argvars[1]);
6853
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006854 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006855 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006856 rettv->v_type = VAR_STRING;
6857}
6858
6859/*
6860 * shiftwidth() function
6861 */
6862 static void
6863f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
6864{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006865 rettv->vval.v_number = 0;
6866
6867 if (argvars[0].v_type != VAR_UNKNOWN)
6868 {
6869 long col;
6870
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006871 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01006872 if (col < 0)
6873 return; // type error; errmsg already given
6874#ifdef FEAT_VARTABS
6875 rettv->vval.v_number = get_sw_value_col(curbuf, col);
6876 return;
6877#endif
6878 }
6879
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 rettv->vval.v_number = get_sw_value(curbuf);
6881}
6882
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883#ifdef FEAT_FLOAT
6884/*
6885 * "sin()" function
6886 */
6887 static void
6888f_sin(typval_T *argvars, typval_T *rettv)
6889{
6890 float_T f = 0.0;
6891
6892 rettv->v_type = VAR_FLOAT;
6893 if (get_float_arg(argvars, &f) == OK)
6894 rettv->vval.v_float = sin(f);
6895 else
6896 rettv->vval.v_float = 0.0;
6897}
6898
6899/*
6900 * "sinh()" function
6901 */
6902 static void
6903f_sinh(typval_T *argvars, typval_T *rettv)
6904{
6905 float_T f = 0.0;
6906
6907 rettv->v_type = VAR_FLOAT;
6908 if (get_float_arg(argvars, &f) == OK)
6909 rettv->vval.v_float = sinh(f);
6910 else
6911 rettv->vval.v_float = 0.0;
6912}
6913#endif
6914
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006915/*
6916 * "soundfold({word})" function
6917 */
6918 static void
6919f_soundfold(typval_T *argvars, typval_T *rettv)
6920{
6921 char_u *s;
6922
6923 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006924 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006925#ifdef FEAT_SPELL
6926 rettv->vval.v_string = eval_soundfold(s);
6927#else
6928 rettv->vval.v_string = vim_strsave(s);
6929#endif
6930}
6931
6932/*
6933 * "spellbadword()" function
6934 */
6935 static void
6936f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
6937{
6938 char_u *word = (char_u *)"";
6939 hlf_T attr = HLF_COUNT;
6940 int len = 0;
6941
6942 if (rettv_list_alloc(rettv) == FAIL)
6943 return;
6944
6945#ifdef FEAT_SPELL
6946 if (argvars[0].v_type == VAR_UNKNOWN)
6947 {
6948 /* Find the start and length of the badly spelled word. */
6949 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
6950 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006951 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006952 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01006953 curwin->w_set_curswant = TRUE;
6954 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006955 }
6956 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
6957 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006958 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006959 int capcol = -1;
6960
6961 if (str != NULL)
6962 {
6963 /* Check the argument for spelling. */
6964 while (*str != NUL)
6965 {
6966 len = spell_check(curwin, str, &attr, &capcol, FALSE);
6967 if (attr != HLF_COUNT)
6968 {
6969 word = str;
6970 break;
6971 }
6972 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02006973 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02006974 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006975 }
6976 }
6977 }
6978#endif
6979
6980 list_append_string(rettv->vval.v_list, word, len);
6981 list_append_string(rettv->vval.v_list, (char_u *)(
6982 attr == HLF_SPB ? "bad" :
6983 attr == HLF_SPR ? "rare" :
6984 attr == HLF_SPL ? "local" :
6985 attr == HLF_SPC ? "caps" :
6986 ""), -1);
6987}
6988
6989/*
6990 * "spellsuggest()" function
6991 */
6992 static void
6993f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
6994{
6995#ifdef FEAT_SPELL
6996 char_u *str;
6997 int typeerr = FALSE;
6998 int maxcount;
6999 garray_T ga;
7000 int i;
7001 listitem_T *li;
7002 int need_capital = FALSE;
7003#endif
7004
7005 if (rettv_list_alloc(rettv) == FAIL)
7006 return;
7007
7008#ifdef FEAT_SPELL
7009 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
7010 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007011 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007012 if (argvars[1].v_type != VAR_UNKNOWN)
7013 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007014 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007015 if (maxcount <= 0)
7016 return;
7017 if (argvars[2].v_type != VAR_UNKNOWN)
7018 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007019 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007020 if (typeerr)
7021 return;
7022 }
7023 }
7024 else
7025 maxcount = 25;
7026
7027 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
7028
7029 for (i = 0; i < ga.ga_len; ++i)
7030 {
7031 str = ((char_u **)ga.ga_data)[i];
7032
7033 li = listitem_alloc();
7034 if (li == NULL)
7035 vim_free(str);
7036 else
7037 {
7038 li->li_tv.v_type = VAR_STRING;
7039 li->li_tv.v_lock = 0;
7040 li->li_tv.vval.v_string = str;
7041 list_append(rettv->vval.v_list, li);
7042 }
7043 }
7044 ga_clear(&ga);
7045 }
7046#endif
7047}
7048
7049 static void
7050f_split(typval_T *argvars, typval_T *rettv)
7051{
7052 char_u *str;
7053 char_u *end;
7054 char_u *pat = NULL;
7055 regmatch_T regmatch;
7056 char_u patbuf[NUMBUFLEN];
7057 char_u *save_cpo;
7058 int match;
7059 colnr_T col = 0;
7060 int keepempty = FALSE;
7061 int typeerr = FALSE;
7062
7063 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7064 save_cpo = p_cpo;
7065 p_cpo = (char_u *)"";
7066
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007067 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007068 if (argvars[1].v_type != VAR_UNKNOWN)
7069 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007070 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071 if (pat == NULL)
7072 typeerr = TRUE;
7073 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007074 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075 }
7076 if (pat == NULL || *pat == NUL)
7077 pat = (char_u *)"[\\x01- ]\\+";
7078
7079 if (rettv_list_alloc(rettv) == FAIL)
7080 return;
7081 if (typeerr)
7082 return;
7083
7084 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7085 if (regmatch.regprog != NULL)
7086 {
7087 regmatch.rm_ic = FALSE;
7088 while (*str != NUL || keepempty)
7089 {
7090 if (*str == NUL)
7091 match = FALSE; /* empty item at the end */
7092 else
7093 match = vim_regexec_nl(&regmatch, str, col);
7094 if (match)
7095 end = regmatch.startp[0];
7096 else
7097 end = str + STRLEN(str);
7098 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
7099 && *str != NUL && match && end < regmatch.endp[0]))
7100 {
7101 if (list_append_string(rettv->vval.v_list, str,
7102 (int)(end - str)) == FAIL)
7103 break;
7104 }
7105 if (!match)
7106 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01007107 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007108 if (regmatch.endp[0] > str)
7109 col = 0;
7110 else
Bram Moolenaar13505972019-01-24 15:04:48 +01007111 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007112 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007113 str = regmatch.endp[0];
7114 }
7115
7116 vim_regfree(regmatch.regprog);
7117 }
7118
7119 p_cpo = save_cpo;
7120}
7121
7122#ifdef FEAT_FLOAT
7123/*
7124 * "sqrt()" function
7125 */
7126 static void
7127f_sqrt(typval_T *argvars, typval_T *rettv)
7128{
7129 float_T f = 0.0;
7130
7131 rettv->v_type = VAR_FLOAT;
7132 if (get_float_arg(argvars, &f) == OK)
7133 rettv->vval.v_float = sqrt(f);
7134 else
7135 rettv->vval.v_float = 0.0;
7136}
7137
7138/*
7139 * "str2float()" function
7140 */
7141 static void
7142f_str2float(typval_T *argvars, typval_T *rettv)
7143{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007144 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007145 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007146
Bram Moolenaar08243d22017-01-10 16:12:29 +01007147 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007148 p = skipwhite(p + 1);
7149 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01007150 if (isneg)
7151 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007152 rettv->v_type = VAR_FLOAT;
7153}
7154#endif
7155
7156/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02007157 * "str2list()" function
7158 */
7159 static void
7160f_str2list(typval_T *argvars, typval_T *rettv)
7161{
7162 char_u *p;
7163 int utf8 = FALSE;
7164
7165 if (rettv_list_alloc(rettv) == FAIL)
7166 return;
7167
7168 if (argvars[1].v_type != VAR_UNKNOWN)
7169 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
7170
7171 p = tv_get_string(&argvars[0]);
7172
7173 if (has_mbyte || utf8)
7174 {
7175 int (*ptr2len)(char_u *);
7176 int (*ptr2char)(char_u *);
7177
7178 if (utf8 || enc_utf8)
7179 {
7180 ptr2len = utf_ptr2len;
7181 ptr2char = utf_ptr2char;
7182 }
7183 else
7184 {
7185 ptr2len = mb_ptr2len;
7186 ptr2char = mb_ptr2char;
7187 }
7188
7189 for ( ; *p != NUL; p += (*ptr2len)(p))
7190 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
7191 }
7192 else
7193 for ( ; *p != NUL; ++p)
7194 list_append_number(rettv->vval.v_list, *p);
7195}
7196
7197/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007198 * "str2nr()" function
7199 */
7200 static void
7201f_str2nr(typval_T *argvars, typval_T *rettv)
7202{
7203 int base = 10;
7204 char_u *p;
7205 varnumber_T n;
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007206 int what = 0;
Bram Moolenaar08243d22017-01-10 16:12:29 +01007207 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007208
7209 if (argvars[1].v_type != VAR_UNKNOWN)
7210 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007211 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007212 if (base != 2 && base != 8 && base != 10 && base != 16)
7213 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007214 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007215 return;
7216 }
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007217 if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2]))
7218 what |= STR2NR_QUOTE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007219 }
7220
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007221 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01007222 isneg = (*p == '-');
7223 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007224 p = skipwhite(p + 1);
7225 switch (base)
7226 {
Bram Moolenaar60a8de22019-09-15 14:33:22 +02007227 case 2: what |= STR2NR_BIN + STR2NR_FORCE; break;
7228 case 8: what |= STR2NR_OCT + STR2NR_FORCE; break;
7229 case 16: what |= STR2NR_HEX + STR2NR_FORCE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02007231 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
7232 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01007233 if (isneg)
7234 rettv->vval.v_number = -n;
7235 else
7236 rettv->vval.v_number = n;
7237
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007238}
7239
7240#ifdef HAVE_STRFTIME
7241/*
7242 * "strftime({format}[, {time}])" function
7243 */
7244 static void
7245f_strftime(typval_T *argvars, typval_T *rettv)
7246{
7247 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02007248 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007249 struct tm *curtime;
7250 time_t seconds;
7251 char_u *p;
7252
7253 rettv->v_type = VAR_STRING;
7254
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007255 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007256 if (argvars[1].v_type == VAR_UNKNOWN)
7257 seconds = time(NULL);
7258 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007259 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02007260 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007261 /* MSVC returns NULL for an invalid value of seconds. */
7262 if (curtime == NULL)
7263 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
7264 else
7265 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007266 vimconv_T conv;
7267 char_u *enc;
7268
7269 conv.vc_type = CONV_NONE;
7270 enc = enc_locale();
7271 convert_setup(&conv, p_enc, enc);
7272 if (conv.vc_type != CONV_NONE)
7273 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007274 if (p != NULL)
7275 (void)strftime((char *)result_buf, sizeof(result_buf),
7276 (char *)p, curtime);
7277 else
7278 result_buf[0] = NUL;
7279
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007280 if (conv.vc_type != CONV_NONE)
7281 vim_free(p);
7282 convert_setup(&conv, enc, p_enc);
7283 if (conv.vc_type != CONV_NONE)
7284 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
7285 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007286 rettv->vval.v_string = vim_strsave(result_buf);
7287
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007288 /* Release conversion descriptors */
7289 convert_setup(&conv, NULL, NULL);
7290 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007291 }
7292}
7293#endif
7294
7295/*
7296 * "strgetchar()" function
7297 */
7298 static void
7299f_strgetchar(typval_T *argvars, typval_T *rettv)
7300{
7301 char_u *str;
7302 int len;
7303 int error = FALSE;
7304 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01007305 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007306
7307 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007308 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007309 if (str == NULL)
7310 return;
7311 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007312 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007313 if (error)
7314 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007315
Bram Moolenaar13505972019-01-24 15:04:48 +01007316 while (charidx >= 0 && byteidx < len)
7317 {
7318 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007319 {
Bram Moolenaar13505972019-01-24 15:04:48 +01007320 rettv->vval.v_number = mb_ptr2char(str + byteidx);
7321 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007322 }
Bram Moolenaar13505972019-01-24 15:04:48 +01007323 --charidx;
7324 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007325 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007326}
7327
7328/*
7329 * "stridx()" function
7330 */
7331 static void
7332f_stridx(typval_T *argvars, typval_T *rettv)
7333{
7334 char_u buf[NUMBUFLEN];
7335 char_u *needle;
7336 char_u *haystack;
7337 char_u *save_haystack;
7338 char_u *pos;
7339 int start_idx;
7340
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007341 needle = tv_get_string_chk(&argvars[1]);
7342 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007343 rettv->vval.v_number = -1;
7344 if (needle == NULL || haystack == NULL)
7345 return; /* type error; errmsg already given */
7346
7347 if (argvars[2].v_type != VAR_UNKNOWN)
7348 {
7349 int error = FALSE;
7350
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007351 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007352 if (error || start_idx >= (int)STRLEN(haystack))
7353 return;
7354 if (start_idx >= 0)
7355 haystack += start_idx;
7356 }
7357
7358 pos = (char_u *)strstr((char *)haystack, (char *)needle);
7359 if (pos != NULL)
7360 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
7361}
7362
7363/*
7364 * "string()" function
7365 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01007366 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007367f_string(typval_T *argvars, typval_T *rettv)
7368{
7369 char_u *tofree;
7370 char_u numbuf[NUMBUFLEN];
7371
7372 rettv->v_type = VAR_STRING;
7373 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
7374 get_copyID());
7375 /* Make a copy if we have a value but it's not in allocated memory. */
7376 if (rettv->vval.v_string != NULL && tofree == NULL)
7377 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
7378}
7379
7380/*
7381 * "strlen()" function
7382 */
7383 static void
7384f_strlen(typval_T *argvars, typval_T *rettv)
7385{
7386 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007387 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007388}
7389
7390/*
7391 * "strchars()" function
7392 */
7393 static void
7394f_strchars(typval_T *argvars, typval_T *rettv)
7395{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007396 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007397 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007398 varnumber_T len = 0;
7399 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007400
7401 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007402 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007403 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007404 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405 else
7406 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
7408 while (*s != NUL)
7409 {
7410 func_mb_ptr2char_adv(&s);
7411 ++len;
7412 }
7413 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007414 }
7415}
7416
7417/*
7418 * "strdisplaywidth()" function
7419 */
7420 static void
7421f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
7422{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007423 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007424 int col = 0;
7425
7426 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007427 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007428
7429 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
7430}
7431
7432/*
7433 * "strwidth()" function
7434 */
7435 static void
7436f_strwidth(typval_T *argvars, typval_T *rettv)
7437{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007438 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439
Bram Moolenaar13505972019-01-24 15:04:48 +01007440 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441}
7442
7443/*
7444 * "strcharpart()" function
7445 */
7446 static void
7447f_strcharpart(typval_T *argvars, typval_T *rettv)
7448{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007449 char_u *p;
7450 int nchar;
7451 int nbyte = 0;
7452 int charlen;
7453 int len = 0;
7454 int slen;
7455 int error = FALSE;
7456
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007457 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007458 slen = (int)STRLEN(p);
7459
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007460 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007461 if (!error)
7462 {
7463 if (nchar > 0)
7464 while (nchar > 0 && nbyte < slen)
7465 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007466 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007467 --nchar;
7468 }
7469 else
7470 nbyte = nchar;
7471 if (argvars[2].v_type != VAR_UNKNOWN)
7472 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007473 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007474 while (charlen > 0 && nbyte + len < slen)
7475 {
7476 int off = nbyte + len;
7477
7478 if (off < 0)
7479 len += 1;
7480 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02007481 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007482 --charlen;
7483 }
7484 }
7485 else
7486 len = slen - nbyte; /* default: all bytes that are available. */
7487 }
7488
7489 /*
7490 * Only return the overlap between the specified part and the actual
7491 * string.
7492 */
7493 if (nbyte < 0)
7494 {
7495 len += nbyte;
7496 nbyte = 0;
7497 }
7498 else if (nbyte > slen)
7499 nbyte = slen;
7500 if (len < 0)
7501 len = 0;
7502 else if (nbyte + len > slen)
7503 len = slen - nbyte;
7504
7505 rettv->v_type = VAR_STRING;
7506 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007507}
7508
7509/*
7510 * "strpart()" function
7511 */
7512 static void
7513f_strpart(typval_T *argvars, typval_T *rettv)
7514{
7515 char_u *p;
7516 int n;
7517 int len;
7518 int slen;
7519 int error = FALSE;
7520
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007521 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522 slen = (int)STRLEN(p);
7523
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007524 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007525 if (error)
7526 len = 0;
7527 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007528 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529 else
7530 len = slen - n; /* default len: all bytes that are available. */
7531
7532 /*
7533 * Only return the overlap between the specified part and the actual
7534 * string.
7535 */
7536 if (n < 0)
7537 {
7538 len += n;
7539 n = 0;
7540 }
7541 else if (n > slen)
7542 n = slen;
7543 if (len < 0)
7544 len = 0;
7545 else if (n + len > slen)
7546 len = slen - n;
7547
7548 rettv->v_type = VAR_STRING;
7549 rettv->vval.v_string = vim_strnsave(p + n, len);
7550}
7551
7552/*
7553 * "strridx()" function
7554 */
7555 static void
7556f_strridx(typval_T *argvars, typval_T *rettv)
7557{
7558 char_u buf[NUMBUFLEN];
7559 char_u *needle;
7560 char_u *haystack;
7561 char_u *rest;
7562 char_u *lastmatch = NULL;
7563 int haystack_len, end_idx;
7564
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007565 needle = tv_get_string_chk(&argvars[1]);
7566 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007567
7568 rettv->vval.v_number = -1;
7569 if (needle == NULL || haystack == NULL)
7570 return; /* type error; errmsg already given */
7571
7572 haystack_len = (int)STRLEN(haystack);
7573 if (argvars[2].v_type != VAR_UNKNOWN)
7574 {
7575 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007576 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007577 if (end_idx < 0)
7578 return; /* can never find a match */
7579 }
7580 else
7581 end_idx = haystack_len;
7582
7583 if (*needle == NUL)
7584 {
7585 /* Empty string matches past the end. */
7586 lastmatch = haystack + end_idx;
7587 }
7588 else
7589 {
7590 for (rest = haystack; *rest != '\0'; ++rest)
7591 {
7592 rest = (char_u *)strstr((char *)rest, (char *)needle);
7593 if (rest == NULL || rest > haystack + end_idx)
7594 break;
7595 lastmatch = rest;
7596 }
7597 }
7598
7599 if (lastmatch == NULL)
7600 rettv->vval.v_number = -1;
7601 else
7602 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
7603}
7604
7605/*
7606 * "strtrans()" function
7607 */
7608 static void
7609f_strtrans(typval_T *argvars, typval_T *rettv)
7610{
7611 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007612 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007613}
7614
7615/*
7616 * "submatch()" function
7617 */
7618 static void
7619f_submatch(typval_T *argvars, typval_T *rettv)
7620{
7621 int error = FALSE;
7622 int no;
7623 int retList = 0;
7624
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007625 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007626 if (error)
7627 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007628 if (no < 0 || no >= NSUBEXP)
7629 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007630 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01007631 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02007632 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007634 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007635 if (error)
7636 return;
7637
7638 if (retList == 0)
7639 {
7640 rettv->v_type = VAR_STRING;
7641 rettv->vval.v_string = reg_submatch(no);
7642 }
7643 else
7644 {
7645 rettv->v_type = VAR_LIST;
7646 rettv->vval.v_list = reg_submatch_list(no);
7647 }
7648}
7649
7650/*
7651 * "substitute()" function
7652 */
7653 static void
7654f_substitute(typval_T *argvars, typval_T *rettv)
7655{
7656 char_u patbuf[NUMBUFLEN];
7657 char_u subbuf[NUMBUFLEN];
7658 char_u flagsbuf[NUMBUFLEN];
7659
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007660 char_u *str = tv_get_string_chk(&argvars[0]);
7661 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007662 char_u *sub = NULL;
7663 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007664 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007665
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007666 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
7667 expr = &argvars[2];
7668 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007669 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007670
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007671 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007672 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
7673 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007674 rettv->vval.v_string = NULL;
7675 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02007676 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007677}
7678
7679/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007680 * "swapinfo(swap_filename)" function
7681 */
7682 static void
7683f_swapinfo(typval_T *argvars, typval_T *rettv)
7684{
7685 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007686 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02007687}
7688
7689/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02007690 * "swapname(expr)" function
7691 */
7692 static void
7693f_swapname(typval_T *argvars, typval_T *rettv)
7694{
7695 buf_T *buf;
7696
7697 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007698 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02007699 if (buf == NULL || buf->b_ml.ml_mfp == NULL
7700 || buf->b_ml.ml_mfp->mf_fname == NULL)
7701 rettv->vval.v_string = NULL;
7702 else
7703 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
7704}
7705
7706/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007707 * "synID(lnum, col, trans)" function
7708 */
7709 static void
7710f_synID(typval_T *argvars UNUSED, typval_T *rettv)
7711{
7712 int id = 0;
7713#ifdef FEAT_SYN_HL
7714 linenr_T lnum;
7715 colnr_T col;
7716 int trans;
7717 int transerr = FALSE;
7718
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007719 lnum = tv_get_lnum(argvars); /* -1 on type error */
7720 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
7721 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722
7723 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7724 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
7725 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
7726#endif
7727
7728 rettv->vval.v_number = id;
7729}
7730
7731/*
7732 * "synIDattr(id, what [, mode])" function
7733 */
7734 static void
7735f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
7736{
7737 char_u *p = NULL;
7738#ifdef FEAT_SYN_HL
7739 int id;
7740 char_u *what;
7741 char_u *mode;
7742 char_u modebuf[NUMBUFLEN];
7743 int modec;
7744
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007745 id = (int)tv_get_number(&argvars[0]);
7746 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747 if (argvars[2].v_type != VAR_UNKNOWN)
7748 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007749 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007750 modec = TOLOWER_ASC(mode[0]);
7751 if (modec != 't' && modec != 'c' && modec != 'g')
7752 modec = 0; /* replace invalid with current */
7753 }
7754 else
7755 {
7756#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
7757 if (USE_24BIT)
7758 modec = 'g';
7759 else
7760#endif
7761 if (t_colors > 1)
7762 modec = 'c';
7763 else
7764 modec = 't';
7765 }
7766
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007767 switch (TOLOWER_ASC(what[0]))
7768 {
7769 case 'b':
7770 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
7771 p = highlight_color(id, what, modec);
7772 else /* bold */
7773 p = highlight_has_attr(id, HL_BOLD, modec);
7774 break;
7775
7776 case 'f': /* fg[#] or font */
7777 p = highlight_color(id, what, modec);
7778 break;
7779
7780 case 'i':
7781 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
7782 p = highlight_has_attr(id, HL_INVERSE, modec);
7783 else /* italic */
7784 p = highlight_has_attr(id, HL_ITALIC, modec);
7785 break;
7786
7787 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02007788 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007789 break;
7790
7791 case 'r': /* reverse */
7792 p = highlight_has_attr(id, HL_INVERSE, modec);
7793 break;
7794
7795 case 's':
7796 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
7797 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02007798 /* strikeout */
7799 else if (TOLOWER_ASC(what[1]) == 't' &&
7800 TOLOWER_ASC(what[2]) == 'r')
7801 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007802 else /* standout */
7803 p = highlight_has_attr(id, HL_STANDOUT, modec);
7804 break;
7805
7806 case 'u':
7807 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
7808 /* underline */
7809 p = highlight_has_attr(id, HL_UNDERLINE, modec);
7810 else
7811 /* undercurl */
7812 p = highlight_has_attr(id, HL_UNDERCURL, modec);
7813 break;
7814 }
7815
7816 if (p != NULL)
7817 p = vim_strsave(p);
7818#endif
7819 rettv->v_type = VAR_STRING;
7820 rettv->vval.v_string = p;
7821}
7822
7823/*
7824 * "synIDtrans(id)" function
7825 */
7826 static void
7827f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
7828{
7829 int id;
7830
7831#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007832 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007833
7834 if (id > 0)
7835 id = syn_get_final_id(id);
7836 else
7837#endif
7838 id = 0;
7839
7840 rettv->vval.v_number = id;
7841}
7842
7843/*
7844 * "synconcealed(lnum, col)" function
7845 */
7846 static void
7847f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
7848{
7849#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
7850 linenr_T lnum;
7851 colnr_T col;
7852 int syntax_flags = 0;
7853 int cchar;
7854 int matchid = 0;
7855 char_u str[NUMBUFLEN];
7856#endif
7857
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007858 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859
7860#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007861 lnum = tv_get_lnum(argvars); /* -1 on type error */
7862 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007863
7864 vim_memset(str, NUL, sizeof(str));
7865
7866 if (rettv_list_alloc(rettv) != FAIL)
7867 {
7868 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7869 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7870 && curwin->w_p_cole > 0)
7871 {
7872 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
7873 syntax_flags = get_syntax_info(&matchid);
7874
7875 /* get the conceal character */
7876 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
7877 {
7878 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02007879 if (cchar == NUL && curwin->w_p_cole == 1)
7880 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007881 if (cchar != NUL)
7882 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007883 if (has_mbyte)
7884 (*mb_char2bytes)(cchar, str);
7885 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007886 str[0] = cchar;
7887 }
7888 }
7889 }
7890
7891 list_append_number(rettv->vval.v_list,
7892 (syntax_flags & HL_CONCEAL) != 0);
7893 /* -1 to auto-determine strlen */
7894 list_append_string(rettv->vval.v_list, str, -1);
7895 list_append_number(rettv->vval.v_list, matchid);
7896 }
7897#endif
7898}
7899
7900/*
7901 * "synstack(lnum, col)" function
7902 */
7903 static void
7904f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
7905{
7906#ifdef FEAT_SYN_HL
7907 linenr_T lnum;
7908 colnr_T col;
7909 int i;
7910 int id;
7911#endif
7912
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02007913 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914
7915#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007916 lnum = tv_get_lnum(argvars); /* -1 on type error */
7917 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918
7919 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
7920 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
7921 && rettv_list_alloc(rettv) != FAIL)
7922 {
7923 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
7924 for (i = 0; ; ++i)
7925 {
7926 id = syn_get_stack_item(i);
7927 if (id < 0)
7928 break;
7929 if (list_append_number(rettv->vval.v_list, id) == FAIL)
7930 break;
7931 }
7932 }
7933#endif
7934}
7935
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936/*
7937 * "tabpagebuflist()" function
7938 */
7939 static void
7940f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7941{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007942 tabpage_T *tp;
7943 win_T *wp = NULL;
7944
7945 if (argvars[0].v_type == VAR_UNKNOWN)
7946 wp = firstwin;
7947 else
7948 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007949 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007950 if (tp != NULL)
7951 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
7952 }
7953 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
7954 {
7955 for (; wp != NULL; wp = wp->w_next)
7956 if (list_append_number(rettv->vval.v_list,
7957 wp->w_buffer->b_fnum) == FAIL)
7958 break;
7959 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960}
7961
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007962/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007963 * "tagfiles()" function
7964 */
7965 static void
7966f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
7967{
7968 char_u *fname;
7969 tagname_T tn;
7970 int first;
7971
7972 if (rettv_list_alloc(rettv) == FAIL)
7973 return;
7974 fname = alloc(MAXPATHL);
7975 if (fname == NULL)
7976 return;
7977
7978 for (first = TRUE; ; first = FALSE)
7979 if (get_tagfname(&tn, first, fname) == FAIL
7980 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
7981 break;
7982 tagname_free(&tn);
7983 vim_free(fname);
7984}
7985
7986/*
7987 * "taglist()" function
7988 */
7989 static void
7990f_taglist(typval_T *argvars, typval_T *rettv)
7991{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01007992 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007993 char_u *tag_pattern;
7994
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007995 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007996
7997 rettv->vval.v_number = FALSE;
7998 if (*tag_pattern == NUL)
7999 return;
8000
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008001 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008002 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008003 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01008004 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008005}
8006
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008007#ifdef FEAT_FLOAT
8008/*
8009 * "tan()" function
8010 */
8011 static void
8012f_tan(typval_T *argvars, typval_T *rettv)
8013{
8014 float_T f = 0.0;
8015
8016 rettv->v_type = VAR_FLOAT;
8017 if (get_float_arg(argvars, &f) == OK)
8018 rettv->vval.v_float = tan(f);
8019 else
8020 rettv->vval.v_float = 0.0;
8021}
8022
8023/*
8024 * "tanh()" function
8025 */
8026 static void
8027f_tanh(typval_T *argvars, typval_T *rettv)
8028{
8029 float_T f = 0.0;
8030
8031 rettv->v_type = VAR_FLOAT;
8032 if (get_float_arg(argvars, &f) == OK)
8033 rettv->vval.v_float = tanh(f);
8034 else
8035 rettv->vval.v_float = 0.0;
8036}
8037#endif
8038
8039/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008040 * "tolower(string)" function
8041 */
8042 static void
8043f_tolower(typval_T *argvars, typval_T *rettv)
8044{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008045 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008046 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008047}
8048
8049/*
8050 * "toupper(string)" function
8051 */
8052 static void
8053f_toupper(typval_T *argvars, typval_T *rettv)
8054{
8055 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008056 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008057}
8058
8059/*
8060 * "tr(string, fromstr, tostr)" function
8061 */
8062 static void
8063f_tr(typval_T *argvars, typval_T *rettv)
8064{
8065 char_u *in_str;
8066 char_u *fromstr;
8067 char_u *tostr;
8068 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008069 int inlen;
8070 int fromlen;
8071 int tolen;
8072 int idx;
8073 char_u *cpstr;
8074 int cplen;
8075 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008076 char_u buf[NUMBUFLEN];
8077 char_u buf2[NUMBUFLEN];
8078 garray_T ga;
8079
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008080 in_str = tv_get_string(&argvars[0]);
8081 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
8082 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083
8084 /* Default return value: empty string. */
8085 rettv->v_type = VAR_STRING;
8086 rettv->vval.v_string = NULL;
8087 if (fromstr == NULL || tostr == NULL)
8088 return; /* type error; errmsg already given */
8089 ga_init2(&ga, (int)sizeof(char), 80);
8090
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008091 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008092 /* not multi-byte: fromstr and tostr must be the same length */
8093 if (STRLEN(fromstr) != STRLEN(tostr))
8094 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008095error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008096 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008097 ga_clear(&ga);
8098 return;
8099 }
8100
8101 /* fromstr and tostr have to contain the same number of chars */
8102 while (*in_str != NUL)
8103 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008104 if (has_mbyte)
8105 {
8106 inlen = (*mb_ptr2len)(in_str);
8107 cpstr = in_str;
8108 cplen = inlen;
8109 idx = 0;
8110 for (p = fromstr; *p != NUL; p += fromlen)
8111 {
8112 fromlen = (*mb_ptr2len)(p);
8113 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
8114 {
8115 for (p = tostr; *p != NUL; p += tolen)
8116 {
8117 tolen = (*mb_ptr2len)(p);
8118 if (idx-- == 0)
8119 {
8120 cplen = tolen;
8121 cpstr = p;
8122 break;
8123 }
8124 }
8125 if (*p == NUL) /* tostr is shorter than fromstr */
8126 goto error;
8127 break;
8128 }
8129 ++idx;
8130 }
8131
8132 if (first && cpstr == in_str)
8133 {
8134 /* Check that fromstr and tostr have the same number of
8135 * (multi-byte) characters. Done only once when a character
8136 * of in_str doesn't appear in fromstr. */
8137 first = FALSE;
8138 for (p = tostr; *p != NUL; p += tolen)
8139 {
8140 tolen = (*mb_ptr2len)(p);
8141 --idx;
8142 }
8143 if (idx != 0)
8144 goto error;
8145 }
8146
8147 (void)ga_grow(&ga, cplen);
8148 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
8149 ga.ga_len += cplen;
8150
8151 in_str += inlen;
8152 }
8153 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008154 {
8155 /* When not using multi-byte chars we can do it faster. */
8156 p = vim_strchr(fromstr, *in_str);
8157 if (p != NULL)
8158 ga_append(&ga, tostr[p - fromstr]);
8159 else
8160 ga_append(&ga, *in_str);
8161 ++in_str;
8162 }
8163 }
8164
8165 /* add a terminating NUL */
8166 (void)ga_grow(&ga, 1);
8167 ga_append(&ga, NUL);
8168
8169 rettv->vval.v_string = ga.ga_data;
8170}
8171
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008172/*
8173 * "trim({expr})" function
8174 */
8175 static void
8176f_trim(typval_T *argvars, typval_T *rettv)
8177{
8178 char_u buf1[NUMBUFLEN];
8179 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008180 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008181 char_u *mask = NULL;
8182 char_u *tail;
8183 char_u *prev;
8184 char_u *p;
8185 int c1;
8186
8187 rettv->v_type = VAR_STRING;
8188 if (head == NULL)
8189 {
8190 rettv->vval.v_string = NULL;
8191 return;
8192 }
8193
8194 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008195 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01008196
8197 while (*head != NUL)
8198 {
8199 c1 = PTR2CHAR(head);
8200 if (mask == NULL)
8201 {
8202 if (c1 > ' ' && c1 != 0xa0)
8203 break;
8204 }
8205 else
8206 {
8207 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8208 if (c1 == PTR2CHAR(p))
8209 break;
8210 if (*p == NUL)
8211 break;
8212 }
8213 MB_PTR_ADV(head);
8214 }
8215
8216 for (tail = head + STRLEN(head); tail > head; tail = prev)
8217 {
8218 prev = tail;
8219 MB_PTR_BACK(head, prev);
8220 c1 = PTR2CHAR(prev);
8221 if (mask == NULL)
8222 {
8223 if (c1 > ' ' && c1 != 0xa0)
8224 break;
8225 }
8226 else
8227 {
8228 for (p = mask; *p != NUL; MB_PTR_ADV(p))
8229 if (c1 == PTR2CHAR(p))
8230 break;
8231 if (*p == NUL)
8232 break;
8233 }
8234 }
8235 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
8236}
8237
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008238#ifdef FEAT_FLOAT
8239/*
8240 * "trunc({float})" function
8241 */
8242 static void
8243f_trunc(typval_T *argvars, typval_T *rettv)
8244{
8245 float_T f = 0.0;
8246
8247 rettv->v_type = VAR_FLOAT;
8248 if (get_float_arg(argvars, &f) == OK)
8249 /* trunc() is not in C90, use floor() or ceil() instead. */
8250 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
8251 else
8252 rettv->vval.v_float = 0.0;
8253}
8254#endif
8255
8256/*
8257 * "type(expr)" function
8258 */
8259 static void
8260f_type(typval_T *argvars, typval_T *rettv)
8261{
8262 int n = -1;
8263
8264 switch (argvars[0].v_type)
8265 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02008266 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
8267 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008268 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02008269 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
8270 case VAR_LIST: n = VAR_TYPE_LIST; break;
8271 case VAR_DICT: n = VAR_TYPE_DICT; break;
8272 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008273 case VAR_SPECIAL:
8274 if (argvars[0].vval.v_number == VVAL_FALSE
8275 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02008276 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008277 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02008278 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008279 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02008280 case VAR_JOB: n = VAR_TYPE_JOB; break;
8281 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008282 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008283 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01008284 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008285 n = -1;
8286 break;
8287 }
8288 rettv->vval.v_number = n;
8289}
8290
8291/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008292 * "virtcol(string)" function
8293 */
8294 static void
8295f_virtcol(typval_T *argvars, typval_T *rettv)
8296{
8297 colnr_T vcol = 0;
8298 pos_T *fp;
8299 int fnum = curbuf->b_fnum;
8300
8301 fp = var2fpos(&argvars[0], FALSE, &fnum);
8302 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
8303 && fnum == curbuf->b_fnum)
8304 {
8305 getvvcol(curwin, fp, NULL, NULL, &vcol);
8306 ++vcol;
8307 }
8308
8309 rettv->vval.v_number = vcol;
8310}
8311
8312/*
8313 * "visualmode()" function
8314 */
8315 static void
8316f_visualmode(typval_T *argvars, typval_T *rettv)
8317{
8318 char_u str[2];
8319
8320 rettv->v_type = VAR_STRING;
8321 str[0] = curbuf->b_visual_mode_eval;
8322 str[1] = NUL;
8323 rettv->vval.v_string = vim_strsave(str);
8324
8325 /* A non-zero number or non-empty string argument: reset mode. */
8326 if (non_zero_arg(&argvars[0]))
8327 curbuf->b_visual_mode_eval = NUL;
8328}
8329
8330/*
8331 * "wildmenumode()" function
8332 */
8333 static void
8334f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8335{
8336#ifdef FEAT_WILDMENU
8337 if (wild_menu_showing)
8338 rettv->vval.v_number = 1;
8339#endif
8340}
8341
8342/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008343 * "wordcount()" function
8344 */
8345 static void
8346f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
8347{
8348 if (rettv_dict_alloc(rettv) == FAIL)
8349 return;
8350 cursor_pos_info(rettv->vval.v_dict);
8351}
8352
8353/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008354 * "xor(expr, expr)" function
8355 */
8356 static void
8357f_xor(typval_T *argvars, typval_T *rettv)
8358{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008359 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8360 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008361}
8362
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008363#endif /* FEAT_EVAL */