blob: e14aa0452e9cb6176d99451f1870dcd32bdeb74c [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);
32static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020033static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020034#ifdef FEAT_FLOAT
35static void f_asin(typval_T *argvars, typval_T *rettv);
36static void f_atan(typval_T *argvars, typval_T *rettv);
37static void f_atan2(typval_T *argvars, typval_T *rettv);
38#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010039#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020040static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010041static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010042# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010043static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010044# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010045#endif
Bram Moolenaar15e248e2019-06-30 20:21:37 +020046static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020047static void f_bufexists(typval_T *argvars, typval_T *rettv);
48static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020049static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_bufloaded(typval_T *argvars, typval_T *rettv);
51static void f_bufname(typval_T *argvars, typval_T *rettv);
52static void f_bufnr(typval_T *argvars, typval_T *rettv);
53static void f_bufwinid(typval_T *argvars, typval_T *rettv);
54static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
55static void f_byte2line(typval_T *argvars, typval_T *rettv);
56static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
57static void f_byteidx(typval_T *argvars, typval_T *rettv);
58static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
59static void f_call(typval_T *argvars, typval_T *rettv);
60#ifdef FEAT_FLOAT
61static void f_ceil(typval_T *argvars, typval_T *rettv);
62#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020063static void f_changenr(typval_T *argvars, typval_T *rettv);
64static void f_char2nr(typval_T *argvars, typval_T *rettv);
65static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020066static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020067static void f_confirm(typval_T *argvars, typval_T *rettv);
68static void f_copy(typval_T *argvars, typval_T *rettv);
69#ifdef FEAT_FLOAT
70static void f_cos(typval_T *argvars, typval_T *rettv);
71static void f_cosh(typval_T *argvars, typval_T *rettv);
72#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
74static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010075#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020076static void f_debugbreak(typval_T *argvars, typval_T *rettv);
77#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020078static void f_deepcopy(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020079static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020080static void f_did_filetype(typval_T *argvars, typval_T *rettv);
81static void f_diff_filler(typval_T *argvars, typval_T *rettv);
82static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
83static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020084static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_escape(typval_T *argvars, typval_T *rettv);
86static void f_eval(typval_T *argvars, typval_T *rettv);
87static void f_eventhandler(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020088static void f_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_exists(typval_T *argvars, typval_T *rettv);
90#ifdef FEAT_FLOAT
91static void f_exp(typval_T *argvars, typval_T *rettv);
92#endif
93static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +020094static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020095static void f_feedkeys(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020096#ifdef FEAT_FLOAT
97static void f_float2nr(typval_T *argvars, typval_T *rettv);
98static void f_floor(typval_T *argvars, typval_T *rettv);
99static void f_fmod(typval_T *argvars, typval_T *rettv);
100#endif
101static void f_fnameescape(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200102static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200103static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200104static void f_function(typval_T *argvars, typval_T *rettv);
105static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
106static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200107static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200108static void f_getbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100109static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200110static void f_getchar(typval_T *argvars, typval_T *rettv);
111static void f_getcharmod(typval_T *argvars, typval_T *rettv);
112static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200113static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200114static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200115static void f_getfontname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100116static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200117static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_getpid(typval_T *argvars, typval_T *rettv);
119static void f_getcurpos(typval_T *argvars, typval_T *rettv);
120static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200121static void f_getreg(typval_T *argvars, typval_T *rettv);
122static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200123static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100124static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200125static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100126static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127static void f_getwinposx(typval_T *argvars, typval_T *rettv);
128static void f_getwinposy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200129static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200130static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
131static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200132static void f_hlID(typval_T *argvars, typval_T *rettv);
133static void f_hlexists(typval_T *argvars, typval_T *rettv);
134static void f_hostname(typval_T *argvars, typval_T *rettv);
135static void f_iconv(typval_T *argvars, typval_T *rettv);
136static void f_indent(typval_T *argvars, typval_T *rettv);
137static void f_index(typval_T *argvars, typval_T *rettv);
138static void f_input(typval_T *argvars, typval_T *rettv);
139static void f_inputdialog(typval_T *argvars, typval_T *rettv);
140static void f_inputlist(typval_T *argvars, typval_T *rettv);
141static void f_inputrestore(typval_T *argvars, typval_T *rettv);
142static void f_inputsave(typval_T *argvars, typval_T *rettv);
143static void f_inputsecret(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200144static void f_invert(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200145static void f_islocked(typval_T *argvars, typval_T *rettv);
146#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200147static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200148static void f_isnan(typval_T *argvars, typval_T *rettv);
149#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200150static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
151static void f_len(typval_T *argvars, typval_T *rettv);
152static void f_libcall(typval_T *argvars, typval_T *rettv);
153static void f_libcallnr(typval_T *argvars, typval_T *rettv);
154static void f_line(typval_T *argvars, typval_T *rettv);
155static void f_line2byte(typval_T *argvars, typval_T *rettv);
156static void f_lispindent(typval_T *argvars, typval_T *rettv);
157static void f_localtime(typval_T *argvars, typval_T *rettv);
158#ifdef FEAT_FLOAT
159static void f_log(typval_T *argvars, typval_T *rettv);
160static void f_log10(typval_T *argvars, typval_T *rettv);
161#endif
162#ifdef FEAT_LUA
163static void f_luaeval(typval_T *argvars, typval_T *rettv);
164#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200165static void f_maparg(typval_T *argvars, typval_T *rettv);
166static void f_mapcheck(typval_T *argvars, typval_T *rettv);
167static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200168static void f_matchend(typval_T *argvars, typval_T *rettv);
169static void f_matchlist(typval_T *argvars, typval_T *rettv);
170static void f_matchstr(typval_T *argvars, typval_T *rettv);
171static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
172static void f_max(typval_T *argvars, typval_T *rettv);
173static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200174static void f_mode(typval_T *argvars, typval_T *rettv);
175#ifdef FEAT_MZSCHEME
176static void f_mzeval(typval_T *argvars, typval_T *rettv);
177#endif
178static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
179static void f_nr2char(typval_T *argvars, typval_T *rettv);
180static void f_or(typval_T *argvars, typval_T *rettv);
181static void f_pathshorten(typval_T *argvars, typval_T *rettv);
182#ifdef FEAT_PERL
183static void f_perleval(typval_T *argvars, typval_T *rettv);
184#endif
185#ifdef FEAT_FLOAT
186static void f_pow(typval_T *argvars, typval_T *rettv);
187#endif
188static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
189static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200190static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200191static void f_pumvisible(typval_T *argvars, typval_T *rettv);
192#ifdef FEAT_PYTHON3
193static void f_py3eval(typval_T *argvars, typval_T *rettv);
194#endif
195#ifdef FEAT_PYTHON
196static void f_pyeval(typval_T *argvars, typval_T *rettv);
197#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100198#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
199static void f_pyxeval(typval_T *argvars, typval_T *rettv);
200#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200201static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200202static void f_reg_executing(typval_T *argvars, typval_T *rettv);
203static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204static void f_reltime(typval_T *argvars, typval_T *rettv);
205#ifdef FEAT_FLOAT
206static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
207#endif
208static void f_reltimestr(typval_T *argvars, typval_T *rettv);
209static void f_remote_expr(typval_T *argvars, typval_T *rettv);
210static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
211static void f_remote_peek(typval_T *argvars, typval_T *rettv);
212static void f_remote_read(typval_T *argvars, typval_T *rettv);
213static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100214static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200215static void f_rename(typval_T *argvars, typval_T *rettv);
216static void f_repeat(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200217#ifdef FEAT_FLOAT
218static void f_round(typval_T *argvars, typval_T *rettv);
219#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100220#ifdef FEAT_RUBY
221static void f_rubyeval(typval_T *argvars, typval_T *rettv);
222#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200223static void f_screenattr(typval_T *argvars, typval_T *rettv);
224static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100225static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200226static void f_screencol(typval_T *argvars, typval_T *rettv);
227static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100228static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200229static void f_search(typval_T *argvars, typval_T *rettv);
230static void f_searchdecl(typval_T *argvars, typval_T *rettv);
231static void f_searchpair(typval_T *argvars, typval_T *rettv);
232static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
233static void f_searchpos(typval_T *argvars, typval_T *rettv);
234static void f_server2client(typval_T *argvars, typval_T *rettv);
235static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200236static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200237static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200238static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200239static void f_setfperm(typval_T *argvars, typval_T *rettv);
240static void f_setline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200241static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200242static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100243static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200244#ifdef FEAT_CRYPT
245static void f_sha256(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb005cd82019-09-04 15:54:55 +0200246#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200247static void f_shellescape(typval_T *argvars, typval_T *rettv);
248static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200249#ifdef FEAT_FLOAT
250static void f_sin(typval_T *argvars, typval_T *rettv);
251static void f_sinh(typval_T *argvars, typval_T *rettv);
252#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200253static void f_soundfold(typval_T *argvars, typval_T *rettv);
254static void f_spellbadword(typval_T *argvars, typval_T *rettv);
255static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
256static void f_split(typval_T *argvars, typval_T *rettv);
257#ifdef FEAT_FLOAT
258static void f_sqrt(typval_T *argvars, typval_T *rettv);
259static void f_str2float(typval_T *argvars, typval_T *rettv);
260#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200261static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200262static void f_str2nr(typval_T *argvars, typval_T *rettv);
263static void f_strchars(typval_T *argvars, typval_T *rettv);
264#ifdef HAVE_STRFTIME
265static void f_strftime(typval_T *argvars, typval_T *rettv);
266#endif
267static void f_strgetchar(typval_T *argvars, typval_T *rettv);
268static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200269static void f_strlen(typval_T *argvars, typval_T *rettv);
270static void f_strcharpart(typval_T *argvars, typval_T *rettv);
271static void f_strpart(typval_T *argvars, typval_T *rettv);
272static void f_strridx(typval_T *argvars, typval_T *rettv);
273static void f_strtrans(typval_T *argvars, typval_T *rettv);
274static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
275static void f_strwidth(typval_T *argvars, typval_T *rettv);
276static void f_submatch(typval_T *argvars, typval_T *rettv);
277static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200278static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200279static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200280static void f_synID(typval_T *argvars, typval_T *rettv);
281static void f_synIDattr(typval_T *argvars, typval_T *rettv);
282static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
283static void f_synstack(typval_T *argvars, typval_T *rettv);
284static void f_synconcealed(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200285static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
286static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
287static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
288static void f_taglist(typval_T *argvars, typval_T *rettv);
289static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200290#ifdef FEAT_FLOAT
291static void f_tan(typval_T *argvars, typval_T *rettv);
292static void f_tanh(typval_T *argvars, typval_T *rettv);
293#endif
294#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200295static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200296static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200297static void f_timer_start(typval_T *argvars, typval_T *rettv);
298static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200299static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200300#endif
301static void f_tolower(typval_T *argvars, typval_T *rettv);
302static void f_toupper(typval_T *argvars, typval_T *rettv);
303static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100304static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200305#ifdef FEAT_FLOAT
306static void f_trunc(typval_T *argvars, typval_T *rettv);
307#endif
308static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200309static void f_virtcol(typval_T *argvars, typval_T *rettv);
310static void f_visualmode(typval_T *argvars, typval_T *rettv);
311static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200312static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200313static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
314static void f_win_getid(typval_T *argvars, typval_T *rettv);
315static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
316static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
317static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100318static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200319static void f_winbufnr(typval_T *argvars, typval_T *rettv);
320static void f_wincol(typval_T *argvars, typval_T *rettv);
321static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200322static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200323static void f_winline(typval_T *argvars, typval_T *rettv);
324static void f_winnr(typval_T *argvars, typval_T *rettv);
325static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
326static void f_winrestview(typval_T *argvars, typval_T *rettv);
327static void f_winsaveview(typval_T *argvars, typval_T *rettv);
328static void f_winwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200329static void f_wordcount(typval_T *argvars, typval_T *rettv);
330static void f_xor(typval_T *argvars, typval_T *rettv);
331
332/*
333 * Array with names and number of arguments of all internal functions
334 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
335 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200336typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200337{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200338 char *f_name; // function name
339 char f_min_argc; // minimal number of arguments
340 char f_max_argc; // maximal number of arguments
341 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200342 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200343 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200344} funcentry_T;
345
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200346// values for f_argtype; zero means it cannot be used as a method
347#define FEARG_1 1 // base is the first argument
348#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200349#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200350#define FEARG_LAST 9 // base is the last argument
351
Bram Moolenaarac92e252019-08-03 21:58:38 +0200352static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353{
354#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200355 {"abs", 1, 1, FEARG_1, f_abs},
356 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200357#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200358 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200359 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200360 {"append", 2, 2, FEARG_LAST, f_append},
361 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
362 {"argc", 0, 1, 0, f_argc},
363 {"argidx", 0, 0, 0, f_argidx},
364 {"arglistid", 0, 2, 0, f_arglistid},
365 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200366#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200367 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200368#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200369 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200370 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200371 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200372 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200373 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
374 {"assert_false", 1, 2, FEARG_1, f_assert_false},
375 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
376 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200377 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200378 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200379 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200380 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200382 {"atan", 1, 1, FEARG_1, f_atan},
383 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200384#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100385#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200386 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200387 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100388# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200389 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100390# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100391#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200392 {"browse", 4, 4, 0, f_browse},
393 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200394 {"bufadd", 1, 1, FEARG_1, f_bufadd},
395 {"bufexists", 1, 1, FEARG_1, f_bufexists},
396 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200397 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
398 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200399 {"buflisted", 1, 1, FEARG_1, f_buflisted},
400 {"bufload", 1, 1, FEARG_1, f_bufload},
401 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200402 {"bufname", 0, 1, FEARG_1, f_bufname},
403 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200404 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
405 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200406 {"byte2line", 1, 1, FEARG_1, f_byte2line},
407 {"byteidx", 2, 2, FEARG_1, f_byteidx},
408 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
409 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200410#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200411 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200412#endif
413#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200414 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
415 {"ch_close", 1, 1, FEARG_1, f_ch_close},
416 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
417 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
418 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
419 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
420 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
421 {"ch_info", 1, 1, FEARG_1, f_ch_info},
422 {"ch_log", 1, 2, FEARG_1, f_ch_log},
423 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
424 {"ch_open", 1, 2, FEARG_1, f_ch_open},
425 {"ch_read", 1, 2, FEARG_1, f_ch_read},
426 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
427 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
428 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
429 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
430 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
431 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200432#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200433 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200434 {"char2nr", 1, 2, FEARG_1, f_char2nr},
435 {"chdir", 1, 1, FEARG_1, f_chdir},
436 {"cindent", 1, 1, FEARG_1, f_cindent},
437 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
438 {"col", 1, 1, FEARG_1, f_col},
439 {"complete", 2, 2, FEARG_2, f_complete},
440 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200441 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200442 {"complete_info", 0, 1, FEARG_1, f_complete_info},
443 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200444 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200445#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200446 {"cos", 1, 1, FEARG_1, f_cos},
447 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200448#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200449 {"count", 2, 4, FEARG_1, f_count},
450 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200451 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100452#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200453 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200454#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200455 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
456 {"delete", 1, 2, FEARG_1, f_delete},
457 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200458 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200459 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
460 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200461 {"empty", 1, 1, FEARG_1, f_empty},
462 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200463 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200464 {"eval", 1, 1, FEARG_1, f_eval},
465 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200466 {"executable", 1, 1, FEARG_1, f_executable},
467 {"execute", 1, 2, FEARG_1, f_execute},
468 {"exepath", 1, 1, FEARG_1, f_exepath},
469 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200470#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200471 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200472#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200473 {"expand", 1, 3, FEARG_1, f_expand},
474 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200475 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200476 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
477 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
478 {"filereadable", 1, 1, FEARG_1, f_filereadable},
479 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200480 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200481 {"finddir", 1, 3, FEARG_1, f_finddir},
482 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200483#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200484 {"float2nr", 1, 1, FEARG_1, f_float2nr},
485 {"floor", 1, 1, FEARG_1, f_floor},
486 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200487#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200488 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
489 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
490 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
491 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
492 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200493 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200494 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200495 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200496 {"funcref", 1, 3, FEARG_1, f_funcref},
497 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200498 {"garbagecollect", 0, 1, 0, f_garbagecollect},
499 {"get", 2, 3, FEARG_1, f_get},
500 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200501 {"getbufline", 2, 3, FEARG_1, f_getbufline},
502 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
503 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"getchar", 0, 1, 0, f_getchar},
505 {"getcharmod", 0, 0, 0, f_getcharmod},
506 {"getcharsearch", 0, 0, 0, f_getcharsearch},
507 {"getcmdline", 0, 0, 0, f_getcmdline},
508 {"getcmdpos", 0, 0, 0, f_getcmdpos},
509 {"getcmdtype", 0, 0, 0, f_getcmdtype},
510 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200511 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200512 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200513 {"getcwd", 0, 2, FEARG_1, f_getcwd},
514 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200515 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200516 {"getfperm", 1, 1, FEARG_1, f_getfperm},
517 {"getfsize", 1, 1, FEARG_1, f_getfsize},
518 {"getftime", 1, 1, FEARG_1, f_getftime},
519 {"getftype", 1, 1, FEARG_1, f_getftype},
520 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
521 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200522 {"getloclist", 1, 2, 0, f_getloclist},
523 {"getmatches", 0, 1, 0, f_getmatches},
524 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200525 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200526 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200527 {"getreg", 0, 3, FEARG_1, f_getreg},
528 {"getregtype", 0, 1, FEARG_1, f_getregtype},
529 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
530 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
531 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200532 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
533 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
534 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200535 {"getwinposx", 0, 0, 0, f_getwinposx},
536 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200537 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
538 {"glob", 1, 4, FEARG_1, f_glob},
539 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
540 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200541 {"has", 1, 1, 0, f_has},
542 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200543 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
544 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
545 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
546 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
547 {"histadd", 2, 2, FEARG_2, f_histadd},
548 {"histdel", 1, 2, FEARG_1, f_histdel},
549 {"histget", 1, 2, FEARG_1, f_histget},
550 {"histnr", 1, 1, FEARG_1, f_histnr},
551 {"hlID", 1, 1, FEARG_1, f_hlID},
552 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200553 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200554 {"iconv", 3, 3, FEARG_1, f_iconv},
555 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200556 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200557 {"input", 1, 3, FEARG_1, f_input},
558 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
559 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200560 {"inputrestore", 0, 0, 0, f_inputrestore},
561 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200562 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200563 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200564 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200565 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200566#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200567 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200568#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200569 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200570#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200571 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200572#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200573 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200574#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200575 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
576 {"job_info", 0, 1, FEARG_1, f_job_info},
577 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
578 {"job_start", 1, 2, FEARG_1, f_job_start},
579 {"job_status", 1, 1, FEARG_1, f_job_status},
580 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200581#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200582 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200583 {"js_decode", 1, 1, FEARG_1, f_js_decode},
584 {"js_encode", 1, 1, FEARG_1, f_js_encode},
585 {"json_decode", 1, 1, FEARG_1, f_json_decode},
586 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200587 {"keys", 1, 1, FEARG_1, f_keys},
588 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
589 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200590 {"libcall", 3, 3, FEARG_3, f_libcall},
591 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200592 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200593 {"line2byte", 1, 1, FEARG_1, f_line2byte},
594 {"lispindent", 1, 1, FEARG_1, f_lispindent},
595 {"list2str", 1, 2, FEARG_1, f_list2str},
596 {"listener_add", 1, 2, FEARG_2, f_listener_add},
597 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
598 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200599 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200600#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200601 {"log", 1, 1, FEARG_1, f_log},
602 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200603#endif
604#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200605 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200606#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200607 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200608 {"maparg", 1, 4, FEARG_1, f_maparg},
609 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
610 {"match", 2, 4, FEARG_1, f_match},
611 {"matchadd", 2, 5, FEARG_1, f_matchadd},
612 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
613 {"matcharg", 1, 1, FEARG_1, f_matcharg},
614 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
615 {"matchend", 2, 4, FEARG_1, f_matchend},
616 {"matchlist", 2, 4, FEARG_1, f_matchlist},
617 {"matchstr", 2, 4, FEARG_1, f_matchstr},
618 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200619 {"max", 1, 1, FEARG_1, f_max},
620 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200621 {"mkdir", 1, 3, FEARG_1, f_mkdir},
622 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200623#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200624 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200626 {"nextnonblank", 1, 1, FEARG_1, f_nextnonblank},
627 {"nr2char", 1, 2, FEARG_1, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200628 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200629 {"pathshorten", 1, 1, FEARG_1, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200630#ifdef FEAT_PERL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200631 {"perleval", 1, 1, FEARG_1, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200633#ifdef FEAT_TEXT_PROP
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200634 {"popup_atcursor", 2, 2, FEARG_1, f_popup_atcursor},
635 {"popup_beval", 2, 2, FEARG_1, f_popup_beval},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200636 {"popup_clear", 0, 0, 0, f_popup_clear},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200637 {"popup_close", 1, 2, FEARG_1, f_popup_close},
638 {"popup_create", 2, 2, FEARG_1, f_popup_create},
639 {"popup_dialog", 2, 2, FEARG_1, f_popup_dialog},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200640 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
641 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200642 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
643 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200644 {"popup_getoptions", 1, 1, FEARG_1, f_popup_getoptions},
645 {"popup_getpos", 1, 1, FEARG_1, f_popup_getpos},
646 {"popup_hide", 1, 1, FEARG_1, f_popup_hide},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200647 {"popup_locate", 2, 2, 0, f_popup_locate},
Bram Moolenaar6a124e62019-09-04 18:15:19 +0200648 {"popup_menu", 2, 2, FEARG_1, f_popup_menu},
649 {"popup_move", 2, 2, FEARG_1, f_popup_move},
650 {"popup_notification", 2, 2, FEARG_1, f_popup_notification},
651 {"popup_setoptions", 2, 2, FEARG_1, f_popup_setoptions},
652 {"popup_settext", 2, 2, FEARG_1, f_popup_settext},
653 {"popup_show", 1, 1, FEARG_1, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200654#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200656 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657#endif
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200658 {"prevnonblank", 1, 1, FEARG_1, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200659 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200660#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200661 {"prompt_setcallback", 2, 2, FEARG_1, f_prompt_setcallback},
662 {"prompt_setinterrupt", 2, 2, FEARG_1, f_prompt_setinterrupt},
663 {"prompt_setprompt", 2, 2, FEARG_1, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200664#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100665#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200666 {"prop_add", 3, 3, 0, f_prop_add},
667 {"prop_clear", 1, 3, 0, f_prop_clear},
668 {"prop_list", 1, 2, 0, f_prop_list},
669 {"prop_remove", 1, 3, 0, f_prop_remove},
670 {"prop_type_add", 2, 2, 0, f_prop_type_add},
671 {"prop_type_change", 2, 2, 0, f_prop_type_change},
672 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
673 {"prop_type_get", 1, 2, 0, f_prop_type_get},
674 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100675#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200676 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200677 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200678#ifdef FEAT_PYTHON3
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200679 {"py3eval", 1, 1, FEARG_1, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680#endif
681#ifdef FEAT_PYTHON
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200682 {"pyeval", 1, 1, FEARG_1, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200683#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100684#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar3f4f3d82019-09-04 20:05:59 +0200685 {"pyxeval", 1, 1, FEARG_1, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100686#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200687 {"range", 1, 3, 0, f_range},
688 {"readdir", 1, 2, 0, f_readdir},
689 {"readfile", 1, 3, 0, f_readfile},
690 {"reg_executing", 0, 0, 0, f_reg_executing},
691 {"reg_recording", 0, 0, 0, f_reg_recording},
692 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200694 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200695#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200696 {"reltimestr", 1, 1, 0, f_reltimestr},
697 {"remote_expr", 2, 4, 0, f_remote_expr},
698 {"remote_foreground", 1, 1, 0, f_remote_foreground},
699 {"remote_peek", 1, 2, 0, f_remote_peek},
700 {"remote_read", 1, 2, 0, f_remote_read},
701 {"remote_send", 2, 3, 0, f_remote_send},
702 {"remote_startserver", 1, 1, 0, f_remote_startserver},
703 {"remove", 2, 3, FEARG_1, f_remove},
704 {"rename", 2, 2, 0, f_rename},
705 {"repeat", 2, 2, FEARG_1, f_repeat},
706 {"resolve", 1, 1, 0, f_resolve},
707 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200708#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200709 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200710#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100711#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200712 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100713#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200714 {"screenattr", 2, 2, 0, f_screenattr},
715 {"screenchar", 2, 2, 0, f_screenchar},
716 {"screenchars", 2, 2, 0, f_screenchars},
717 {"screencol", 0, 0, 0, f_screencol},
718 {"screenpos", 3, 3, 0, f_screenpos},
719 {"screenrow", 0, 0, 0, f_screenrow},
720 {"screenstring", 2, 2, 0, f_screenstring},
721 {"search", 1, 4, 0, f_search},
722 {"searchdecl", 1, 3, 0, f_searchdecl},
723 {"searchpair", 3, 7, 0, f_searchpair},
724 {"searchpairpos", 3, 7, 0, f_searchpairpos},
725 {"searchpos", 1, 4, 0, f_searchpos},
726 {"server2client", 2, 2, 0, f_server2client},
727 {"serverlist", 0, 0, 0, f_serverlist},
728 {"setbufline", 3, 3, 0, f_setbufline},
729 {"setbufvar", 3, 3, 0, f_setbufvar},
730 {"setcharsearch", 1, 1, 0, f_setcharsearch},
731 {"setcmdpos", 1, 1, 0, f_setcmdpos},
732 {"setenv", 2, 2, 0, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200733 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200734 {"setline", 2, 2, 0, f_setline},
735 {"setloclist", 2, 4, 0, f_setloclist},
736 {"setmatches", 1, 2, 0, f_setmatches},
737 {"setpos", 2, 2, 0, f_setpos},
738 {"setqflist", 1, 3, 0, f_setqflist},
739 {"setreg", 2, 3, 0, f_setreg},
740 {"settabvar", 3, 3, 0, f_settabvar},
741 {"settabwinvar", 4, 4, 0, f_settabwinvar},
742 {"settagstack", 2, 3, 0, f_settagstack},
743 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200744#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200745 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200746#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200747 {"shellescape", 1, 2, 0, f_shellescape},
748 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100749#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200750 {"sign_define", 1, 2, 0, f_sign_define},
751 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
752 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
753 {"sign_jump", 3, 3, 0, f_sign_jump},
754 {"sign_place", 4, 5, 0, f_sign_place},
755 {"sign_placelist", 1, 1, 0, f_sign_placelist},
756 {"sign_undefine", 0, 1, 0, f_sign_undefine},
757 {"sign_unplace", 1, 2, 0, f_sign_unplace},
758 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100759#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200760 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200761#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200762 {"sin", 1, 1, FEARG_1, f_sin},
763 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200764#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200765 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200766#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200767 {"sound_clear", 0, 0, 0, f_sound_clear},
768 {"sound_playevent", 1, 2, 0, f_sound_playevent},
769 {"sound_playfile", 1, 2, 0, f_sound_playfile},
770 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200771#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200772 {"soundfold", 1, 1, 0, f_soundfold},
773 {"spellbadword", 0, 1, 0, f_spellbadword},
774 {"spellsuggest", 1, 3, 0, f_spellsuggest},
775 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200776#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200777 {"sqrt", 1, 1, FEARG_1, f_sqrt},
778 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200779#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200780 {"str2list", 1, 2, FEARG_1, f_str2list},
781 {"str2nr", 1, 2, 0, f_str2nr},
782 {"strcharpart", 2, 3, 0, f_strcharpart},
783 {"strchars", 1, 2, 0, f_strchars},
784 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200785#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200786 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200787#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200788 {"strgetchar", 2, 2, 0, f_strgetchar},
789 {"stridx", 2, 3, 0, f_stridx},
790 {"string", 1, 1, FEARG_1, f_string},
791 {"strlen", 1, 1, FEARG_1, f_strlen},
792 {"strpart", 2, 3, 0, f_strpart},
793 {"strridx", 2, 3, 0, f_strridx},
794 {"strtrans", 1, 1, FEARG_1, f_strtrans},
795 {"strwidth", 1, 1, FEARG_1, f_strwidth},
796 {"submatch", 1, 2, 0, f_submatch},
797 {"substitute", 4, 4, FEARG_1, f_substitute},
798 {"swapinfo", 1, 1, 0, f_swapinfo},
799 {"swapname", 1, 1, 0, f_swapname},
800 {"synID", 3, 3, 0, f_synID},
801 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
802 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
803 {"synconcealed", 2, 2, 0, f_synconcealed},
804 {"synstack", 2, 2, 0, f_synstack},
805 {"system", 1, 2, FEARG_1, f_system},
806 {"systemlist", 1, 2, FEARG_1, f_systemlist},
807 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
808 {"tabpagenr", 0, 1, 0, f_tabpagenr},
809 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
810 {"tagfiles", 0, 0, 0, f_tagfiles},
811 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200812#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200813 {"tan", 1, 1, FEARG_1, f_tan},
814 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200815#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200816 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200817#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200818 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
819 {"term_dumpload", 1, 2, 0, f_term_dumpload},
820 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
821 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200822# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200823 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200824# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200825 {"term_getattr", 2, 2, 0, f_term_getattr},
826 {"term_getcursor", 1, 1, 0, f_term_getcursor},
827 {"term_getjob", 1, 1, 0, f_term_getjob},
828 {"term_getline", 2, 2, 0, f_term_getline},
829 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
830 {"term_getsize", 1, 1, 0, f_term_getsize},
831 {"term_getstatus", 1, 1, 0, f_term_getstatus},
832 {"term_gettitle", 1, 1, 0, f_term_gettitle},
833 {"term_gettty", 1, 2, 0, f_term_gettty},
834 {"term_list", 0, 0, 0, f_term_list},
835 {"term_scrape", 2, 2, 0, f_term_scrape},
836 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200837# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200838 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200839# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200840 {"term_setkill", 2, 2, 0, f_term_setkill},
841 {"term_setrestore", 2, 2, 0, f_term_setrestore},
842 {"term_setsize", 3, 3, 0, f_term_setsize},
843 {"term_start", 1, 2, 0, f_term_start},
844 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200845#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200846 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
847 {"test_autochdir", 0, 0, 0, f_test_autochdir},
848 {"test_feedinput", 1, 1, 0, f_test_feedinput},
849 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
850 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
851 {"test_getvalue", 1, 1, 0, f_test_getvalue},
852 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
853 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200854#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200855 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200857 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200858#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200859 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200860#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200861 {"test_null_list", 0, 0, 0, f_test_null_list},
862 {"test_null_partial", 0, 0, 0, f_test_null_partial},
863 {"test_null_string", 0, 0, 0, f_test_null_string},
864 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
865 {"test_override", 2, 2, 0, f_test_override},
866 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200867#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200868 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200869#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200870#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200871 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200872#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200873 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200874#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200875 {"timer_info", 0, 1, 0, f_timer_info},
876 {"timer_pause", 2, 2, 0, f_timer_pause},
877 {"timer_start", 2, 3, 0, f_timer_start},
878 {"timer_stop", 1, 1, 0, f_timer_stop},
879 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200880#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200881 {"tolower", 1, 1, 0, f_tolower},
882 {"toupper", 1, 1, 0, f_toupper},
883 {"tr", 3, 3, 0, f_tr},
884 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200885#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200886 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200887#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200888 {"type", 1, 1, FEARG_1, f_type},
889 {"undofile", 1, 1, 0, f_undofile},
890 {"undotree", 0, 0, 0, f_undotree},
891 {"uniq", 1, 3, FEARG_1, f_uniq},
892 {"values", 1, 1, FEARG_1, f_values},
893 {"virtcol", 1, 1, 0, f_virtcol},
894 {"visualmode", 0, 1, 0, f_visualmode},
895 {"wildmenumode", 0, 0, 0, f_wildmenumode},
896 {"win_execute", 2, 3, 0, f_win_execute},
897 {"win_findbuf", 1, 1, 0, f_win_findbuf},
898 {"win_getid", 0, 2, 0, f_win_getid},
899 {"win_gotoid", 1, 1, 0, f_win_gotoid},
900 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
901 {"win_id2win", 1, 1, 0, f_win_id2win},
902 {"win_screenpos", 1, 1, 0, f_win_screenpos},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200903 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200904 {"wincol", 0, 0, 0, f_wincol},
905 {"winheight", 1, 1, 0, f_winheight},
906 {"winlayout", 0, 1, 0, f_winlayout},
907 {"winline", 0, 0, 0, f_winline},
908 {"winnr", 0, 1, 0, f_winnr},
909 {"winrestcmd", 0, 0, 0, f_winrestcmd},
910 {"winrestview", 1, 1, 0, f_winrestview},
911 {"winsaveview", 0, 0, 0, f_winsaveview},
912 {"winwidth", 1, 1, 0, f_winwidth},
913 {"wordcount", 0, 0, 0, f_wordcount},
914 {"writefile", 2, 3, 0, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200915 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200916};
917
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918/*
919 * Function given to ExpandGeneric() to obtain the list of internal
920 * or user defined function names.
921 */
922 char_u *
923get_function_name(expand_T *xp, int idx)
924{
925 static int intidx = -1;
926 char_u *name;
927
928 if (idx == 0)
929 intidx = -1;
930 if (intidx < 0)
931 {
932 name = get_user_func_name(xp, idx);
933 if (name != NULL)
934 return name;
935 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200936 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200937 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200938 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200939 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200940 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200941 STRCAT(IObuff, ")");
942 return IObuff;
943 }
944
945 return NULL;
946}
947
948/*
949 * Function given to ExpandGeneric() to obtain the list of internal or
950 * user defined variable or function names.
951 */
952 char_u *
953get_expr_name(expand_T *xp, int idx)
954{
955 static int intidx = -1;
956 char_u *name;
957
958 if (idx == 0)
959 intidx = -1;
960 if (intidx < 0)
961 {
962 name = get_function_name(xp, idx);
963 if (name != NULL)
964 return name;
965 }
966 return get_user_var_name(xp, ++intidx);
967}
968
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200969/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200970 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200971 * Return index, or -1 if not found
972 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200973 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200974find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200975{
976 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200977 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200978 int cmp;
979 int x;
980
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200981 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200982
983 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200984 while (first <= last)
985 {
986 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200987 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200988 if (cmp < 0)
989 last = x - 1;
990 else if (cmp > 0)
991 first = x + 1;
992 else
993 return x;
994 }
995 return -1;
996}
997
998 int
Bram Moolenaarac92e252019-08-03 21:58:38 +0200999has_internal_func(char_u *name)
1000{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001001 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001002}
1003
1004 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001005call_internal_func(
1006 char_u *name,
1007 int argcount,
1008 typval_T *argvars,
1009 typval_T *rettv)
1010{
1011 int i;
1012
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001013 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001014 if (i < 0)
1015 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001016 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001017 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001018 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019 return ERROR_TOOMANY;
1020 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001021 global_functions[i].f_func(argvars, rettv);
1022 return ERROR_NONE;
1023}
1024
1025/*
1026 * Invoke a method for base->method().
1027 */
1028 int
1029call_internal_method(
1030 char_u *name,
1031 int argcount,
1032 typval_T *argvars,
1033 typval_T *rettv,
1034 typval_T *basetv)
1035{
1036 int i;
1037 int fi;
1038 typval_T argv[MAX_FUNC_ARGS + 1];
1039
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001040 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001041 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001042 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001043 if (global_functions[fi].f_argtype == 0)
1044 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001045 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001046 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001047 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001048 return ERROR_TOOMANY;
1049
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001050 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001051 {
1052 // base value goes last
1053 for (i = 0; i < argcount; ++i)
1054 argv[i] = argvars[i];
1055 argv[argcount] = *basetv;
1056 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001057 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001058 {
1059 // base value goes second
1060 argv[0] = argvars[0];
1061 argv[1] = *basetv;
1062 for (i = 1; i < argcount; ++i)
1063 argv[i + 1] = argvars[i];
1064 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001065 else if (global_functions[fi].f_argtype == FEARG_3)
1066 {
1067 // base value goes third
1068 argv[0] = argvars[0];
1069 argv[1] = argvars[1];
1070 argv[2] = *basetv;
1071 for (i = 2; i < argcount; ++i)
1072 argv[i + 1] = argvars[i];
1073 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001074 else
1075 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001076 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001077 argv[0] = *basetv;
1078 for (i = 0; i < argcount; ++i)
1079 argv[i + 1] = argvars[i];
1080 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001081 argv[argcount + 1].v_type = VAR_UNKNOWN;
1082
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001083 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001084 return ERROR_NONE;
1085}
1086
1087/*
1088 * Return TRUE for a non-zero Number and a non-empty String.
1089 */
1090 static int
1091non_zero_arg(typval_T *argvars)
1092{
1093 return ((argvars[0].v_type == VAR_NUMBER
1094 && argvars[0].vval.v_number != 0)
1095 || (argvars[0].v_type == VAR_SPECIAL
1096 && argvars[0].vval.v_number == VVAL_TRUE)
1097 || (argvars[0].v_type == VAR_STRING
1098 && argvars[0].vval.v_string != NULL
1099 && *argvars[0].vval.v_string != NUL));
1100}
1101
1102/*
1103 * Get the lnum from the first argument.
1104 * Also accepts ".", "$", etc., but that only works for the current buffer.
1105 * Returns -1 on error.
1106 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001107 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001108tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001109{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001110 linenr_T lnum;
1111
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001112 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001113 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001114 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001115 int fnum;
1116 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1117
1118 if (fp != NULL)
1119 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001120 }
1121 return lnum;
1122}
1123
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001124/*
1125 * Get the lnum from the first argument.
1126 * Also accepts "$", then "buf" is used.
1127 * Returns 0 on error.
1128 */
1129 static linenr_T
1130tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1131{
1132 if (argvars[0].v_type == VAR_STRING
1133 && argvars[0].vval.v_string != NULL
1134 && argvars[0].vval.v_string[0] == '$'
1135 && buf != NULL)
1136 return buf->b_ml.ml_line_count;
1137 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1138}
1139
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001140#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001141/*
1142 * Get the float value of "argvars[0]" into "f".
1143 * Returns FAIL when the argument is not a Number or Float.
1144 */
1145 static int
1146get_float_arg(typval_T *argvars, float_T *f)
1147{
1148 if (argvars[0].v_type == VAR_FLOAT)
1149 {
1150 *f = argvars[0].vval.v_float;
1151 return OK;
1152 }
1153 if (argvars[0].v_type == VAR_NUMBER)
1154 {
1155 *f = (float_T)argvars[0].vval.v_number;
1156 return OK;
1157 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001158 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001159 return FAIL;
1160}
1161
1162/*
1163 * "abs(expr)" function
1164 */
1165 static void
1166f_abs(typval_T *argvars, typval_T *rettv)
1167{
1168 if (argvars[0].v_type == VAR_FLOAT)
1169 {
1170 rettv->v_type = VAR_FLOAT;
1171 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1172 }
1173 else
1174 {
1175 varnumber_T n;
1176 int error = FALSE;
1177
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001178 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001179 if (error)
1180 rettv->vval.v_number = -1;
1181 else if (n > 0)
1182 rettv->vval.v_number = n;
1183 else
1184 rettv->vval.v_number = -n;
1185 }
1186}
1187
1188/*
1189 * "acos()" function
1190 */
1191 static void
1192f_acos(typval_T *argvars, typval_T *rettv)
1193{
1194 float_T f = 0.0;
1195
1196 rettv->v_type = VAR_FLOAT;
1197 if (get_float_arg(argvars, &f) == OK)
1198 rettv->vval.v_float = acos(f);
1199 else
1200 rettv->vval.v_float = 0.0;
1201}
1202#endif
1203
1204/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001205 * "and(expr, expr)" function
1206 */
1207 static void
1208f_and(typval_T *argvars, typval_T *rettv)
1209{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001210 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1211 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001212}
1213
1214/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001215 * If there is a window for "curbuf", make it the current window.
1216 */
1217 static void
1218find_win_for_curbuf(void)
1219{
1220 wininfo_T *wip;
1221
1222 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1223 {
1224 if (wip->wi_win != NULL)
1225 {
1226 curwin = wip->wi_win;
1227 break;
1228 }
1229 }
1230}
1231
1232/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001233 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001234 */
1235 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001236set_buffer_lines(
1237 buf_T *buf,
1238 linenr_T lnum_arg,
1239 int append,
1240 typval_T *lines,
1241 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001242{
Bram Moolenaarca851592018-06-06 21:04:07 +02001243 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1244 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001245 list_T *l = NULL;
1246 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001247 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001248 linenr_T append_lnum;
1249 buf_T *curbuf_save = NULL;
1250 win_T *curwin_save = NULL;
1251 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001252
Bram Moolenaarca851592018-06-06 21:04:07 +02001253 /* When using the current buffer ml_mfp will be set if needed. Useful when
1254 * setline() is used on startup. For other buffers the buffer must be
1255 * loaded. */
1256 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001257 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001258 rettv->vval.v_number = 1; /* FAIL */
1259 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001260 }
1261
Bram Moolenaarca851592018-06-06 21:04:07 +02001262 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001263 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001264 curbuf_save = curbuf;
1265 curwin_save = curwin;
1266 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001267 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001268 }
1269
1270 if (append)
1271 // appendbufline() uses the line number below which we insert
1272 append_lnum = lnum - 1;
1273 else
1274 // setbufline() uses the line number above which we insert, we only
1275 // append if it's below the last line
1276 append_lnum = curbuf->b_ml.ml_line_count;
1277
1278 if (lines->v_type == VAR_LIST)
1279 {
1280 l = lines->vval.v_list;
1281 li = l->lv_first;
1282 }
1283 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001284 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001285
1286 /* default result is zero == OK */
1287 for (;;)
1288 {
1289 if (l != NULL)
1290 {
1291 /* list argument, get next string */
1292 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001294 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 li = li->li_next;
1296 }
1297
Bram Moolenaarca851592018-06-06 21:04:07 +02001298 rettv->vval.v_number = 1; /* FAIL */
1299 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1300 break;
1301
1302 /* When coming here from Insert mode, sync undo, so that this can be
1303 * undone separately from what was previously inserted. */
1304 if (u_sync_once == 2)
1305 {
1306 u_sync_once = 1; /* notify that u_sync() was called */
1307 u_sync(TRUE);
1308 }
1309
1310 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1311 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001312 // Existing line, replace it.
1313 // Removes any existing text properties.
1314 if (u_savesub(lnum) == OK && ml_replace_len(
1315 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001316 {
1317 changed_bytes(lnum, 0);
1318 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1319 check_cursor_col();
1320 rettv->vval.v_number = 0; /* OK */
1321 }
1322 }
1323 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1324 {
1325 /* append the line */
1326 ++added;
1327 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1328 rettv->vval.v_number = 0; /* OK */
1329 }
1330
1331 if (l == NULL) /* only one string argument */
1332 break;
1333 ++lnum;
1334 }
1335
1336 if (added > 0)
1337 {
1338 win_T *wp;
1339 tabpage_T *tp;
1340
1341 appended_lines_mark(append_lnum, added);
Bram Moolenaard2007022019-08-27 21:56:06 +02001342
1343 // Only adjust the cursor for buffers other than the current, unless it
1344 // is the current window. For curbuf and other windows it has been
1345 // done in mark_adjust_internal().
Bram Moolenaarca851592018-06-06 21:04:07 +02001346 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaard2007022019-08-27 21:56:06 +02001347 if (wp->w_buffer == buf
1348 && (wp->w_buffer != curbuf || wp == curwin)
1349 && wp->w_cursor.lnum > append_lnum)
Bram Moolenaarca851592018-06-06 21:04:07 +02001350 wp->w_cursor.lnum += added;
1351 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001352 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001354
1355 if (!is_curbuf)
1356 {
1357 curbuf = curbuf_save;
1358 curwin = curwin_save;
1359 }
1360}
1361
1362/*
1363 * "append(lnum, string/list)" function
1364 */
1365 static void
1366f_append(typval_T *argvars, typval_T *rettv)
1367{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001368 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001369
1370 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1371}
1372
1373/*
1374 * "appendbufline(buf, lnum, string/list)" function
1375 */
1376 static void
1377f_appendbufline(typval_T *argvars, typval_T *rettv)
1378{
1379 linenr_T lnum;
1380 buf_T *buf;
1381
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001382 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001383 if (buf == NULL)
1384 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001385 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001386 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001387 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001388 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1389 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001390}
1391
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001392#ifdef FEAT_FLOAT
1393/*
1394 * "asin()" function
1395 */
1396 static void
1397f_asin(typval_T *argvars, typval_T *rettv)
1398{
1399 float_T f = 0.0;
1400
1401 rettv->v_type = VAR_FLOAT;
1402 if (get_float_arg(argvars, &f) == OK)
1403 rettv->vval.v_float = asin(f);
1404 else
1405 rettv->vval.v_float = 0.0;
1406}
1407
1408/*
1409 * "atan()" function
1410 */
1411 static void
1412f_atan(typval_T *argvars, typval_T *rettv)
1413{
1414 float_T f = 0.0;
1415
1416 rettv->v_type = VAR_FLOAT;
1417 if (get_float_arg(argvars, &f) == OK)
1418 rettv->vval.v_float = atan(f);
1419 else
1420 rettv->vval.v_float = 0.0;
1421}
1422
1423/*
1424 * "atan2()" function
1425 */
1426 static void
1427f_atan2(typval_T *argvars, typval_T *rettv)
1428{
1429 float_T fx = 0.0, fy = 0.0;
1430
1431 rettv->v_type = VAR_FLOAT;
1432 if (get_float_arg(argvars, &fx) == OK
1433 && get_float_arg(&argvars[1], &fy) == OK)
1434 rettv->vval.v_float = atan2(fx, fy);
1435 else
1436 rettv->vval.v_float = 0.0;
1437}
1438#endif
1439
1440/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001441 * "balloon_show()" function
1442 */
1443#ifdef FEAT_BEVAL
1444 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001445f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1446{
1447 rettv->v_type = VAR_STRING;
1448 if (balloonEval != NULL)
1449 {
1450 if (balloonEval->msg == NULL)
1451 rettv->vval.v_string = NULL;
1452 else
1453 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1454 }
1455}
1456
1457 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001458f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1459{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001460 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001461 {
1462 if (argvars[0].v_type == VAR_LIST
1463# ifdef FEAT_GUI
1464 && !gui.in_use
1465# endif
1466 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001467 {
1468 list_T *l = argvars[0].vval.v_list;
1469
1470 // empty list removes the balloon
1471 post_balloon(balloonEval, NULL,
1472 l == NULL || l->lv_len == 0 ? NULL : l);
1473 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001474 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001475 {
1476 char_u *mesg = tv_get_string_chk(&argvars[0]);
1477
1478 if (mesg != NULL)
1479 // empty string removes the balloon
1480 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1481 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001482 }
1483}
1484
Bram Moolenaar669a8282017-11-19 20:13:05 +01001485# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001486 static void
1487f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1488{
1489 if (rettv_list_alloc(rettv) == OK)
1490 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001491 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001492
1493 if (msg != NULL)
1494 {
1495 pumitem_T *array;
1496 int size = split_message(msg, &array);
1497 int i;
1498
1499 /* Skip the first and last item, they are always empty. */
1500 for (i = 1; i < size - 1; ++i)
1501 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001502 while (size > 0)
1503 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001504 vim_free(array);
1505 }
1506 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001507}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001508# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001509#endif
1510
1511/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001512 * Find a buffer by number or exact name.
1513 */
1514 static buf_T *
1515find_buffer(typval_T *avar)
1516{
1517 buf_T *buf = NULL;
1518
1519 if (avar->v_type == VAR_NUMBER)
1520 buf = buflist_findnr((int)avar->vval.v_number);
1521 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1522 {
1523 buf = buflist_findname_exp(avar->vval.v_string);
1524 if (buf == NULL)
1525 {
1526 /* No full path name match, try a match with a URL or a "nofile"
1527 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001528 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001529 if (buf->b_fname != NULL
1530 && (path_with_url(buf->b_fname)
1531#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001532 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001533#endif
1534 )
1535 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1536 break;
1537 }
1538 }
1539 return buf;
1540}
1541
1542/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001543 * "bufadd(expr)" function
1544 */
1545 static void
1546f_bufadd(typval_T *argvars, typval_T *rettv)
1547{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001548 char_u *name = tv_get_string(&argvars[0]);
1549
1550 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001551}
1552
1553/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001554 * "bufexists(expr)" function
1555 */
1556 static void
1557f_bufexists(typval_T *argvars, typval_T *rettv)
1558{
1559 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1560}
1561
1562/*
1563 * "buflisted(expr)" function
1564 */
1565 static void
1566f_buflisted(typval_T *argvars, typval_T *rettv)
1567{
1568 buf_T *buf;
1569
1570 buf = find_buffer(&argvars[0]);
1571 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1572}
1573
1574/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001575 * "bufload(expr)" function
1576 */
1577 static void
1578f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1579{
1580 buf_T *buf = get_buf_arg(&argvars[0]);
1581
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001582 if (buf != NULL)
1583 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001584}
1585
1586/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001587 * "bufloaded(expr)" function
1588 */
1589 static void
1590f_bufloaded(typval_T *argvars, typval_T *rettv)
1591{
1592 buf_T *buf;
1593
1594 buf = find_buffer(&argvars[0]);
1595 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1596}
1597
1598 buf_T *
1599buflist_find_by_name(char_u *name, int curtab_only)
1600{
1601 int save_magic;
1602 char_u *save_cpo;
1603 buf_T *buf;
1604
1605 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1606 save_magic = p_magic;
1607 p_magic = TRUE;
1608 save_cpo = p_cpo;
1609 p_cpo = (char_u *)"";
1610
1611 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1612 TRUE, FALSE, curtab_only));
1613
1614 p_magic = save_magic;
1615 p_cpo = save_cpo;
1616 return buf;
1617}
1618
1619/*
1620 * Get buffer by number or pattern.
1621 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001622 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001623tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624{
1625 char_u *name = tv->vval.v_string;
1626 buf_T *buf;
1627
1628 if (tv->v_type == VAR_NUMBER)
1629 return buflist_findnr((int)tv->vval.v_number);
1630 if (tv->v_type != VAR_STRING)
1631 return NULL;
1632 if (name == NULL || *name == NUL)
1633 return curbuf;
1634 if (name[0] == '$' && name[1] == NUL)
1635 return lastbuf;
1636
1637 buf = buflist_find_by_name(name, curtab_only);
1638
1639 /* If not found, try expanding the name, like done for bufexists(). */
1640 if (buf == NULL)
1641 buf = find_buffer(tv);
1642
1643 return buf;
1644}
1645
1646/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001647 * Get the buffer from "arg" and give an error and return NULL if it is not
1648 * valid.
1649 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001650 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001651get_buf_arg(typval_T *arg)
1652{
1653 buf_T *buf;
1654
1655 ++emsg_off;
1656 buf = tv_get_buf(arg, FALSE);
1657 --emsg_off;
1658 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001659 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001660 return buf;
1661}
1662
1663/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001664 * "bufname(expr)" function
1665 */
1666 static void
1667f_bufname(typval_T *argvars, typval_T *rettv)
1668{
1669 buf_T *buf;
1670
Bram Moolenaara8eee212019-08-24 22:14:58 +02001671 if (argvars[0].v_type == VAR_UNKNOWN)
1672 buf = curbuf;
1673 else
1674 {
1675 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1676 ++emsg_off;
1677 buf = tv_get_buf(&argvars[0], FALSE);
1678 --emsg_off;
1679 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001680 rettv->v_type = VAR_STRING;
1681 if (buf != NULL && buf->b_fname != NULL)
1682 rettv->vval.v_string = vim_strsave(buf->b_fname);
1683 else
1684 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685}
1686
1687/*
1688 * "bufnr(expr)" function
1689 */
1690 static void
1691f_bufnr(typval_T *argvars, typval_T *rettv)
1692{
1693 buf_T *buf;
1694 int error = FALSE;
1695 char_u *name;
1696
Bram Moolenaara8eee212019-08-24 22:14:58 +02001697 if (argvars[0].v_type == VAR_UNKNOWN)
1698 buf = curbuf;
1699 else
1700 {
1701 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1702 ++emsg_off;
1703 buf = tv_get_buf(&argvars[0], FALSE);
1704 --emsg_off;
1705 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001706
Bram Moolenaara8eee212019-08-24 22:14:58 +02001707 // If the buffer isn't found and the second argument is not zero create a
1708 // new buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001709 if (buf == NULL
1710 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001711 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001712 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001713 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 && !error)
1715 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1716
1717 if (buf != NULL)
1718 rettv->vval.v_number = buf->b_fnum;
1719 else
1720 rettv->vval.v_number = -1;
1721}
1722
1723 static void
1724buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1725{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001726 win_T *wp;
1727 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728 buf_T *buf;
1729
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001730 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001731 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001732 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001733 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001734 {
1735 ++winnr;
1736 if (wp->w_buffer == buf)
1737 break;
1738 }
1739 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001740 --emsg_off;
1741}
1742
1743/*
1744 * "bufwinid(nr)" function
1745 */
1746 static void
1747f_bufwinid(typval_T *argvars, typval_T *rettv)
1748{
1749 buf_win_common(argvars, rettv, FALSE);
1750}
1751
1752/*
1753 * "bufwinnr(nr)" function
1754 */
1755 static void
1756f_bufwinnr(typval_T *argvars, typval_T *rettv)
1757{
1758 buf_win_common(argvars, rettv, TRUE);
1759}
1760
1761/*
1762 * "byte2line(byte)" function
1763 */
1764 static void
1765f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1766{
1767#ifndef FEAT_BYTEOFF
1768 rettv->vval.v_number = -1;
1769#else
1770 long boff = 0;
1771
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001772 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001773 if (boff < 0)
1774 rettv->vval.v_number = -1;
1775 else
1776 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1777 (linenr_T)0, &boff);
1778#endif
1779}
1780
1781 static void
1782byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1783{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001784 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001785 char_u *str;
1786 varnumber_T idx;
1787
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001788 str = tv_get_string_chk(&argvars[0]);
1789 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001790 rettv->vval.v_number = -1;
1791 if (str == NULL || idx < 0)
1792 return;
1793
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001794 t = str;
1795 for ( ; idx > 0; idx--)
1796 {
1797 if (*t == NUL) /* EOL reached */
1798 return;
1799 if (enc_utf8 && comp)
1800 t += utf_ptr2len(t);
1801 else
1802 t += (*mb_ptr2len)(t);
1803 }
1804 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001805}
1806
1807/*
1808 * "byteidx()" function
1809 */
1810 static void
1811f_byteidx(typval_T *argvars, typval_T *rettv)
1812{
1813 byteidx(argvars, rettv, FALSE);
1814}
1815
1816/*
1817 * "byteidxcomp()" function
1818 */
1819 static void
1820f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1821{
1822 byteidx(argvars, rettv, TRUE);
1823}
1824
1825/*
1826 * "call(func, arglist [, dict])" function
1827 */
1828 static void
1829f_call(typval_T *argvars, typval_T *rettv)
1830{
1831 char_u *func;
1832 partial_T *partial = NULL;
1833 dict_T *selfdict = NULL;
1834
1835 if (argvars[1].v_type != VAR_LIST)
1836 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001837 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001838 return;
1839 }
1840 if (argvars[1].vval.v_list == NULL)
1841 return;
1842
1843 if (argvars[0].v_type == VAR_FUNC)
1844 func = argvars[0].vval.v_string;
1845 else if (argvars[0].v_type == VAR_PARTIAL)
1846 {
1847 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001848 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001849 }
1850 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001851 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001852 if (*func == NUL)
1853 return; /* type error or empty name */
1854
1855 if (argvars[2].v_type != VAR_UNKNOWN)
1856 {
1857 if (argvars[2].v_type != VAR_DICT)
1858 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001859 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001860 return;
1861 }
1862 selfdict = argvars[2].vval.v_dict;
1863 }
1864
1865 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1866}
1867
1868#ifdef FEAT_FLOAT
1869/*
1870 * "ceil({float})" function
1871 */
1872 static void
1873f_ceil(typval_T *argvars, typval_T *rettv)
1874{
1875 float_T f = 0.0;
1876
1877 rettv->v_type = VAR_FLOAT;
1878 if (get_float_arg(argvars, &f) == OK)
1879 rettv->vval.v_float = ceil(f);
1880 else
1881 rettv->vval.v_float = 0.0;
1882}
1883#endif
1884
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001885/*
1886 * "changenr()" function
1887 */
1888 static void
1889f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1890{
1891 rettv->vval.v_number = curbuf->b_u_seq_cur;
1892}
1893
1894/*
1895 * "char2nr(string)" function
1896 */
1897 static void
1898f_char2nr(typval_T *argvars, typval_T *rettv)
1899{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001900 if (has_mbyte)
1901 {
1902 int utf8 = 0;
1903
1904 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001905 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001906
1907 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001908 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001909 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001910 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001911 }
1912 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001913 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001914}
1915
1916/*
1917 * "cindent(lnum)" function
1918 */
1919 static void
1920f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1921{
1922#ifdef FEAT_CINDENT
1923 pos_T pos;
1924 linenr_T lnum;
1925
1926 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001927 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1929 {
1930 curwin->w_cursor.lnum = lnum;
1931 rettv->vval.v_number = get_c_indent();
1932 curwin->w_cursor = pos;
1933 }
1934 else
1935#endif
1936 rettv->vval.v_number = -1;
1937}
1938
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001939 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001940get_optional_window(typval_T *argvars, int idx)
1941{
1942 win_T *win = curwin;
1943
1944 if (argvars[idx].v_type != VAR_UNKNOWN)
1945 {
1946 win = find_win_by_nr_or_id(&argvars[idx]);
1947 if (win == NULL)
1948 {
1949 emsg(_(e_invalwindow));
1950 return NULL;
1951 }
1952 }
1953 return win;
1954}
1955
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001956/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001957 * "col(string)" function
1958 */
1959 static void
1960f_col(typval_T *argvars, typval_T *rettv)
1961{
1962 colnr_T col = 0;
1963 pos_T *fp;
1964 int fnum = curbuf->b_fnum;
1965
1966 fp = var2fpos(&argvars[0], FALSE, &fnum);
1967 if (fp != NULL && fnum == curbuf->b_fnum)
1968 {
1969 if (fp->col == MAXCOL)
1970 {
1971 /* '> can be MAXCOL, get the length of the line then */
1972 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1973 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1974 else
1975 col = MAXCOL;
1976 }
1977 else
1978 {
1979 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980 /* col(".") when the cursor is on the NUL at the end of the line
1981 * because of "coladd" can be seen as an extra column. */
1982 if (virtual_active() && fp == &curwin->w_cursor)
1983 {
1984 char_u *p = ml_get_cursor();
1985
1986 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1987 curwin->w_virtcol - curwin->w_cursor.coladd))
1988 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001989 int l;
1990
1991 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1992 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001993 }
1994 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 }
1996 }
1997 rettv->vval.v_number = col;
1998}
1999
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002000/*
2001 * "confirm(message, buttons[, default [, type]])" function
2002 */
2003 static void
2004f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2005{
2006#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2007 char_u *message;
2008 char_u *buttons = NULL;
2009 char_u buf[NUMBUFLEN];
2010 char_u buf2[NUMBUFLEN];
2011 int def = 1;
2012 int type = VIM_GENERIC;
2013 char_u *typestr;
2014 int error = FALSE;
2015
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002016 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002017 if (message == NULL)
2018 error = TRUE;
2019 if (argvars[1].v_type != VAR_UNKNOWN)
2020 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002021 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002022 if (buttons == NULL)
2023 error = TRUE;
2024 if (argvars[2].v_type != VAR_UNKNOWN)
2025 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002026 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002027 if (argvars[3].v_type != VAR_UNKNOWN)
2028 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002029 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002030 if (typestr == NULL)
2031 error = TRUE;
2032 else
2033 {
2034 switch (TOUPPER_ASC(*typestr))
2035 {
2036 case 'E': type = VIM_ERROR; break;
2037 case 'Q': type = VIM_QUESTION; break;
2038 case 'I': type = VIM_INFO; break;
2039 case 'W': type = VIM_WARNING; break;
2040 case 'G': type = VIM_GENERIC; break;
2041 }
2042 }
2043 }
2044 }
2045 }
2046
2047 if (buttons == NULL || *buttons == NUL)
2048 buttons = (char_u *)_("&Ok");
2049
2050 if (!error)
2051 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2052 def, NULL, FALSE);
2053#endif
2054}
2055
2056/*
2057 * "copy()" function
2058 */
2059 static void
2060f_copy(typval_T *argvars, typval_T *rettv)
2061{
2062 item_copy(&argvars[0], rettv, FALSE, 0);
2063}
2064
2065#ifdef FEAT_FLOAT
2066/*
2067 * "cos()" function
2068 */
2069 static void
2070f_cos(typval_T *argvars, typval_T *rettv)
2071{
2072 float_T f = 0.0;
2073
2074 rettv->v_type = VAR_FLOAT;
2075 if (get_float_arg(argvars, &f) == OK)
2076 rettv->vval.v_float = cos(f);
2077 else
2078 rettv->vval.v_float = 0.0;
2079}
2080
2081/*
2082 * "cosh()" function
2083 */
2084 static void
2085f_cosh(typval_T *argvars, typval_T *rettv)
2086{
2087 float_T f = 0.0;
2088
2089 rettv->v_type = VAR_FLOAT;
2090 if (get_float_arg(argvars, &f) == OK)
2091 rettv->vval.v_float = cosh(f);
2092 else
2093 rettv->vval.v_float = 0.0;
2094}
2095#endif
2096
2097/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2099 *
2100 * Checks the existence of a cscope connection.
2101 */
2102 static void
2103f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2104{
2105#ifdef FEAT_CSCOPE
2106 int num = 0;
2107 char_u *dbpath = NULL;
2108 char_u *prepend = NULL;
2109 char_u buf[NUMBUFLEN];
2110
2111 if (argvars[0].v_type != VAR_UNKNOWN
2112 && argvars[1].v_type != VAR_UNKNOWN)
2113 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002114 num = (int)tv_get_number(&argvars[0]);
2115 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002116 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002117 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002118 }
2119
2120 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2121#endif
2122}
2123
2124/*
2125 * "cursor(lnum, col)" function, or
2126 * "cursor(list)"
2127 *
2128 * Moves the cursor to the specified line and column.
2129 * Returns 0 when the position could be set, -1 otherwise.
2130 */
2131 static void
2132f_cursor(typval_T *argvars, typval_T *rettv)
2133{
2134 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002135 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002136 int set_curswant = TRUE;
2137
2138 rettv->vval.v_number = -1;
2139 if (argvars[1].v_type == VAR_UNKNOWN)
2140 {
2141 pos_T pos;
2142 colnr_T curswant = -1;
2143
2144 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2145 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002146 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147 return;
2148 }
2149 line = pos.lnum;
2150 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002151 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002152 if (curswant >= 0)
2153 {
2154 curwin->w_curswant = curswant - 1;
2155 set_curswant = FALSE;
2156 }
2157 }
2158 else
2159 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002160 line = tv_get_lnum(argvars);
2161 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002162 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002163 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002165 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002166 return; /* type error; errmsg already given */
2167 if (line > 0)
2168 curwin->w_cursor.lnum = line;
2169 if (col > 0)
2170 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002171 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172
2173 /* Make sure the cursor is in a valid position. */
2174 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002175 /* Correct cursor for multi-byte character. */
2176 if (has_mbyte)
2177 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002178
2179 curwin->w_set_curswant = set_curswant;
2180 rettv->vval.v_number = 0;
2181}
2182
Bram Moolenaar4f974752019-02-17 17:44:42 +01002183#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002184/*
2185 * "debugbreak()" function
2186 */
2187 static void
2188f_debugbreak(typval_T *argvars, typval_T *rettv)
2189{
2190 int pid;
2191
2192 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002193 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002194 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002195 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002196 else
2197 {
2198 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2199
2200 if (hProcess != NULL)
2201 {
2202 DebugBreakProcess(hProcess);
2203 CloseHandle(hProcess);
2204 rettv->vval.v_number = OK;
2205 }
2206 }
2207}
2208#endif
2209
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002210/*
2211 * "deepcopy()" function
2212 */
2213 static void
2214f_deepcopy(typval_T *argvars, typval_T *rettv)
2215{
2216 int noref = 0;
2217 int copyID;
2218
2219 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002220 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002221 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002222 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002223 else
2224 {
2225 copyID = get_copyID();
2226 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2227 }
2228}
2229
2230/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002231 * "deletebufline()" function
2232 */
2233 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002234f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002235{
2236 buf_T *buf;
2237 linenr_T first, last;
2238 linenr_T lnum;
2239 long count;
2240 int is_curbuf;
2241 buf_T *curbuf_save = NULL;
2242 win_T *curwin_save = NULL;
2243 tabpage_T *tp;
2244 win_T *wp;
2245
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002246 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002247 if (buf == NULL)
2248 {
2249 rettv->vval.v_number = 1; /* FAIL */
2250 return;
2251 }
2252 is_curbuf = buf == curbuf;
2253
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002254 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002255 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002256 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002257 else
2258 last = first;
2259
2260 if (buf->b_ml.ml_mfp == NULL || first < 1
2261 || first > buf->b_ml.ml_line_count || last < first)
2262 {
2263 rettv->vval.v_number = 1; /* FAIL */
2264 return;
2265 }
2266
2267 if (!is_curbuf)
2268 {
2269 curbuf_save = curbuf;
2270 curwin_save = curwin;
2271 curbuf = buf;
2272 find_win_for_curbuf();
2273 }
2274 if (last > curbuf->b_ml.ml_line_count)
2275 last = curbuf->b_ml.ml_line_count;
2276 count = last - first + 1;
2277
2278 // When coming here from Insert mode, sync undo, so that this can be
2279 // undone separately from what was previously inserted.
2280 if (u_sync_once == 2)
2281 {
2282 u_sync_once = 1; // notify that u_sync() was called
2283 u_sync(TRUE);
2284 }
2285
2286 if (u_save(first - 1, last + 1) == FAIL)
2287 {
2288 rettv->vval.v_number = 1; /* FAIL */
2289 return;
2290 }
2291
2292 for (lnum = first; lnum <= last; ++lnum)
2293 ml_delete(first, TRUE);
2294
2295 FOR_ALL_TAB_WINDOWS(tp, wp)
2296 if (wp->w_buffer == buf)
2297 {
2298 if (wp->w_cursor.lnum > last)
2299 wp->w_cursor.lnum -= count;
2300 else if (wp->w_cursor.lnum> first)
2301 wp->w_cursor.lnum = first;
2302 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2303 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2304 }
2305 check_cursor_col();
2306 deleted_lines_mark(first, count);
2307
2308 if (!is_curbuf)
2309 {
2310 curbuf = curbuf_save;
2311 curwin = curwin_save;
2312 }
2313}
2314
2315/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002316 * "did_filetype()" function
2317 */
2318 static void
2319f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2320{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002321 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002322}
2323
2324/*
2325 * "diff_filler()" function
2326 */
2327 static void
2328f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2329{
2330#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002331 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002332#endif
2333}
2334
2335/*
2336 * "diff_hlID()" function
2337 */
2338 static void
2339f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2340{
2341#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002342 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002343 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002344 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 static int fnum = 0;
2346 static int change_start = 0;
2347 static int change_end = 0;
2348 static hlf_T hlID = (hlf_T)0;
2349 int filler_lines;
2350 int col;
2351
2352 if (lnum < 0) /* ignore type error in {lnum} arg */
2353 lnum = 0;
2354 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002355 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002356 || fnum != curbuf->b_fnum)
2357 {
2358 /* New line, buffer, change: need to get the values. */
2359 filler_lines = diff_check(curwin, lnum);
2360 if (filler_lines < 0)
2361 {
2362 if (filler_lines == -1)
2363 {
2364 change_start = MAXCOL;
2365 change_end = -1;
2366 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2367 hlID = HLF_ADD; /* added line */
2368 else
2369 hlID = HLF_CHD; /* changed line */
2370 }
2371 else
2372 hlID = HLF_ADD; /* added line */
2373 }
2374 else
2375 hlID = (hlf_T)0;
2376 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002377 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002378 fnum = curbuf->b_fnum;
2379 }
2380
2381 if (hlID == HLF_CHD || hlID == HLF_TXD)
2382 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002383 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002384 if (col >= change_start && col <= change_end)
2385 hlID = HLF_TXD; /* changed text */
2386 else
2387 hlID = HLF_CHD; /* changed line */
2388 }
2389 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2390#endif
2391}
2392
2393/*
2394 * "empty({expr})" function
2395 */
2396 static void
2397f_empty(typval_T *argvars, typval_T *rettv)
2398{
2399 int n = FALSE;
2400
2401 switch (argvars[0].v_type)
2402 {
2403 case VAR_STRING:
2404 case VAR_FUNC:
2405 n = argvars[0].vval.v_string == NULL
2406 || *argvars[0].vval.v_string == NUL;
2407 break;
2408 case VAR_PARTIAL:
2409 n = FALSE;
2410 break;
2411 case VAR_NUMBER:
2412 n = argvars[0].vval.v_number == 0;
2413 break;
2414 case VAR_FLOAT:
2415#ifdef FEAT_FLOAT
2416 n = argvars[0].vval.v_float == 0.0;
2417 break;
2418#endif
2419 case VAR_LIST:
2420 n = argvars[0].vval.v_list == NULL
2421 || argvars[0].vval.v_list->lv_first == NULL;
2422 break;
2423 case VAR_DICT:
2424 n = argvars[0].vval.v_dict == NULL
2425 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2426 break;
2427 case VAR_SPECIAL:
2428 n = argvars[0].vval.v_number != VVAL_TRUE;
2429 break;
2430
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002431 case VAR_BLOB:
2432 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002433 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2434 break;
2435
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002436 case VAR_JOB:
2437#ifdef FEAT_JOB_CHANNEL
2438 n = argvars[0].vval.v_job == NULL
2439 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2440 break;
2441#endif
2442 case VAR_CHANNEL:
2443#ifdef FEAT_JOB_CHANNEL
2444 n = argvars[0].vval.v_channel == NULL
2445 || !channel_is_open(argvars[0].vval.v_channel);
2446 break;
2447#endif
2448 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002449 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 n = TRUE;
2451 break;
2452 }
2453
2454 rettv->vval.v_number = n;
2455}
2456
2457/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002458 * "environ()" function
2459 */
2460 static void
2461f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2462{
2463#if !defined(AMIGA)
2464 int i = 0;
2465 char_u *entry, *value;
2466# ifdef MSWIN
2467 extern wchar_t **_wenviron;
2468# else
2469 extern char **environ;
2470# endif
2471
2472 if (rettv_dict_alloc(rettv) != OK)
2473 return;
2474
2475# ifdef MSWIN
2476 if (*_wenviron == NULL)
2477 return;
2478# else
2479 if (*environ == NULL)
2480 return;
2481# endif
2482
2483 for (i = 0; ; ++i)
2484 {
2485# ifdef MSWIN
2486 short_u *p;
2487
2488 if ((p = (short_u *)_wenviron[i]) == NULL)
2489 return;
2490 entry = utf16_to_enc(p, NULL);
2491# else
2492 if ((entry = (char_u *)environ[i]) == NULL)
2493 return;
2494 entry = vim_strsave(entry);
2495# endif
2496 if (entry == NULL) // out of memory
2497 return;
2498 if ((value = vim_strchr(entry, '=')) == NULL)
2499 {
2500 vim_free(entry);
2501 continue;
2502 }
2503 *value++ = NUL;
2504 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2505 vim_free(entry);
2506 }
2507#endif
2508}
2509
2510/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002511 * "escape({string}, {chars})" function
2512 */
2513 static void
2514f_escape(typval_T *argvars, typval_T *rettv)
2515{
2516 char_u buf[NUMBUFLEN];
2517
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002518 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2519 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002520 rettv->v_type = VAR_STRING;
2521}
2522
2523/*
2524 * "eval()" function
2525 */
2526 static void
2527f_eval(typval_T *argvars, typval_T *rettv)
2528{
2529 char_u *s, *p;
2530
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002531 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002532 if (s != NULL)
2533 s = skipwhite(s);
2534
2535 p = s;
2536 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2537 {
2538 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002539 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002540 need_clr_eos = FALSE;
2541 rettv->v_type = VAR_NUMBER;
2542 rettv->vval.v_number = 0;
2543 }
2544 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002545 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002546}
2547
2548/*
2549 * "eventhandler()" function
2550 */
2551 static void
2552f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2553{
2554 rettv->vval.v_number = vgetc_busy;
2555}
2556
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002557static garray_T redir_execute_ga;
2558
2559/*
2560 * Append "value[value_len]" to the execute() output.
2561 */
2562 void
2563execute_redir_str(char_u *value, int value_len)
2564{
2565 int len;
2566
2567 if (value_len == -1)
2568 len = (int)STRLEN(value); /* Append the entire string */
2569 else
2570 len = value_len; /* Append only "value_len" characters */
2571 if (ga_grow(&redir_execute_ga, len) == OK)
2572 {
2573 mch_memmove((char *)redir_execute_ga.ga_data
2574 + redir_execute_ga.ga_len, value, len);
2575 redir_execute_ga.ga_len += len;
2576 }
2577}
2578
2579/*
2580 * Get next line from a list.
2581 * Called by do_cmdline() to get the next line.
2582 * Returns allocated string, or NULL for end of function.
2583 */
2584
2585 static char_u *
2586get_list_line(
2587 int c UNUSED,
2588 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002589 int indent UNUSED,
2590 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002591{
2592 listitem_T **p = (listitem_T **)cookie;
2593 listitem_T *item = *p;
2594 char_u buf[NUMBUFLEN];
2595 char_u *s;
2596
2597 if (item == NULL)
2598 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002599 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002600 *p = item->li_next;
2601 return s == NULL ? NULL : vim_strsave(s);
2602}
2603
2604/*
2605 * "execute()" function
2606 */
2607 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002608execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002609{
2610 char_u *cmd = NULL;
2611 list_T *list = NULL;
2612 int save_msg_silent = msg_silent;
2613 int save_emsg_silent = emsg_silent;
2614 int save_emsg_noredir = emsg_noredir;
2615 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002616 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002617 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002618 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002619 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002620
2621 rettv->vval.v_string = NULL;
2622 rettv->v_type = VAR_STRING;
2623
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002624 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002625 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002626 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627 if (list == NULL || list->lv_first == NULL)
2628 /* empty list, no commands, empty output */
2629 return;
2630 ++list->lv_refcount;
2631 }
2632 else
2633 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002634 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002635 if (cmd == NULL)
2636 return;
2637 }
2638
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002639 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002640 {
2641 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002642 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002643
2644 if (s == NULL)
2645 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002646 if (*s == NUL)
2647 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002648 if (STRNCMP(s, "silent", 6) == 0)
2649 ++msg_silent;
2650 if (STRCMP(s, "silent!") == 0)
2651 {
2652 emsg_silent = TRUE;
2653 emsg_noredir = TRUE;
2654 }
2655 }
2656 else
2657 ++msg_silent;
2658
2659 if (redir_execute)
2660 save_ga = redir_execute_ga;
2661 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2662 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002663 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002664 if (!echo_output)
2665 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002666
2667 if (cmd != NULL)
2668 do_cmdline_cmd(cmd);
2669 else
2670 {
2671 listitem_T *item = list->lv_first;
2672
2673 do_cmdline(NULL, get_list_line, (void *)&item,
2674 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2675 --list->lv_refcount;
2676 }
2677
Bram Moolenaard297f352017-01-29 20:31:21 +01002678 /* Need to append a NUL to the result. */
2679 if (ga_grow(&redir_execute_ga, 1) == OK)
2680 {
2681 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2682 rettv->vval.v_string = redir_execute_ga.ga_data;
2683 }
2684 else
2685 {
2686 ga_clear(&redir_execute_ga);
2687 rettv->vval.v_string = NULL;
2688 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002689 msg_silent = save_msg_silent;
2690 emsg_silent = save_emsg_silent;
2691 emsg_noredir = save_emsg_noredir;
2692
2693 redir_execute = save_redir_execute;
2694 if (redir_execute)
2695 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002696 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002697
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002698 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002699 if (echo_output)
2700 // When not working silently: put it in column zero. A following
2701 // "echon" will overwrite the message, unavoidably.
2702 msg_col = 0;
2703 else
2704 // When working silently: Put it back where it was, since nothing
2705 // should have been written.
2706 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002707}
2708
2709/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002710 * "execute()" function
2711 */
2712 static void
2713f_execute(typval_T *argvars, typval_T *rettv)
2714{
2715 execute_common(argvars, rettv, 0);
2716}
2717
2718/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002719 * "exists()" function
2720 */
2721 static void
2722f_exists(typval_T *argvars, typval_T *rettv)
2723{
2724 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002725 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002726
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002727 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728 if (*p == '$') /* environment variable */
2729 {
2730 /* first try "normal" environment variables (fast) */
2731 if (mch_getenv(p + 1) != NULL)
2732 n = TRUE;
2733 else
2734 {
2735 /* try expanding things like $VIM and ${HOME} */
2736 p = expand_env_save(p);
2737 if (p != NULL && *p != '$')
2738 n = TRUE;
2739 vim_free(p);
2740 }
2741 }
2742 else if (*p == '&' || *p == '+') /* option */
2743 {
2744 n = (get_option_tv(&p, NULL, TRUE) == OK);
2745 if (*skipwhite(p) != NUL)
2746 n = FALSE; /* trailing garbage */
2747 }
2748 else if (*p == '*') /* internal or user defined function */
2749 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002750 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002751 }
2752 else if (*p == ':')
2753 {
2754 n = cmd_exists(p + 1);
2755 }
2756 else if (*p == '#')
2757 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002758 if (p[1] == '#')
2759 n = autocmd_supported(p + 2);
2760 else
2761 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002762 }
2763 else /* internal variable */
2764 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002765 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002766 }
2767
2768 rettv->vval.v_number = n;
2769}
2770
2771#ifdef FEAT_FLOAT
2772/*
2773 * "exp()" function
2774 */
2775 static void
2776f_exp(typval_T *argvars, typval_T *rettv)
2777{
2778 float_T f = 0.0;
2779
2780 rettv->v_type = VAR_FLOAT;
2781 if (get_float_arg(argvars, &f) == OK)
2782 rettv->vval.v_float = exp(f);
2783 else
2784 rettv->vval.v_float = 0.0;
2785}
2786#endif
2787
2788/*
2789 * "expand()" function
2790 */
2791 static void
2792f_expand(typval_T *argvars, typval_T *rettv)
2793{
2794 char_u *s;
2795 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002796 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002797 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2798 expand_T xpc;
2799 int error = FALSE;
2800 char_u *result;
2801
2802 rettv->v_type = VAR_STRING;
2803 if (argvars[1].v_type != VAR_UNKNOWN
2804 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002805 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002806 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002807 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002808
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002809 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002810 if (*s == '%' || *s == '#' || *s == '<')
2811 {
2812 ++emsg_off;
2813 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2814 --emsg_off;
2815 if (rettv->v_type == VAR_LIST)
2816 {
2817 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2818 list_append_string(rettv->vval.v_list, result, -1);
2819 else
2820 vim_free(result);
2821 }
2822 else
2823 rettv->vval.v_string = result;
2824 }
2825 else
2826 {
2827 /* When the optional second argument is non-zero, don't remove matches
2828 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2829 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002830 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002831 options |= WILD_KEEP_ALL;
2832 if (!error)
2833 {
2834 ExpandInit(&xpc);
2835 xpc.xp_context = EXPAND_FILES;
2836 if (p_wic)
2837 options += WILD_ICASE;
2838 if (rettv->v_type == VAR_STRING)
2839 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2840 options, WILD_ALL);
2841 else if (rettv_list_alloc(rettv) != FAIL)
2842 {
2843 int i;
2844
2845 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2846 for (i = 0; i < xpc.xp_numfiles; i++)
2847 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2848 ExpandCleanup(&xpc);
2849 }
2850 }
2851 else
2852 rettv->vval.v_string = NULL;
2853 }
2854}
2855
2856/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002857 * "expandcmd()" function
2858 * Expand all the special characters in a command string.
2859 */
2860 static void
2861f_expandcmd(typval_T *argvars, typval_T *rettv)
2862{
2863 exarg_T eap;
2864 char_u *cmdstr;
2865 char *errormsg = NULL;
2866
2867 rettv->v_type = VAR_STRING;
2868 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2869
2870 memset(&eap, 0, sizeof(eap));
2871 eap.cmd = cmdstr;
2872 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002873 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002874 eap.usefilter = FALSE;
2875 eap.nextcmd = NULL;
2876 eap.cmdidx = CMD_USER;
2877
2878 expand_filename(&eap, &cmdstr, &errormsg);
2879 if (errormsg != NULL && *errormsg != NUL)
2880 emsg(errormsg);
2881
2882 rettv->vval.v_string = cmdstr;
2883}
2884
2885/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002886 * "feedkeys()" function
2887 */
2888 static void
2889f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2890{
2891 int remap = TRUE;
2892 int insert = FALSE;
2893 char_u *keys, *flags;
2894 char_u nbuf[NUMBUFLEN];
2895 int typed = FALSE;
2896 int execute = FALSE;
2897 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002898 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002899 char_u *keys_esc;
2900
2901 /* This is not allowed in the sandbox. If the commands would still be
2902 * executed in the sandbox it would be OK, but it probably happens later,
2903 * when "sandbox" is no longer set. */
2904 if (check_secure())
2905 return;
2906
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002907 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002908
2909 if (argvars[1].v_type != VAR_UNKNOWN)
2910 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002911 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002912 for ( ; *flags != NUL; ++flags)
2913 {
2914 switch (*flags)
2915 {
2916 case 'n': remap = FALSE; break;
2917 case 'm': remap = TRUE; break;
2918 case 't': typed = TRUE; break;
2919 case 'i': insert = TRUE; break;
2920 case 'x': execute = TRUE; break;
2921 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002922 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002923 }
2924 }
2925 }
2926
2927 if (*keys != NUL || execute)
2928 {
2929 /* Need to escape K_SPECIAL and CSI before putting the string in the
2930 * typeahead buffer. */
2931 keys_esc = vim_strsave_escape_csi(keys);
2932 if (keys_esc != NULL)
2933 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002934 if (lowlevel)
2935 {
2936#ifdef USE_INPUT_BUF
2937 add_to_input_buf(keys, (int)STRLEN(keys));
2938#else
2939 emsg(_("E980: lowlevel input not supported"));
2940#endif
2941 }
2942 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002943 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002944 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002945 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002946 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002947#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002948 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002949#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002950 )
2951 typebuf_was_filled = TRUE;
2952 }
2953 vim_free(keys_esc);
2954
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002955 if (execute)
2956 {
2957 int save_msg_scroll = msg_scroll;
2958
2959 /* Avoid a 1 second delay when the keys start Insert mode. */
2960 msg_scroll = FALSE;
2961
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002962 if (!dangerous)
2963 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002964 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002965 if (!dangerous)
2966 --ex_normal_busy;
2967
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002968 msg_scroll |= save_msg_scroll;
2969 }
2970 }
2971 }
2972}
2973
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002974#ifdef FEAT_FLOAT
2975/*
2976 * "float2nr({float})" function
2977 */
2978 static void
2979f_float2nr(typval_T *argvars, typval_T *rettv)
2980{
2981 float_T f = 0.0;
2982
2983 if (get_float_arg(argvars, &f) == OK)
2984 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002985 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002986 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002987 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002988 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002989 else
2990 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002991 }
2992}
2993
2994/*
2995 * "floor({float})" function
2996 */
2997 static void
2998f_floor(typval_T *argvars, typval_T *rettv)
2999{
3000 float_T f = 0.0;
3001
3002 rettv->v_type = VAR_FLOAT;
3003 if (get_float_arg(argvars, &f) == OK)
3004 rettv->vval.v_float = floor(f);
3005 else
3006 rettv->vval.v_float = 0.0;
3007}
3008
3009/*
3010 * "fmod()" function
3011 */
3012 static void
3013f_fmod(typval_T *argvars, typval_T *rettv)
3014{
3015 float_T fx = 0.0, fy = 0.0;
3016
3017 rettv->v_type = VAR_FLOAT;
3018 if (get_float_arg(argvars, &fx) == OK
3019 && get_float_arg(&argvars[1], &fy) == OK)
3020 rettv->vval.v_float = fmod(fx, fy);
3021 else
3022 rettv->vval.v_float = 0.0;
3023}
3024#endif
3025
3026/*
3027 * "fnameescape({string})" function
3028 */
3029 static void
3030f_fnameescape(typval_T *argvars, typval_T *rettv)
3031{
3032 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003033 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003034 rettv->v_type = VAR_STRING;
3035}
3036
3037/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003038 * "foreground()" function
3039 */
3040 static void
3041f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3042{
3043#ifdef FEAT_GUI
3044 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003045 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003046 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003047 return;
3048 }
3049#endif
3050#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003051 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003052#endif
3053}
3054
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003055 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003056common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003057{
3058 char_u *s;
3059 char_u *name;
3060 int use_string = FALSE;
3061 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003062 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003063
3064 if (argvars[0].v_type == VAR_FUNC)
3065 {
3066 /* function(MyFunc, [arg], dict) */
3067 s = argvars[0].vval.v_string;
3068 }
3069 else if (argvars[0].v_type == VAR_PARTIAL
3070 && argvars[0].vval.v_partial != NULL)
3071 {
3072 /* function(dict.MyFunc, [arg]) */
3073 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003074 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003075 }
3076 else
3077 {
3078 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003079 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003080 use_string = TRUE;
3081 }
3082
Bram Moolenaar843b8842016-08-21 14:36:15 +02003083 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003084 {
3085 name = s;
3086 trans_name = trans_function_name(&name, FALSE,
3087 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3088 if (*name != NUL)
3089 s = NULL;
3090 }
3091
Bram Moolenaar843b8842016-08-21 14:36:15 +02003092 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3093 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003094 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003095 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003096 else if (trans_name != NULL && (is_funcref
3097 ? find_func(trans_name) == NULL
3098 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003099 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003100 else
3101 {
3102 int dict_idx = 0;
3103 int arg_idx = 0;
3104 list_T *list = NULL;
3105
3106 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3107 {
3108 char sid_buf[25];
3109 int off = *s == 's' ? 2 : 5;
3110
3111 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3112 * also be called from another script. Using trans_function_name()
3113 * would also work, but some plugins depend on the name being
3114 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003115 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003116 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003117 if (name != NULL)
3118 {
3119 STRCPY(name, sid_buf);
3120 STRCAT(name, s + off);
3121 }
3122 }
3123 else
3124 name = vim_strsave(s);
3125
3126 if (argvars[1].v_type != VAR_UNKNOWN)
3127 {
3128 if (argvars[2].v_type != VAR_UNKNOWN)
3129 {
3130 /* function(name, [args], dict) */
3131 arg_idx = 1;
3132 dict_idx = 2;
3133 }
3134 else if (argvars[1].v_type == VAR_DICT)
3135 /* function(name, dict) */
3136 dict_idx = 1;
3137 else
3138 /* function(name, [args]) */
3139 arg_idx = 1;
3140 if (dict_idx > 0)
3141 {
3142 if (argvars[dict_idx].v_type != VAR_DICT)
3143 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003144 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003145 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003146 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003147 }
3148 if (argvars[dict_idx].vval.v_dict == NULL)
3149 dict_idx = 0;
3150 }
3151 if (arg_idx > 0)
3152 {
3153 if (argvars[arg_idx].v_type != VAR_LIST)
3154 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003155 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003156 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003157 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003158 }
3159 list = argvars[arg_idx].vval.v_list;
3160 if (list == NULL || list->lv_len == 0)
3161 arg_idx = 0;
3162 }
3163 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003164 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003165 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003166 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003167
3168 /* result is a VAR_PARTIAL */
3169 if (pt == NULL)
3170 vim_free(name);
3171 else
3172 {
3173 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3174 {
3175 listitem_T *li;
3176 int i = 0;
3177 int arg_len = 0;
3178 int lv_len = 0;
3179
3180 if (arg_pt != NULL)
3181 arg_len = arg_pt->pt_argc;
3182 if (list != NULL)
3183 lv_len = list->lv_len;
3184 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003185 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003186 if (pt->pt_argv == NULL)
3187 {
3188 vim_free(pt);
3189 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003190 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003191 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003192 for (i = 0; i < arg_len; i++)
3193 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3194 if (lv_len > 0)
3195 for (li = list->lv_first; li != NULL;
3196 li = li->li_next)
3197 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003198 }
3199
3200 /* For "function(dict.func, [], dict)" and "func" is a partial
3201 * use "dict". That is backwards compatible. */
3202 if (dict_idx > 0)
3203 {
3204 /* The dict is bound explicitly, pt_auto is FALSE. */
3205 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3206 ++pt->pt_dict->dv_refcount;
3207 }
3208 else if (arg_pt != NULL)
3209 {
3210 /* If the dict was bound automatically the result is also
3211 * bound automatically. */
3212 pt->pt_dict = arg_pt->pt_dict;
3213 pt->pt_auto = arg_pt->pt_auto;
3214 if (pt->pt_dict != NULL)
3215 ++pt->pt_dict->dv_refcount;
3216 }
3217
3218 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003219 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3220 {
3221 pt->pt_func = arg_pt->pt_func;
3222 func_ptr_ref(pt->pt_func);
3223 vim_free(name);
3224 }
3225 else if (is_funcref)
3226 {
3227 pt->pt_func = find_func(trans_name);
3228 func_ptr_ref(pt->pt_func);
3229 vim_free(name);
3230 }
3231 else
3232 {
3233 pt->pt_name = name;
3234 func_ref(name);
3235 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003236 }
3237 rettv->v_type = VAR_PARTIAL;
3238 rettv->vval.v_partial = pt;
3239 }
3240 else
3241 {
3242 /* result is a VAR_FUNC */
3243 rettv->v_type = VAR_FUNC;
3244 rettv->vval.v_string = name;
3245 func_ref(name);
3246 }
3247 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003248theend:
3249 vim_free(trans_name);
3250}
3251
3252/*
3253 * "funcref()" function
3254 */
3255 static void
3256f_funcref(typval_T *argvars, typval_T *rettv)
3257{
3258 common_function(argvars, rettv, TRUE);
3259}
3260
3261/*
3262 * "function()" function
3263 */
3264 static void
3265f_function(typval_T *argvars, typval_T *rettv)
3266{
3267 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003268}
3269
3270/*
3271 * "garbagecollect()" function
3272 */
3273 static void
3274f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3275{
3276 /* This is postponed until we are back at the toplevel, because we may be
3277 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3278 want_garbage_collect = TRUE;
3279
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003280 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003281 garbage_collect_at_exit = TRUE;
3282}
3283
3284/*
3285 * "get()" function
3286 */
3287 static void
3288f_get(typval_T *argvars, typval_T *rettv)
3289{
3290 listitem_T *li;
3291 list_T *l;
3292 dictitem_T *di;
3293 dict_T *d;
3294 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003295 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003296
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003297 if (argvars[0].v_type == VAR_BLOB)
3298 {
3299 int error = FALSE;
3300 int idx = tv_get_number_chk(&argvars[1], &error);
3301
3302 if (!error)
3303 {
3304 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003305 if (idx < 0)
3306 idx = blob_len(argvars[0].vval.v_blob) + idx;
3307 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
3308 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003309 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003310 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003311 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003312 tv = rettv;
3313 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003314 }
3315 }
3316 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317 {
3318 if ((l = argvars[0].vval.v_list) != NULL)
3319 {
3320 int error = FALSE;
3321
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003322 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003323 if (!error && li != NULL)
3324 tv = &li->li_tv;
3325 }
3326 }
3327 else if (argvars[0].v_type == VAR_DICT)
3328 {
3329 if ((d = argvars[0].vval.v_dict) != NULL)
3330 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003331 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003332 if (di != NULL)
3333 tv = &di->di_tv;
3334 }
3335 }
3336 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3337 {
3338 partial_T *pt;
3339 partial_T fref_pt;
3340
3341 if (argvars[0].v_type == VAR_PARTIAL)
3342 pt = argvars[0].vval.v_partial;
3343 else
3344 {
3345 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3346 fref_pt.pt_name = argvars[0].vval.v_string;
3347 pt = &fref_pt;
3348 }
3349
3350 if (pt != NULL)
3351 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003352 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003353 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003354
3355 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3356 {
3357 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003358 n = partial_name(pt);
3359 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003360 rettv->vval.v_string = NULL;
3361 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003362 {
3363 rettv->vval.v_string = vim_strsave(n);
3364 if (rettv->v_type == VAR_FUNC)
3365 func_ref(rettv->vval.v_string);
3366 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003367 }
3368 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003369 {
3370 what_is_dict = TRUE;
3371 if (pt->pt_dict != NULL)
3372 rettv_dict_set(rettv, pt->pt_dict);
3373 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003374 else if (STRCMP(what, "args") == 0)
3375 {
3376 rettv->v_type = VAR_LIST;
3377 if (rettv_list_alloc(rettv) == OK)
3378 {
3379 int i;
3380
3381 for (i = 0; i < pt->pt_argc; ++i)
3382 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3383 }
3384 }
3385 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003386 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003387
3388 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3389 // third argument
3390 if (!what_is_dict)
3391 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003392 }
3393 }
3394 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003395 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003396
3397 if (tv == NULL)
3398 {
3399 if (argvars[2].v_type != VAR_UNKNOWN)
3400 copy_tv(&argvars[2], rettv);
3401 }
3402 else
3403 copy_tv(tv, rettv);
3404}
3405
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003406/*
3407 * Returns buffer options, variables and other attributes in a dictionary.
3408 */
3409 static dict_T *
3410get_buffer_info(buf_T *buf)
3411{
3412 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003413 tabpage_T *tp;
3414 win_T *wp;
3415 list_T *windows;
3416
3417 dict = dict_alloc();
3418 if (dict == NULL)
3419 return NULL;
3420
Bram Moolenaare0be1672018-07-08 16:50:37 +02003421 dict_add_number(dict, "bufnr", buf->b_fnum);
3422 dict_add_string(dict, "name", buf->b_ffname);
3423 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
3424 : buflist_findlnum(buf));
3425 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
3426 dict_add_number(dict, "listed", buf->b_p_bl);
3427 dict_add_number(dict, "changed", bufIsChanged(buf));
3428 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
3429 dict_add_number(dict, "hidden",
3430 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003431
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003432 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02003433 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003434
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003435 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003436 windows = list_alloc();
3437 if (windows != NULL)
3438 {
3439 FOR_ALL_TAB_WINDOWS(tp, wp)
3440 if (wp->w_buffer == buf)
3441 list_append_number(windows, (varnumber_T)wp->w_id);
3442 dict_add_list(dict, "windows", windows);
3443 }
3444
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003445#ifdef FEAT_TEXT_PROP
3446 // List of popup windows displaying this buffer
3447 windows = list_alloc();
3448 if (windows != NULL)
3449 {
3450 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
3451 if (wp->w_buffer == buf)
3452 list_append_number(windows, (varnumber_T)wp->w_id);
3453 FOR_ALL_TABPAGES(tp)
3454 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
3455 if (wp->w_buffer == buf)
3456 list_append_number(windows, (varnumber_T)wp->w_id);
3457
3458 dict_add_list(dict, "popups", windows);
3459 }
3460#endif
3461
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003462#ifdef FEAT_SIGNS
3463 if (buf->b_signlist != NULL)
3464 {
3465 /* List of signs placed in this buffer */
3466 list_T *signs = list_alloc();
3467 if (signs != NULL)
3468 {
3469 get_buffer_signs(buf, signs);
3470 dict_add_list(dict, "signs", signs);
3471 }
3472 }
3473#endif
3474
3475 return dict;
3476}
3477
3478/*
3479 * "getbufinfo()" function
3480 */
3481 static void
3482f_getbufinfo(typval_T *argvars, typval_T *rettv)
3483{
3484 buf_T *buf = NULL;
3485 buf_T *argbuf = NULL;
3486 dict_T *d;
3487 int filtered = FALSE;
3488 int sel_buflisted = FALSE;
3489 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003490 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003491
3492 if (rettv_list_alloc(rettv) != OK)
3493 return;
3494
3495 /* List of all the buffers or selected buffers */
3496 if (argvars[0].v_type == VAR_DICT)
3497 {
3498 dict_T *sel_d = argvars[0].vval.v_dict;
3499
3500 if (sel_d != NULL)
3501 {
3502 dictitem_T *di;
3503
3504 filtered = TRUE;
3505
3506 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003507 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003508 sel_buflisted = TRUE;
3509
3510 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003511 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003512 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003513
3514 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003515 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003516 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003517 }
3518 }
3519 else if (argvars[0].v_type != VAR_UNKNOWN)
3520 {
3521 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003522 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003523 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003524 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003525 --emsg_off;
3526 if (argbuf == NULL)
3527 return;
3528 }
3529
3530 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02003531 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003532 {
3533 if (argbuf != NULL && argbuf != buf)
3534 continue;
3535 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003536 || (sel_buflisted && !buf->b_p_bl)
3537 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003538 continue;
3539
3540 d = get_buffer_info(buf);
3541 if (d != NULL)
3542 list_append_dict(rettv->vval.v_list, d);
3543 if (argbuf != NULL)
3544 return;
3545 }
3546}
3547
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003548/*
3549 * Get line or list of lines from buffer "buf" into "rettv".
3550 * Return a range (from start to end) of lines in rettv from the specified
3551 * buffer.
3552 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
3553 */
3554 static void
3555get_buffer_lines(
3556 buf_T *buf,
3557 linenr_T start,
3558 linenr_T end,
3559 int retlist,
3560 typval_T *rettv)
3561{
3562 char_u *p;
3563
3564 rettv->v_type = VAR_STRING;
3565 rettv->vval.v_string = NULL;
3566 if (retlist && rettv_list_alloc(rettv) == FAIL)
3567 return;
3568
3569 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
3570 return;
3571
3572 if (!retlist)
3573 {
3574 if (start >= 1 && start <= buf->b_ml.ml_line_count)
3575 p = ml_get_buf(buf, start, FALSE);
3576 else
3577 p = (char_u *)"";
3578 rettv->vval.v_string = vim_strsave(p);
3579 }
3580 else
3581 {
3582 if (end < start)
3583 return;
3584
3585 if (start < 1)
3586 start = 1;
3587 if (end > buf->b_ml.ml_line_count)
3588 end = buf->b_ml.ml_line_count;
3589 while (start <= end)
3590 if (list_append_string(rettv->vval.v_list,
3591 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
3592 break;
3593 }
3594}
3595
3596/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003597 * "getbufline()" function
3598 */
3599 static void
3600f_getbufline(typval_T *argvars, typval_T *rettv)
3601{
3602 linenr_T lnum;
3603 linenr_T end;
3604 buf_T *buf;
3605
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003606 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003607 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003608 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003609 --emsg_off;
3610
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003611 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003612 if (argvars[2].v_type == VAR_UNKNOWN)
3613 end = lnum;
3614 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003615 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003616
3617 get_buffer_lines(buf, lnum, end, TRUE, rettv);
3618}
3619
3620/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003621 * "getchangelist()" function
3622 */
3623 static void
3624f_getchangelist(typval_T *argvars, typval_T *rettv)
3625{
3626#ifdef FEAT_JUMPLIST
3627 buf_T *buf;
3628 int i;
3629 list_T *l;
3630 dict_T *d;
3631#endif
3632
3633 if (rettv_list_alloc(rettv) != OK)
3634 return;
3635
3636#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003637 if (argvars[0].v_type == VAR_UNKNOWN)
3638 buf = curbuf;
3639 else
3640 {
3641 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3642 ++emsg_off;
3643 buf = tv_get_buf(&argvars[0], FALSE);
3644 --emsg_off;
3645 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003646 if (buf == NULL)
3647 return;
3648
3649 l = list_alloc();
3650 if (l == NULL)
3651 return;
3652
3653 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3654 return;
3655 /*
3656 * The current window change list index tracks only the position in the
3657 * current buffer change list. For other buffers, use the change list
3658 * length as the current index.
3659 */
3660 list_append_number(rettv->vval.v_list,
3661 (varnumber_T)((buf == curwin->w_buffer)
3662 ? curwin->w_changelistidx : buf->b_changelistlen));
3663
3664 for (i = 0; i < buf->b_changelistlen; ++i)
3665 {
3666 if (buf->b_changelist[i].lnum == 0)
3667 continue;
3668 if ((d = dict_alloc()) == NULL)
3669 return;
3670 if (list_append_dict(l, d) == FAIL)
3671 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003672 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3673 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003674 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003675 }
3676#endif
3677}
3678/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003679 * "getchar()" function
3680 */
3681 static void
3682f_getchar(typval_T *argvars, typval_T *rettv)
3683{
3684 varnumber_T n;
3685 int error = FALSE;
3686
Bram Moolenaar84d93902018-09-11 20:10:20 +02003687#ifdef MESSAGE_QUEUE
3688 // vpeekc() used to check for messages, but that caused problems, invoking
3689 // a callback where it was not expected. Some plugins use getchar(1) in a
3690 // loop to await a message, therefore make sure we check for messages here.
3691 parse_queued_messages();
3692#endif
3693
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003694 /* Position the cursor. Needed after a message that ends in a space. */
3695 windgoto(msg_row, msg_col);
3696
3697 ++no_mapping;
3698 ++allow_keys;
3699 for (;;)
3700 {
3701 if (argvars[0].v_type == VAR_UNKNOWN)
3702 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01003703 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003704 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003705 /* getchar(1): only check if char avail */
3706 n = vpeekc_any();
3707 else if (error || vpeekc_any() == NUL)
3708 /* illegal argument or getchar(0) and no char avail: return zero */
3709 n = 0;
3710 else
3711 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01003712 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003713
3714 if (n == K_IGNORE)
3715 continue;
3716 break;
3717 }
3718 --no_mapping;
3719 --allow_keys;
3720
3721 set_vim_var_nr(VV_MOUSE_WIN, 0);
3722 set_vim_var_nr(VV_MOUSE_WINID, 0);
3723 set_vim_var_nr(VV_MOUSE_LNUM, 0);
3724 set_vim_var_nr(VV_MOUSE_COL, 0);
3725
3726 rettv->vval.v_number = n;
3727 if (IS_SPECIAL(n) || mod_mask != 0)
3728 {
3729 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
3730 int i = 0;
3731
3732 /* Turn a special key into three bytes, plus modifier. */
3733 if (mod_mask != 0)
3734 {
3735 temp[i++] = K_SPECIAL;
3736 temp[i++] = KS_MODIFIER;
3737 temp[i++] = mod_mask;
3738 }
3739 if (IS_SPECIAL(n))
3740 {
3741 temp[i++] = K_SPECIAL;
3742 temp[i++] = K_SECOND(n);
3743 temp[i++] = K_THIRD(n);
3744 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003745 else if (has_mbyte)
3746 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747 else
3748 temp[i++] = n;
3749 temp[i++] = NUL;
3750 rettv->v_type = VAR_STRING;
3751 rettv->vval.v_string = vim_strsave(temp);
3752
3753#ifdef FEAT_MOUSE
3754 if (is_mouse_key(n))
3755 {
3756 int row = mouse_row;
3757 int col = mouse_col;
3758 win_T *win;
3759 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003760 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003761 int winnr = 1;
3762
3763 if (row >= 0 && col >= 0)
3764 {
3765 /* Find the window at the mouse coordinates and compute the
3766 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003767 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02003768 if (win == NULL)
3769 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02003770 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003771# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02003772 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003773 winnr = 0;
3774 else
3775# endif
3776 for (wp = firstwin; wp != win && wp != NULL;
3777 wp = wp->w_next)
3778 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003779 set_vim_var_nr(VV_MOUSE_WIN, winnr);
3780 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
3781 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
3782 set_vim_var_nr(VV_MOUSE_COL, col + 1);
3783 }
3784 }
3785#endif
3786 }
3787}
3788
3789/*
3790 * "getcharmod()" function
3791 */
3792 static void
3793f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
3794{
3795 rettv->vval.v_number = mod_mask;
3796}
3797
3798/*
3799 * "getcharsearch()" function
3800 */
3801 static void
3802f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3803{
3804 if (rettv_dict_alloc(rettv) != FAIL)
3805 {
3806 dict_T *dict = rettv->vval.v_dict;
3807
Bram Moolenaare0be1672018-07-08 16:50:37 +02003808 dict_add_string(dict, "char", last_csearch());
3809 dict_add_number(dict, "forward", last_csearch_forward());
3810 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003811 }
3812}
3813
3814/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003815 * "getcmdwintype()" function
3816 */
3817 static void
3818f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
3819{
3820 rettv->v_type = VAR_STRING;
3821 rettv->vval.v_string = NULL;
3822#ifdef FEAT_CMDWIN
3823 rettv->vval.v_string = alloc(2);
3824 if (rettv->vval.v_string != NULL)
3825 {
3826 rettv->vval.v_string[0] = cmdwin_type;
3827 rettv->vval.v_string[1] = NUL;
3828 }
3829#endif
3830}
3831
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003832/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003833 * "getenv()" function
3834 */
3835 static void
3836f_getenv(typval_T *argvars, typval_T *rettv)
3837{
3838 int mustfree = FALSE;
3839 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3840
3841 if (p == NULL)
3842 {
3843 rettv->v_type = VAR_SPECIAL;
3844 rettv->vval.v_number = VVAL_NULL;
3845 return;
3846 }
3847 if (!mustfree)
3848 p = vim_strsave(p);
3849 rettv->vval.v_string = p;
3850 rettv->v_type = VAR_STRING;
3851}
3852
3853/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003854 * "getfontname()" function
3855 */
3856 static void
3857f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3858{
3859 rettv->v_type = VAR_STRING;
3860 rettv->vval.v_string = NULL;
3861#ifdef FEAT_GUI
3862 if (gui.in_use)
3863 {
3864 GuiFont font;
3865 char_u *name = NULL;
3866
3867 if (argvars[0].v_type == VAR_UNKNOWN)
3868 {
3869 /* Get the "Normal" font. Either the name saved by
3870 * hl_set_font_name() or from the font ID. */
3871 font = gui.norm_font;
3872 name = hl_get_font_name();
3873 }
3874 else
3875 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003876 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003877 if (STRCMP(name, "*") == 0) /* don't use font dialog */
3878 return;
3879 font = gui_mch_get_font(name, FALSE);
3880 if (font == NOFONT)
3881 return; /* Invalid font name, return empty string. */
3882 }
3883 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3884 if (argvars[0].v_type != VAR_UNKNOWN)
3885 gui_mch_free_font(font);
3886 }
3887#endif
3888}
3889
3890/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003891 * "getjumplist()" function
3892 */
3893 static void
3894f_getjumplist(typval_T *argvars, typval_T *rettv)
3895{
3896#ifdef FEAT_JUMPLIST
3897 win_T *wp;
3898 int i;
3899 list_T *l;
3900 dict_T *d;
3901#endif
3902
3903 if (rettv_list_alloc(rettv) != OK)
3904 return;
3905
3906#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003907 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003908 if (wp == NULL)
3909 return;
3910
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003911 cleanup_jumplist(wp, TRUE);
3912
Bram Moolenaar4f505882018-02-10 21:06:32 +01003913 l = list_alloc();
3914 if (l == NULL)
3915 return;
3916
3917 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3918 return;
3919 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3920
3921 for (i = 0; i < wp->w_jumplistlen; ++i)
3922 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003923 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3924 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003925 if ((d = dict_alloc()) == NULL)
3926 return;
3927 if (list_append_dict(l, d) == FAIL)
3928 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003929 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3930 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003931 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003932 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003933 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003934 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003935 }
3936#endif
3937}
3938
3939/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003940 * "getline(lnum, [end])" function
3941 */
3942 static void
3943f_getline(typval_T *argvars, typval_T *rettv)
3944{
3945 linenr_T lnum;
3946 linenr_T end;
3947 int retlist;
3948
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003949 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003950 if (argvars[1].v_type == VAR_UNKNOWN)
3951 {
3952 end = 0;
3953 retlist = FALSE;
3954 }
3955 else
3956 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003957 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003958 retlist = TRUE;
3959 }
3960
3961 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
3962}
3963
3964/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003965 * "getpid()" function
3966 */
3967 static void
3968f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3969{
3970 rettv->vval.v_number = mch_get_pid();
3971}
3972
3973 static void
3974getpos_both(
3975 typval_T *argvars,
3976 typval_T *rettv,
3977 int getcurpos)
3978{
3979 pos_T *fp;
3980 list_T *l;
3981 int fnum = -1;
3982
3983 if (rettv_list_alloc(rettv) == OK)
3984 {
3985 l = rettv->vval.v_list;
3986 if (getcurpos)
3987 fp = &curwin->w_cursor;
3988 else
3989 fp = var2fpos(&argvars[0], TRUE, &fnum);
3990 if (fnum != -1)
3991 list_append_number(l, (varnumber_T)fnum);
3992 else
3993 list_append_number(l, (varnumber_T)0);
3994 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3995 : (varnumber_T)0);
3996 list_append_number(l, (fp != NULL)
3997 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
3998 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003999 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004000 (varnumber_T)0);
4001 if (getcurpos)
4002 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01004003 int save_set_curswant = curwin->w_set_curswant;
4004 colnr_T save_curswant = curwin->w_curswant;
4005 colnr_T save_virtcol = curwin->w_virtcol;
4006
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007 update_curswant();
4008 list_append_number(l, curwin->w_curswant == MAXCOL ?
4009 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01004010
4011 // Do not change "curswant", as it is unexpected that a get
4012 // function has a side effect.
4013 if (save_set_curswant)
4014 {
4015 curwin->w_set_curswant = save_set_curswant;
4016 curwin->w_curswant = save_curswant;
4017 curwin->w_virtcol = save_virtcol;
4018 curwin->w_valid &= ~VALID_VIRTCOL;
4019 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004020 }
4021 }
4022 else
4023 rettv->vval.v_number = FALSE;
4024}
4025
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004026/*
4027 * "getcurpos()" function
4028 */
4029 static void
4030f_getcurpos(typval_T *argvars, typval_T *rettv)
4031{
4032 getpos_both(argvars, rettv, TRUE);
4033}
4034
4035/*
4036 * "getpos(string)" function
4037 */
4038 static void
4039f_getpos(typval_T *argvars, typval_T *rettv)
4040{
4041 getpos_both(argvars, rettv, FALSE);
4042}
4043
4044/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004045 * "getreg()" function
4046 */
4047 static void
4048f_getreg(typval_T *argvars, typval_T *rettv)
4049{
4050 char_u *strregname;
4051 int regname;
4052 int arg2 = FALSE;
4053 int return_list = FALSE;
4054 int error = FALSE;
4055
4056 if (argvars[0].v_type != VAR_UNKNOWN)
4057 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004058 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004059 error = strregname == NULL;
4060 if (argvars[1].v_type != VAR_UNKNOWN)
4061 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004062 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004063 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004064 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004065 }
4066 }
4067 else
4068 strregname = get_vim_var_str(VV_REG);
4069
4070 if (error)
4071 return;
4072
4073 regname = (strregname == NULL ? '"' : *strregname);
4074 if (regname == 0)
4075 regname = '"';
4076
4077 if (return_list)
4078 {
4079 rettv->v_type = VAR_LIST;
4080 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4081 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4082 if (rettv->vval.v_list == NULL)
4083 (void)rettv_list_alloc(rettv);
4084 else
4085 ++rettv->vval.v_list->lv_refcount;
4086 }
4087 else
4088 {
4089 rettv->v_type = VAR_STRING;
4090 rettv->vval.v_string = get_reg_contents(regname,
4091 arg2 ? GREG_EXPR_SRC : 0);
4092 }
4093}
4094
4095/*
4096 * "getregtype()" function
4097 */
4098 static void
4099f_getregtype(typval_T *argvars, typval_T *rettv)
4100{
4101 char_u *strregname;
4102 int regname;
4103 char_u buf[NUMBUFLEN + 2];
4104 long reglen = 0;
4105
4106 if (argvars[0].v_type != VAR_UNKNOWN)
4107 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004108 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004109 if (strregname == NULL) /* type error; errmsg already given */
4110 {
4111 rettv->v_type = VAR_STRING;
4112 rettv->vval.v_string = NULL;
4113 return;
4114 }
4115 }
4116 else
4117 /* Default to v:register */
4118 strregname = get_vim_var_str(VV_REG);
4119
4120 regname = (strregname == NULL ? '"' : *strregname);
4121 if (regname == 0)
4122 regname = '"';
4123
4124 buf[0] = NUL;
4125 buf[1] = NUL;
4126 switch (get_reg_type(regname, &reglen))
4127 {
4128 case MLINE: buf[0] = 'V'; break;
4129 case MCHAR: buf[0] = 'v'; break;
4130 case MBLOCK:
4131 buf[0] = Ctrl_V;
4132 sprintf((char *)buf + 1, "%ld", reglen + 1);
4133 break;
4134 }
4135 rettv->v_type = VAR_STRING;
4136 rettv->vval.v_string = vim_strsave(buf);
4137}
4138
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004139/*
4140 * Returns information (variables, options, etc.) about a tab page
4141 * as a dictionary.
4142 */
4143 static dict_T *
4144get_tabpage_info(tabpage_T *tp, int tp_idx)
4145{
4146 win_T *wp;
4147 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004148 list_T *l;
4149
4150 dict = dict_alloc();
4151 if (dict == NULL)
4152 return NULL;
4153
Bram Moolenaare0be1672018-07-08 16:50:37 +02004154 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004155
4156 l = list_alloc();
4157 if (l != NULL)
4158 {
4159 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004160 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004161 list_append_number(l, (varnumber_T)wp->w_id);
4162 dict_add_list(dict, "windows", l);
4163 }
4164
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004165 /* Make a reference to tabpage variables */
4166 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004167
4168 return dict;
4169}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004170
4171/*
4172 * "gettabinfo()" function
4173 */
4174 static void
4175f_gettabinfo(typval_T *argvars, typval_T *rettv)
4176{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004177 tabpage_T *tp, *tparg = NULL;
4178 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02004179 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004180
4181 if (rettv_list_alloc(rettv) != OK)
4182 return;
4183
4184 if (argvars[0].v_type != VAR_UNKNOWN)
4185 {
4186 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004187 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004188 if (tparg == NULL)
4189 return;
4190 }
4191
4192 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004193 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004194 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004195 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004196 if (tparg != NULL && tp != tparg)
4197 continue;
4198 d = get_tabpage_info(tp, tpnr);
4199 if (d != NULL)
4200 list_append_dict(rettv->vval.v_list, d);
4201 if (tparg != NULL)
4202 return;
4203 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004204}
4205
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004206/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01004207 * "gettagstack()" function
4208 */
4209 static void
4210f_gettagstack(typval_T *argvars, typval_T *rettv)
4211{
4212 win_T *wp = curwin; // default is current window
4213
4214 if (rettv_dict_alloc(rettv) != OK)
4215 return;
4216
4217 if (argvars[0].v_type != VAR_UNKNOWN)
4218 {
4219 wp = find_win_by_nr_or_id(&argvars[0]);
4220 if (wp == NULL)
4221 return;
4222 }
4223
4224 get_tagstack(wp, rettv->vval.v_dict);
4225}
4226
4227/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004228 * Returns information about a window as a dictionary.
4229 */
4230 static dict_T *
4231get_win_info(win_T *wp, short tpnr, short winnr)
4232{
4233 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004234
4235 dict = dict_alloc();
4236 if (dict == NULL)
4237 return NULL;
4238
Bram Moolenaare0be1672018-07-08 16:50:37 +02004239 dict_add_number(dict, "tabnr", tpnr);
4240 dict_add_number(dict, "winnr", winnr);
4241 dict_add_number(dict, "winid", wp->w_id);
4242 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02004243 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01004244 dict_add_number(dict, "topline", wp->w_topline);
4245 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02004246#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02004247 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02004248#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02004249 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02004250 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004251 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004252
Bram Moolenaar69905d12017-08-13 18:14:47 +02004253#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02004254 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02004255#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02004256#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02004257 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
4258 dict_add_number(dict, "loclist",
4259 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02004260#endif
4261
Bram Moolenaar30567352016-08-27 21:25:44 +02004262 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004263 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004264
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004265 return dict;
4266}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004267
4268/*
4269 * "getwininfo()" function
4270 */
4271 static void
4272f_getwininfo(typval_T *argvars, typval_T *rettv)
4273{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004274 tabpage_T *tp;
4275 win_T *wp = NULL, *wparg = NULL;
4276 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02004277 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004278
4279 if (rettv_list_alloc(rettv) != OK)
4280 return;
4281
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004282 if (argvars[0].v_type != VAR_UNKNOWN)
4283 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01004284 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004285 if (wparg == NULL)
4286 return;
4287 }
4288
4289 /* Collect information about either all the windows across all the tab
4290 * pages or one particular window.
4291 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004292 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004293 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004294 tabnr++;
4295 winnr = 0;
4296 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004297 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004298 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004299 if (wparg != NULL && wp != wparg)
4300 continue;
4301 d = get_win_info(wp, tabnr, winnr);
4302 if (d != NULL)
4303 list_append_dict(rettv->vval.v_list, d);
4304 if (wparg != NULL)
4305 /* found information about a specific window */
4306 return;
4307 }
4308 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004309}
4310
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004311/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004312 * "win_execute()" function
4313 */
4314 static void
4315f_win_execute(typval_T *argvars, typval_T *rettv)
4316{
4317 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02004318 tabpage_T *tp;
4319 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004320 win_T *save_curwin;
4321 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004322
Bram Moolenaar820680b2019-08-09 14:56:22 +02004323 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004324 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02004325 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004326 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004327 check_cursor();
4328 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004329 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004330 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004331 }
4332}
4333
4334/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004335 * "win_findbuf()" function
4336 */
4337 static void
4338f_win_findbuf(typval_T *argvars, typval_T *rettv)
4339{
4340 if (rettv_list_alloc(rettv) != FAIL)
4341 win_findbuf(argvars, rettv->vval.v_list);
4342}
4343
4344/*
4345 * "win_getid()" function
4346 */
4347 static void
4348f_win_getid(typval_T *argvars, typval_T *rettv)
4349{
4350 rettv->vval.v_number = win_getid(argvars);
4351}
4352
4353/*
4354 * "win_gotoid()" function
4355 */
4356 static void
4357f_win_gotoid(typval_T *argvars, typval_T *rettv)
4358{
4359 rettv->vval.v_number = win_gotoid(argvars);
4360}
4361
4362/*
4363 * "win_id2tabwin()" function
4364 */
4365 static void
4366f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
4367{
4368 if (rettv_list_alloc(rettv) != FAIL)
4369 win_id2tabwin(argvars, rettv->vval.v_list);
4370}
4371
4372/*
4373 * "win_id2win()" function
4374 */
4375 static void
4376f_win_id2win(typval_T *argvars, typval_T *rettv)
4377{
4378 rettv->vval.v_number = win_id2win(argvars);
4379}
4380
4381/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01004382 * "win_screenpos()" function
4383 */
4384 static void
4385f_win_screenpos(typval_T *argvars, typval_T *rettv)
4386{
4387 win_T *wp;
4388
4389 if (rettv_list_alloc(rettv) == FAIL)
4390 return;
4391
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02004392 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01004393 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
4394 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
4395}
4396
4397/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004398 * "getwinpos({timeout})" function
4399 */
4400 static void
4401f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
4402{
4403 int x = -1;
4404 int y = -1;
4405
4406 if (rettv_list_alloc(rettv) == FAIL)
4407 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004408#if defined(FEAT_GUI) \
4409 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4410 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004411 {
4412 varnumber_T timeout = 100;
4413
4414 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004415 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004416
4417 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004418 }
4419#endif
4420 list_append_number(rettv->vval.v_list, (varnumber_T)x);
4421 list_append_number(rettv->vval.v_list, (varnumber_T)y);
4422}
4423
4424
4425/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004426 * "getwinposx()" function
4427 */
4428 static void
4429f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
4430{
4431 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004432#if defined(FEAT_GUI) \
4433 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4434 || defined(MSWIN)
4435
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004436 {
4437 int x, y;
4438
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004439 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004440 rettv->vval.v_number = x;
4441 }
4442#endif
4443}
4444
4445/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004446 * "getwinposy()" function
4447 */
4448 static void
4449f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
4450{
4451 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004452#if defined(FEAT_GUI) \
4453 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4454 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004455 {
4456 int x, y;
4457
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004458 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004459 rettv->vval.v_number = y;
4460 }
4461#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004462}
4463
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004464/* for VIM_VERSION_ defines */
4465#include "version.h"
4466
4467/*
4468 * "has()" function
4469 */
4470 static void
4471f_has(typval_T *argvars, typval_T *rettv)
4472{
4473 int i;
4474 char_u *name;
4475 int n = FALSE;
4476 static char *(has_list[]) =
4477 {
4478#ifdef AMIGA
4479 "amiga",
4480# ifdef FEAT_ARP
4481 "arp",
4482# endif
4483#endif
4484#ifdef __BEOS__
4485 "beos",
4486#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004487#if defined(BSD) && !defined(MACOS_X)
4488 "bsd",
4489#endif
4490#ifdef hpux
4491 "hpux",
4492#endif
4493#ifdef __linux__
4494 "linux",
4495#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02004496#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01004497 "mac", /* Mac OS X (and, once, Mac OS Classic) */
4498 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02004499# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01004500 "macunix", /* Mac OS X, with the darwin feature */
4501 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02004502# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004503#endif
4504#ifdef __QNX__
4505 "qnx",
4506#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004507#ifdef SUN_SYSTEM
4508 "sun",
4509#else
4510 "moon",
4511#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004512#ifdef UNIX
4513 "unix",
4514#endif
4515#ifdef VMS
4516 "vms",
4517#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004518#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004519 "win32",
4520#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01004521#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004522 "win32unix",
4523#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01004524#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004525 "win64",
4526#endif
4527#ifdef EBCDIC
4528 "ebcdic",
4529#endif
4530#ifndef CASE_INSENSITIVE_FILENAME
4531 "fname_case",
4532#endif
4533#ifdef HAVE_ACL
4534 "acl",
4535#endif
4536#ifdef FEAT_ARABIC
4537 "arabic",
4538#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004539 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004540#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004541 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004542#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01004543#ifdef FEAT_AUTOSERVERNAME
4544 "autoservername",
4545#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004546#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004547 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01004548# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549 "balloon_multiline",
4550# endif
4551#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004552#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01004553 "balloon_eval_term",
4554#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004555#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
4556 "builtin_terms",
4557# ifdef ALL_BUILTIN_TCAPS
4558 "all_builtin_terms",
4559# endif
4560#endif
4561#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01004562 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004563 || defined(FEAT_GUI_MOTIF))
4564 "browsefilter",
4565#endif
4566#ifdef FEAT_BYTEOFF
4567 "byte_offset",
4568#endif
4569#ifdef FEAT_JOB_CHANNEL
4570 "channel",
4571#endif
4572#ifdef FEAT_CINDENT
4573 "cindent",
4574#endif
4575#ifdef FEAT_CLIENTSERVER
4576 "clientserver",
4577#endif
4578#ifdef FEAT_CLIPBOARD
4579 "clipboard",
4580#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004581 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004582 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004583#ifdef FEAT_COMMENTS
4584 "comments",
4585#endif
4586#ifdef FEAT_CONCEAL
4587 "conceal",
4588#endif
4589#ifdef FEAT_CRYPT
4590 "cryptv",
4591 "crypt-blowfish",
4592 "crypt-blowfish2",
4593#endif
4594#ifdef FEAT_CSCOPE
4595 "cscope",
4596#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004597 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004598#ifdef CURSOR_SHAPE
4599 "cursorshape",
4600#endif
4601#ifdef DEBUG
4602 "debug",
4603#endif
4604#ifdef FEAT_CON_DIALOG
4605 "dialog_con",
4606#endif
4607#ifdef FEAT_GUI_DIALOG
4608 "dialog_gui",
4609#endif
4610#ifdef FEAT_DIFF
4611 "diff",
4612#endif
4613#ifdef FEAT_DIGRAPHS
4614 "digraphs",
4615#endif
4616#ifdef FEAT_DIRECTX
4617 "directx",
4618#endif
4619#ifdef FEAT_DND
4620 "dnd",
4621#endif
4622#ifdef FEAT_EMACS_TAGS
4623 "emacs_tags",
4624#endif
4625 "eval", /* always present, of course! */
4626 "ex_extra", /* graduated feature */
4627#ifdef FEAT_SEARCH_EXTRA
4628 "extra_search",
4629#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004630#ifdef FEAT_SEARCHPATH
4631 "file_in_path",
4632#endif
4633#ifdef FEAT_FILTERPIPE
4634 "filterpipe",
4635#endif
4636#ifdef FEAT_FIND_ID
4637 "find_in_path",
4638#endif
4639#ifdef FEAT_FLOAT
4640 "float",
4641#endif
4642#ifdef FEAT_FOLDING
4643 "folding",
4644#endif
4645#ifdef FEAT_FOOTER
4646 "footer",
4647#endif
4648#if !defined(USE_SYSTEM) && defined(UNIX)
4649 "fork",
4650#endif
4651#ifdef FEAT_GETTEXT
4652 "gettext",
4653#endif
4654#ifdef FEAT_GUI
4655 "gui",
4656#endif
4657#ifdef FEAT_GUI_ATHENA
4658# ifdef FEAT_GUI_NEXTAW
4659 "gui_neXtaw",
4660# else
4661 "gui_athena",
4662# endif
4663#endif
4664#ifdef FEAT_GUI_GTK
4665 "gui_gtk",
4666# ifdef USE_GTK3
4667 "gui_gtk3",
4668# else
4669 "gui_gtk2",
4670# endif
4671#endif
4672#ifdef FEAT_GUI_GNOME
4673 "gui_gnome",
4674#endif
4675#ifdef FEAT_GUI_MAC
4676 "gui_mac",
4677#endif
4678#ifdef FEAT_GUI_MOTIF
4679 "gui_motif",
4680#endif
4681#ifdef FEAT_GUI_PHOTON
4682 "gui_photon",
4683#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004684#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004685 "gui_win32",
4686#endif
4687#ifdef FEAT_HANGULIN
4688 "hangul_input",
4689#endif
4690#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
4691 "iconv",
4692#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004693 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004694#ifdef FEAT_JOB_CHANNEL
4695 "job",
4696#endif
4697#ifdef FEAT_JUMPLIST
4698 "jumplist",
4699#endif
4700#ifdef FEAT_KEYMAP
4701 "keymap",
4702#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02004703 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004704#ifdef FEAT_LANGMAP
4705 "langmap",
4706#endif
4707#ifdef FEAT_LIBCALL
4708 "libcall",
4709#endif
4710#ifdef FEAT_LINEBREAK
4711 "linebreak",
4712#endif
4713#ifdef FEAT_LISP
4714 "lispindent",
4715#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004716 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004717 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718#ifdef FEAT_LUA
4719# ifndef DYNAMIC_LUA
4720 "lua",
4721# endif
4722#endif
4723#ifdef FEAT_MENU
4724 "menu",
4725#endif
4726#ifdef FEAT_SESSION
4727 "mksession",
4728#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004730#ifdef FEAT_MOUSE
4731 "mouse",
4732#endif
4733#ifdef FEAT_MOUSESHAPE
4734 "mouseshape",
4735#endif
4736#if defined(UNIX) || defined(VMS)
4737# ifdef FEAT_MOUSE_DEC
4738 "mouse_dec",
4739# endif
4740# ifdef FEAT_MOUSE_GPM
4741 "mouse_gpm",
4742# endif
4743# ifdef FEAT_MOUSE_JSB
4744 "mouse_jsbterm",
4745# endif
4746# ifdef FEAT_MOUSE_NET
4747 "mouse_netterm",
4748# endif
4749# ifdef FEAT_MOUSE_PTERM
4750 "mouse_pterm",
4751# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01004752# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004753 "mouse_sgr",
4754# endif
4755# ifdef FEAT_SYSMOUSE
4756 "mouse_sysmouse",
4757# endif
4758# ifdef FEAT_MOUSE_URXVT
4759 "mouse_urxvt",
4760# endif
4761# ifdef FEAT_MOUSE_XTERM
4762 "mouse_xterm",
4763# endif
4764#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004765 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004766#ifdef FEAT_MBYTE_IME
4767 "multi_byte_ime",
4768#endif
4769#ifdef FEAT_MULTI_LANG
4770 "multi_lang",
4771#endif
4772#ifdef FEAT_MZSCHEME
4773#ifndef DYNAMIC_MZSCHEME
4774 "mzscheme",
4775#endif
4776#endif
4777#ifdef FEAT_NUM64
4778 "num64",
4779#endif
4780#ifdef FEAT_OLE
4781 "ole",
4782#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02004783#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004784 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02004785#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004786#ifdef FEAT_PATH_EXTRA
4787 "path_extra",
4788#endif
4789#ifdef FEAT_PERL
4790#ifndef DYNAMIC_PERL
4791 "perl",
4792#endif
4793#endif
4794#ifdef FEAT_PERSISTENT_UNDO
4795 "persistent_undo",
4796#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004797#if defined(FEAT_PYTHON)
4798 "python_compiled",
4799# if defined(DYNAMIC_PYTHON)
4800 "python_dynamic",
4801# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004802 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004803 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004804# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004805#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004806#if defined(FEAT_PYTHON3)
4807 "python3_compiled",
4808# if defined(DYNAMIC_PYTHON3)
4809 "python3_dynamic",
4810# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004811 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004812 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004813# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004814#endif
4815#ifdef FEAT_POSTSCRIPT
4816 "postscript",
4817#endif
4818#ifdef FEAT_PRINTER
4819 "printer",
4820#endif
4821#ifdef FEAT_PROFILE
4822 "profile",
4823#endif
4824#ifdef FEAT_RELTIME
4825 "reltime",
4826#endif
4827#ifdef FEAT_QUICKFIX
4828 "quickfix",
4829#endif
4830#ifdef FEAT_RIGHTLEFT
4831 "rightleft",
4832#endif
4833#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4834 "ruby",
4835#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004836 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004837#ifdef FEAT_CMDL_INFO
4838 "showcmd",
4839 "cmdline_info",
4840#endif
4841#ifdef FEAT_SIGNS
4842 "signs",
4843#endif
4844#ifdef FEAT_SMARTINDENT
4845 "smartindent",
4846#endif
4847#ifdef STARTUPTIME
4848 "startuptime",
4849#endif
4850#ifdef FEAT_STL_OPT
4851 "statusline",
4852#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853#ifdef FEAT_NETBEANS_INTG
4854 "netbeans_intg",
4855#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02004856#ifdef FEAT_SOUND
4857 "sound",
4858#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859#ifdef FEAT_SPELL
4860 "spell",
4861#endif
4862#ifdef FEAT_SYN_HL
4863 "syntax",
4864#endif
4865#if defined(USE_SYSTEM) || !defined(UNIX)
4866 "system",
4867#endif
4868#ifdef FEAT_TAG_BINS
4869 "tag_binary",
4870#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004871#ifdef FEAT_TCL
4872# ifndef DYNAMIC_TCL
4873 "tcl",
4874# endif
4875#endif
4876#ifdef FEAT_TERMGUICOLORS
4877 "termguicolors",
4878#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004879#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02004880 "terminal",
4881#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004882#ifdef TERMINFO
4883 "terminfo",
4884#endif
4885#ifdef FEAT_TERMRESPONSE
4886 "termresponse",
4887#endif
4888#ifdef FEAT_TEXTOBJ
4889 "textobjects",
4890#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01004891#ifdef FEAT_TEXT_PROP
4892 "textprop",
4893#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004894#ifdef HAVE_TGETENT
4895 "tgetent",
4896#endif
4897#ifdef FEAT_TIMERS
4898 "timers",
4899#endif
4900#ifdef FEAT_TITLE
4901 "title",
4902#endif
4903#ifdef FEAT_TOOLBAR
4904 "toolbar",
4905#endif
4906#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4907 "unnamedplus",
4908#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909 "user-commands", /* was accidentally included in 5.4 */
4910 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02004911#ifdef FEAT_VARTABS
4912 "vartabs",
4913#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004914 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915#ifdef FEAT_VIMINFO
4916 "viminfo",
4917#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004918 "vimscript-1",
4919 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02004920 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004921 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004922 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004923 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004924 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01004925#ifdef FEAT_VTP
4926 "vtp",
4927#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004928#ifdef FEAT_WILDIGN
4929 "wildignore",
4930#endif
4931#ifdef FEAT_WILDMENU
4932 "wildmenu",
4933#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004934 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004935#ifdef FEAT_WAK
4936 "winaltkeys",
4937#endif
4938#ifdef FEAT_WRITEBACKUP
4939 "writebackup",
4940#endif
4941#ifdef FEAT_XIM
4942 "xim",
4943#endif
4944#ifdef FEAT_XFONTSET
4945 "xfontset",
4946#endif
4947#ifdef FEAT_XPM_W32
4948 "xpm",
4949 "xpm_w32", /* for backward compatibility */
4950#else
4951# if defined(HAVE_XPM)
4952 "xpm",
4953# endif
4954#endif
4955#ifdef USE_XSMP
4956 "xsmp",
4957#endif
4958#ifdef USE_XSMP_INTERACT
4959 "xsmp_interact",
4960#endif
4961#ifdef FEAT_XCLIPBOARD
4962 "xterm_clipboard",
4963#endif
4964#ifdef FEAT_XTERM_SAVE
4965 "xterm_save",
4966#endif
4967#if defined(UNIX) && defined(FEAT_X11)
4968 "X11",
4969#endif
4970 NULL
4971 };
4972
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004973 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004974 for (i = 0; has_list[i] != NULL; ++i)
4975 if (STRICMP(name, has_list[i]) == 0)
4976 {
4977 n = TRUE;
4978 break;
4979 }
4980
4981 if (n == FALSE)
4982 {
4983 if (STRNICMP(name, "patch", 5) == 0)
4984 {
4985 if (name[5] == '-'
4986 && STRLEN(name) >= 11
4987 && vim_isdigit(name[6])
4988 && vim_isdigit(name[8])
4989 && vim_isdigit(name[10]))
4990 {
4991 int major = atoi((char *)name + 6);
4992 int minor = atoi((char *)name + 8);
4993
4994 /* Expect "patch-9.9.01234". */
4995 n = (major < VIM_VERSION_MAJOR
4996 || (major == VIM_VERSION_MAJOR
4997 && (minor < VIM_VERSION_MINOR
4998 || (minor == VIM_VERSION_MINOR
4999 && has_patch(atoi((char *)name + 10))))));
5000 }
5001 else
5002 n = has_patch(atoi((char *)name + 5));
5003 }
5004 else if (STRICMP(name, "vim_starting") == 0)
5005 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01005006 else if (STRICMP(name, "ttyin") == 0)
5007 n = mch_input_isatty();
5008 else if (STRICMP(name, "ttyout") == 0)
5009 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005010 else if (STRICMP(name, "multi_byte_encoding") == 0)
5011 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005012#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005013 else if (STRICMP(name, "balloon_multiline") == 0)
5014 n = multiline_balloon_available();
5015#endif
5016#ifdef DYNAMIC_TCL
5017 else if (STRICMP(name, "tcl") == 0)
5018 n = tcl_enabled(FALSE);
5019#endif
5020#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5021 else if (STRICMP(name, "iconv") == 0)
5022 n = iconv_enabled(FALSE);
5023#endif
5024#ifdef DYNAMIC_LUA
5025 else if (STRICMP(name, "lua") == 0)
5026 n = lua_enabled(FALSE);
5027#endif
5028#ifdef DYNAMIC_MZSCHEME
5029 else if (STRICMP(name, "mzscheme") == 0)
5030 n = mzscheme_enabled(FALSE);
5031#endif
5032#ifdef DYNAMIC_RUBY
5033 else if (STRICMP(name, "ruby") == 0)
5034 n = ruby_enabled(FALSE);
5035#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005036#ifdef DYNAMIC_PYTHON
5037 else if (STRICMP(name, "python") == 0)
5038 n = python_enabled(FALSE);
5039#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005040#ifdef DYNAMIC_PYTHON3
5041 else if (STRICMP(name, "python3") == 0)
5042 n = python3_enabled(FALSE);
5043#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005044#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5045 else if (STRICMP(name, "pythonx") == 0)
5046 {
5047# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
5048 if (p_pyx == 0)
5049 n = python3_enabled(FALSE) || python_enabled(FALSE);
5050 else if (p_pyx == 3)
5051 n = python3_enabled(FALSE);
5052 else if (p_pyx == 2)
5053 n = python_enabled(FALSE);
5054# elif defined(DYNAMIC_PYTHON)
5055 n = python_enabled(FALSE);
5056# elif defined(DYNAMIC_PYTHON3)
5057 n = python3_enabled(FALSE);
5058# endif
5059 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060#endif
5061#ifdef DYNAMIC_PERL
5062 else if (STRICMP(name, "perl") == 0)
5063 n = perl_enabled(FALSE);
5064#endif
5065#ifdef FEAT_GUI
5066 else if (STRICMP(name, "gui_running") == 0)
5067 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005068# ifdef FEAT_BROWSE
5069 else if (STRICMP(name, "browse") == 0)
5070 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
5071# endif
5072#endif
5073#ifdef FEAT_SYN_HL
5074 else if (STRICMP(name, "syntax_items") == 0)
5075 n = syntax_present(curwin);
5076#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01005077#ifdef FEAT_VTP
5078 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02005079 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005080#endif
5081#ifdef FEAT_NETBEANS_INTG
5082 else if (STRICMP(name, "netbeans_enabled") == 0)
5083 n = netbeans_active();
5084#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02005085#ifdef FEAT_MOUSE_GPM
5086 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
5087 n = gpm_enabled();
5088#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005089#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02005090 else if (STRICMP(name, "terminal") == 0)
5091 n = terminal_enabled();
5092#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005093#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005094 else if (STRICMP(name, "conpty") == 0)
5095 n = use_conpty();
5096#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02005097#ifdef FEAT_CLIPBOARD
5098 else if (STRICMP(name, "clipboard_working") == 0)
5099 n = clip_star.available;
5100#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005101 }
5102
5103 rettv->vval.v_number = n;
5104}
5105
5106/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005107 * "haslocaldir()" function
5108 */
5109 static void
5110f_haslocaldir(typval_T *argvars, typval_T *rettv)
5111{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005112 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005113 win_T *wp = NULL;
5114
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005115 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
5116
5117 // Check for window-local and tab-local directories
5118 if (wp != NULL && wp->w_localdir != NULL)
5119 rettv->vval.v_number = 1;
5120 else if (tp != NULL && tp->tp_localdir != NULL)
5121 rettv->vval.v_number = 2;
5122 else
5123 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005124}
5125
5126/*
5127 * "hasmapto()" function
5128 */
5129 static void
5130f_hasmapto(typval_T *argvars, typval_T *rettv)
5131{
5132 char_u *name;
5133 char_u *mode;
5134 char_u buf[NUMBUFLEN];
5135 int abbr = FALSE;
5136
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005137 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005138 if (argvars[1].v_type == VAR_UNKNOWN)
5139 mode = (char_u *)"nvo";
5140 else
5141 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005142 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005143 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005144 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145 }
5146
5147 if (map_to_exists(name, mode, abbr))
5148 rettv->vval.v_number = TRUE;
5149 else
5150 rettv->vval.v_number = FALSE;
5151}
5152
5153/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005154 * "highlightID(name)" function
5155 */
5156 static void
5157f_hlID(typval_T *argvars, typval_T *rettv)
5158{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005159 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005160}
5161
5162/*
5163 * "highlight_exists()" function
5164 */
5165 static void
5166f_hlexists(typval_T *argvars, typval_T *rettv)
5167{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005168 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005169}
5170
5171/*
5172 * "hostname()" function
5173 */
5174 static void
5175f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
5176{
5177 char_u hostname[256];
5178
5179 mch_get_host_name(hostname, 256);
5180 rettv->v_type = VAR_STRING;
5181 rettv->vval.v_string = vim_strsave(hostname);
5182}
5183
5184/*
5185 * iconv() function
5186 */
5187 static void
5188f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
5189{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005190 char_u buf1[NUMBUFLEN];
5191 char_u buf2[NUMBUFLEN];
5192 char_u *from, *to, *str;
5193 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005194
5195 rettv->v_type = VAR_STRING;
5196 rettv->vval.v_string = NULL;
5197
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005198 str = tv_get_string(&argvars[0]);
5199 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
5200 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005201 vimconv.vc_type = CONV_NONE;
5202 convert_setup(&vimconv, from, to);
5203
5204 /* If the encodings are equal, no conversion needed. */
5205 if (vimconv.vc_type == CONV_NONE)
5206 rettv->vval.v_string = vim_strsave(str);
5207 else
5208 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
5209
5210 convert_setup(&vimconv, NULL, NULL);
5211 vim_free(from);
5212 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005213}
5214
5215/*
5216 * "indent()" function
5217 */
5218 static void
5219f_indent(typval_T *argvars, typval_T *rettv)
5220{
5221 linenr_T lnum;
5222
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005223 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005224 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5225 rettv->vval.v_number = get_indent_lnum(lnum);
5226 else
5227 rettv->vval.v_number = -1;
5228}
5229
5230/*
5231 * "index()" function
5232 */
5233 static void
5234f_index(typval_T *argvars, typval_T *rettv)
5235{
5236 list_T *l;
5237 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005238 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005239 long idx = 0;
5240 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005241 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005242
5243 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005244 if (argvars[0].v_type == VAR_BLOB)
5245 {
5246 typval_T tv;
5247 int start = 0;
5248
5249 if (argvars[2].v_type != VAR_UNKNOWN)
5250 {
5251 start = tv_get_number_chk(&argvars[2], &error);
5252 if (error)
5253 return;
5254 }
5255 b = argvars[0].vval.v_blob;
5256 if (b == NULL)
5257 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01005258 if (start < 0)
5259 {
5260 start = blob_len(b) + start;
5261 if (start < 0)
5262 start = 0;
5263 }
5264
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005265 for (idx = start; idx < blob_len(b); ++idx)
5266 {
5267 tv.v_type = VAR_NUMBER;
5268 tv.vval.v_number = blob_get(b, idx);
5269 if (tv_equal(&tv, &argvars[1], ic, FALSE))
5270 {
5271 rettv->vval.v_number = idx;
5272 return;
5273 }
5274 }
5275 return;
5276 }
5277 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005278 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01005279 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005280 return;
5281 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005282
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005283 l = argvars[0].vval.v_list;
5284 if (l != NULL)
5285 {
5286 item = l->lv_first;
5287 if (argvars[2].v_type != VAR_UNKNOWN)
5288 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005289 /* Start at specified item. Use the cached index that list_find()
5290 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005291 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 idx = l->lv_idx;
5293 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005294 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005295 if (error)
5296 item = NULL;
5297 }
5298
5299 for ( ; item != NULL; item = item->li_next, ++idx)
5300 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
5301 {
5302 rettv->vval.v_number = idx;
5303 break;
5304 }
5305 }
5306}
5307
5308static int inputsecret_flag = 0;
5309
5310/*
5311 * "input()" function
5312 * Also handles inputsecret() when inputsecret is set.
5313 */
5314 static void
5315f_input(typval_T *argvars, typval_T *rettv)
5316{
5317 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
5318}
5319
5320/*
5321 * "inputdialog()" function
5322 */
5323 static void
5324f_inputdialog(typval_T *argvars, typval_T *rettv)
5325{
5326#if defined(FEAT_GUI_TEXTDIALOG)
5327 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
5328 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5329 {
5330 char_u *message;
5331 char_u buf[NUMBUFLEN];
5332 char_u *defstr = (char_u *)"";
5333
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005334 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005335 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005336 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005337 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5338 else
5339 IObuff[0] = NUL;
5340 if (message != NULL && defstr != NULL
5341 && do_dialog(VIM_QUESTION, NULL, message,
5342 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5343 rettv->vval.v_string = vim_strsave(IObuff);
5344 else
5345 {
5346 if (message != NULL && defstr != NULL
5347 && argvars[1].v_type != VAR_UNKNOWN
5348 && argvars[2].v_type != VAR_UNKNOWN)
5349 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005350 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005351 else
5352 rettv->vval.v_string = NULL;
5353 }
5354 rettv->v_type = VAR_STRING;
5355 }
5356 else
5357#endif
5358 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5359}
5360
5361/*
5362 * "inputlist()" function
5363 */
5364 static void
5365f_inputlist(typval_T *argvars, typval_T *rettv)
5366{
5367 listitem_T *li;
5368 int selected;
5369 int mouse_used;
5370
5371#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02005372 /* While starting up, there is no place to enter text. When running tests
5373 * with --not-a-term we assume feedkeys() will be used. */
5374 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005375 return;
5376#endif
5377 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5378 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005379 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005380 return;
5381 }
5382
5383 msg_start();
5384 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
5385 lines_left = Rows; /* avoid more prompt */
5386 msg_scroll = TRUE;
5387 msg_clr_eos();
5388
5389 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
5390 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005391 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005392 msg_putchar('\n');
5393 }
5394
5395 /* Ask for choice. */
5396 selected = prompt_for_number(&mouse_used);
5397 if (mouse_used)
5398 selected -= lines_left;
5399
5400 rettv->vval.v_number = selected;
5401}
5402
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005403static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5404
5405/*
5406 * "inputrestore()" function
5407 */
5408 static void
5409f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5410{
5411 if (ga_userinput.ga_len > 0)
5412 {
5413 --ga_userinput.ga_len;
5414 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5415 + ga_userinput.ga_len);
5416 /* default return is zero == OK */
5417 }
5418 else if (p_verbose > 1)
5419 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005420 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005421 rettv->vval.v_number = 1; /* Failed */
5422 }
5423}
5424
5425/*
5426 * "inputsave()" function
5427 */
5428 static void
5429f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
5430{
5431 /* Add an entry to the stack of typeahead storage. */
5432 if (ga_grow(&ga_userinput, 1) == OK)
5433 {
5434 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5435 + ga_userinput.ga_len);
5436 ++ga_userinput.ga_len;
5437 /* default return is zero == OK */
5438 }
5439 else
5440 rettv->vval.v_number = 1; /* Failed */
5441}
5442
5443/*
5444 * "inputsecret()" function
5445 */
5446 static void
5447f_inputsecret(typval_T *argvars, typval_T *rettv)
5448{
5449 ++cmdline_star;
5450 ++inputsecret_flag;
5451 f_input(argvars, rettv);
5452 --cmdline_star;
5453 --inputsecret_flag;
5454}
5455
5456/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005457 * "invert(expr)" function
5458 */
5459 static void
5460f_invert(typval_T *argvars, typval_T *rettv)
5461{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005462 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005463}
5464
5465/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005466 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
5467 * or it refers to a List or Dictionary that is locked.
5468 */
5469 static int
5470tv_islocked(typval_T *tv)
5471{
5472 return (tv->v_lock & VAR_LOCKED)
5473 || (tv->v_type == VAR_LIST
5474 && tv->vval.v_list != NULL
5475 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
5476 || (tv->v_type == VAR_DICT
5477 && tv->vval.v_dict != NULL
5478 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
5479}
5480
5481/*
5482 * "islocked()" function
5483 */
5484 static void
5485f_islocked(typval_T *argvars, typval_T *rettv)
5486{
5487 lval_T lv;
5488 char_u *end;
5489 dictitem_T *di;
5490
5491 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005492 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005493 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005494 if (end != NULL && lv.ll_name != NULL)
5495 {
5496 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005497 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005498 else
5499 {
5500 if (lv.ll_tv == NULL)
5501 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005502 di = find_var(lv.ll_name, NULL, TRUE);
5503 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005504 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005505 /* Consider a variable locked when:
5506 * 1. the variable itself is locked
5507 * 2. the value of the variable is locked.
5508 * 3. the List or Dict value is locked.
5509 */
5510 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5511 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005512 }
5513 }
5514 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005515 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005516 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005517 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005518 else if (lv.ll_list != NULL)
5519 /* List item. */
5520 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5521 else
5522 /* Dictionary item. */
5523 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5524 }
5525 }
5526
5527 clear_lval(&lv);
5528}
5529
5530#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5531/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005532 * "isinf()" function
5533 */
5534 static void
5535f_isinf(typval_T *argvars, typval_T *rettv)
5536{
5537 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5538 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5539}
5540
5541/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005542 * "isnan()" function
5543 */
5544 static void
5545f_isnan(typval_T *argvars, typval_T *rettv)
5546{
5547 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5548 && isnan(argvars[0].vval.v_float);
5549}
5550#endif
5551
5552/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005553 * "last_buffer_nr()" function.
5554 */
5555 static void
5556f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5557{
5558 int n = 0;
5559 buf_T *buf;
5560
Bram Moolenaar29323592016-07-24 22:04:11 +02005561 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005562 if (n < buf->b_fnum)
5563 n = buf->b_fnum;
5564
5565 rettv->vval.v_number = n;
5566}
5567
5568/*
5569 * "len()" function
5570 */
5571 static void
5572f_len(typval_T *argvars, typval_T *rettv)
5573{
5574 switch (argvars[0].v_type)
5575 {
5576 case VAR_STRING:
5577 case VAR_NUMBER:
5578 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005579 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005580 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005581 case VAR_BLOB:
5582 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5583 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005584 case VAR_LIST:
5585 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5586 break;
5587 case VAR_DICT:
5588 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5589 break;
5590 case VAR_UNKNOWN:
5591 case VAR_SPECIAL:
5592 case VAR_FLOAT:
5593 case VAR_FUNC:
5594 case VAR_PARTIAL:
5595 case VAR_JOB:
5596 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005597 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005598 break;
5599 }
5600}
5601
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005602 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005603libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604{
5605#ifdef FEAT_LIBCALL
5606 char_u *string_in;
5607 char_u **string_result;
5608 int nr_result;
5609#endif
5610
5611 rettv->v_type = type;
5612 if (type != VAR_NUMBER)
5613 rettv->vval.v_string = NULL;
5614
5615 if (check_restricted() || check_secure())
5616 return;
5617
5618#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02005619 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005620 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5621 {
5622 string_in = NULL;
5623 if (argvars[2].v_type == VAR_STRING)
5624 string_in = argvars[2].vval.v_string;
5625 if (type == VAR_NUMBER)
5626 string_result = NULL;
5627 else
5628 string_result = &rettv->vval.v_string;
5629 if (mch_libcall(argvars[0].vval.v_string,
5630 argvars[1].vval.v_string,
5631 string_in,
5632 argvars[2].vval.v_number,
5633 string_result,
5634 &nr_result) == OK
5635 && type == VAR_NUMBER)
5636 rettv->vval.v_number = nr_result;
5637 }
5638#endif
5639}
5640
5641/*
5642 * "libcall()" function
5643 */
5644 static void
5645f_libcall(typval_T *argvars, typval_T *rettv)
5646{
5647 libcall_common(argvars, rettv, VAR_STRING);
5648}
5649
5650/*
5651 * "libcallnr()" function
5652 */
5653 static void
5654f_libcallnr(typval_T *argvars, typval_T *rettv)
5655{
5656 libcall_common(argvars, rettv, VAR_NUMBER);
5657}
5658
5659/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005660 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005661 */
5662 static void
5663f_line(typval_T *argvars, typval_T *rettv)
5664{
5665 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005666 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005667 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005668 int id;
5669 tabpage_T *tp;
5670 win_T *wp;
5671 win_T *save_curwin;
5672 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005673
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005674 if (argvars[1].v_type != VAR_UNKNOWN)
5675 {
5676 // use window specified in the second argument
5677 id = (int)tv_get_number(&argvars[1]);
5678 wp = win_id2wp_tp(id, &tp);
5679 if (wp != NULL && tp != NULL)
5680 {
5681 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5682 == OK)
5683 {
5684 check_cursor();
5685 fp = var2fpos(&argvars[0], TRUE, &fnum);
5686 }
5687 restore_win_noblock(save_curwin, save_curtab, TRUE);
5688 }
5689 }
5690 else
5691 // use current window
5692 fp = var2fpos(&argvars[0], TRUE, &fnum);
5693
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005694 if (fp != NULL)
5695 lnum = fp->lnum;
5696 rettv->vval.v_number = lnum;
5697}
5698
5699/*
5700 * "line2byte(lnum)" function
5701 */
5702 static void
5703f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5704{
5705#ifndef FEAT_BYTEOFF
5706 rettv->vval.v_number = -1;
5707#else
5708 linenr_T lnum;
5709
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005710 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005711 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5712 rettv->vval.v_number = -1;
5713 else
5714 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5715 if (rettv->vval.v_number >= 0)
5716 ++rettv->vval.v_number;
5717#endif
5718}
5719
5720/*
5721 * "lispindent(lnum)" function
5722 */
5723 static void
5724f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
5725{
5726#ifdef FEAT_LISP
5727 pos_T pos;
5728 linenr_T lnum;
5729
5730 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005731 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005732 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5733 {
5734 curwin->w_cursor.lnum = lnum;
5735 rettv->vval.v_number = get_lisp_indent();
5736 curwin->w_cursor = pos;
5737 }
5738 else
5739#endif
5740 rettv->vval.v_number = -1;
5741}
5742
5743/*
5744 * "localtime()" function
5745 */
5746 static void
5747f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
5748{
5749 rettv->vval.v_number = (varnumber_T)time(NULL);
5750}
5751
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005752#ifdef FEAT_FLOAT
5753/*
5754 * "log()" function
5755 */
5756 static void
5757f_log(typval_T *argvars, typval_T *rettv)
5758{
5759 float_T f = 0.0;
5760
5761 rettv->v_type = VAR_FLOAT;
5762 if (get_float_arg(argvars, &f) == OK)
5763 rettv->vval.v_float = log(f);
5764 else
5765 rettv->vval.v_float = 0.0;
5766}
5767
5768/*
5769 * "log10()" function
5770 */
5771 static void
5772f_log10(typval_T *argvars, typval_T *rettv)
5773{
5774 float_T f = 0.0;
5775
5776 rettv->v_type = VAR_FLOAT;
5777 if (get_float_arg(argvars, &f) == OK)
5778 rettv->vval.v_float = log10(f);
5779 else
5780 rettv->vval.v_float = 0.0;
5781}
5782#endif
5783
5784#ifdef FEAT_LUA
5785/*
5786 * "luaeval()" function
5787 */
5788 static void
5789f_luaeval(typval_T *argvars, typval_T *rettv)
5790{
5791 char_u *str;
5792 char_u buf[NUMBUFLEN];
5793
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005794 if (check_restricted() || check_secure())
5795 return;
5796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005797 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005798 do_luaeval(str, argvars + 1, rettv);
5799}
5800#endif
5801
5802/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005803 * "maparg()" function
5804 */
5805 static void
5806f_maparg(typval_T *argvars, typval_T *rettv)
5807{
5808 get_maparg(argvars, rettv, TRUE);
5809}
5810
5811/*
5812 * "mapcheck()" function
5813 */
5814 static void
5815f_mapcheck(typval_T *argvars, typval_T *rettv)
5816{
5817 get_maparg(argvars, rettv, FALSE);
5818}
5819
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005820typedef enum
5821{
5822 MATCH_END, /* matchend() */
5823 MATCH_MATCH, /* match() */
5824 MATCH_STR, /* matchstr() */
5825 MATCH_LIST, /* matchlist() */
5826 MATCH_POS /* matchstrpos() */
5827} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005828
5829 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005830find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005831{
5832 char_u *str = NULL;
5833 long len = 0;
5834 char_u *expr = NULL;
5835 char_u *pat;
5836 regmatch_T regmatch;
5837 char_u patbuf[NUMBUFLEN];
5838 char_u strbuf[NUMBUFLEN];
5839 char_u *save_cpo;
5840 long start = 0;
5841 long nth = 1;
5842 colnr_T startcol = 0;
5843 int match = 0;
5844 list_T *l = NULL;
5845 listitem_T *li = NULL;
5846 long idx = 0;
5847 char_u *tofree = NULL;
5848
5849 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
5850 save_cpo = p_cpo;
5851 p_cpo = (char_u *)"";
5852
5853 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005854 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005855 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005856 /* type MATCH_LIST: return empty list when there are no matches.
5857 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005858 if (rettv_list_alloc(rettv) == FAIL)
5859 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005860 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005861 && (list_append_string(rettv->vval.v_list,
5862 (char_u *)"", 0) == FAIL
5863 || list_append_number(rettv->vval.v_list,
5864 (varnumber_T)-1) == FAIL
5865 || list_append_number(rettv->vval.v_list,
5866 (varnumber_T)-1) == FAIL
5867 || list_append_number(rettv->vval.v_list,
5868 (varnumber_T)-1) == FAIL))
5869 {
5870 list_free(rettv->vval.v_list);
5871 rettv->vval.v_list = NULL;
5872 goto theend;
5873 }
5874 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005875 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005876 {
5877 rettv->v_type = VAR_STRING;
5878 rettv->vval.v_string = NULL;
5879 }
5880
5881 if (argvars[0].v_type == VAR_LIST)
5882 {
5883 if ((l = argvars[0].vval.v_list) == NULL)
5884 goto theend;
5885 li = l->lv_first;
5886 }
5887 else
5888 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005889 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005890 len = (long)STRLEN(str);
5891 }
5892
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005893 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005894 if (pat == NULL)
5895 goto theend;
5896
5897 if (argvars[2].v_type != VAR_UNKNOWN)
5898 {
5899 int error = FALSE;
5900
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005901 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005902 if (error)
5903 goto theend;
5904 if (l != NULL)
5905 {
5906 li = list_find(l, start);
5907 if (li == NULL)
5908 goto theend;
5909 idx = l->lv_idx; /* use the cached index */
5910 }
5911 else
5912 {
5913 if (start < 0)
5914 start = 0;
5915 if (start > len)
5916 goto theend;
5917 /* When "count" argument is there ignore matches before "start",
5918 * otherwise skip part of the string. Differs when pattern is "^"
5919 * or "\<". */
5920 if (argvars[3].v_type != VAR_UNKNOWN)
5921 startcol = start;
5922 else
5923 {
5924 str += start;
5925 len -= start;
5926 }
5927 }
5928
5929 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005930 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005931 if (error)
5932 goto theend;
5933 }
5934
5935 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5936 if (regmatch.regprog != NULL)
5937 {
5938 regmatch.rm_ic = p_ic;
5939
5940 for (;;)
5941 {
5942 if (l != NULL)
5943 {
5944 if (li == NULL)
5945 {
5946 match = FALSE;
5947 break;
5948 }
5949 vim_free(tofree);
5950 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5951 if (str == NULL)
5952 break;
5953 }
5954
5955 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5956
5957 if (match && --nth <= 0)
5958 break;
5959 if (l == NULL && !match)
5960 break;
5961
5962 /* Advance to just after the match. */
5963 if (l != NULL)
5964 {
5965 li = li->li_next;
5966 ++idx;
5967 }
5968 else
5969 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005970 startcol = (colnr_T)(regmatch.startp[0]
5971 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972 if (startcol > (colnr_T)len
5973 || str + startcol <= regmatch.startp[0])
5974 {
5975 match = FALSE;
5976 break;
5977 }
5978 }
5979 }
5980
5981 if (match)
5982 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005983 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005984 {
5985 listitem_T *li1 = rettv->vval.v_list->lv_first;
5986 listitem_T *li2 = li1->li_next;
5987 listitem_T *li3 = li2->li_next;
5988 listitem_T *li4 = li3->li_next;
5989
5990 vim_free(li1->li_tv.vval.v_string);
5991 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
5992 (int)(regmatch.endp[0] - regmatch.startp[0]));
5993 li3->li_tv.vval.v_number =
5994 (varnumber_T)(regmatch.startp[0] - expr);
5995 li4->li_tv.vval.v_number =
5996 (varnumber_T)(regmatch.endp[0] - expr);
5997 if (l != NULL)
5998 li2->li_tv.vval.v_number = (varnumber_T)idx;
5999 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006000 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006001 {
6002 int i;
6003
6004 /* return list with matched string and submatches */
6005 for (i = 0; i < NSUBEXP; ++i)
6006 {
6007 if (regmatch.endp[i] == NULL)
6008 {
6009 if (list_append_string(rettv->vval.v_list,
6010 (char_u *)"", 0) == FAIL)
6011 break;
6012 }
6013 else if (list_append_string(rettv->vval.v_list,
6014 regmatch.startp[i],
6015 (int)(regmatch.endp[i] - regmatch.startp[i]))
6016 == FAIL)
6017 break;
6018 }
6019 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006020 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006021 {
6022 /* return matched string */
6023 if (l != NULL)
6024 copy_tv(&li->li_tv, rettv);
6025 else
6026 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
6027 (int)(regmatch.endp[0] - regmatch.startp[0]));
6028 }
6029 else if (l != NULL)
6030 rettv->vval.v_number = idx;
6031 else
6032 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006033 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006034 rettv->vval.v_number =
6035 (varnumber_T)(regmatch.startp[0] - str);
6036 else
6037 rettv->vval.v_number =
6038 (varnumber_T)(regmatch.endp[0] - str);
6039 rettv->vval.v_number += (varnumber_T)(str - expr);
6040 }
6041 }
6042 vim_regfree(regmatch.regprog);
6043 }
6044
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006045theend:
6046 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006047 /* matchstrpos() without a list: drop the second item. */
6048 listitem_remove(rettv->vval.v_list,
6049 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006050 vim_free(tofree);
6051 p_cpo = save_cpo;
6052}
6053
6054/*
6055 * "match()" function
6056 */
6057 static void
6058f_match(typval_T *argvars, typval_T *rettv)
6059{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006060 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006061}
6062
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063/*
6064 * "matchend()" function
6065 */
6066 static void
6067f_matchend(typval_T *argvars, typval_T *rettv)
6068{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006069 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006070}
6071
6072/*
6073 * "matchlist()" function
6074 */
6075 static void
6076f_matchlist(typval_T *argvars, typval_T *rettv)
6077{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006078 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006079}
6080
6081/*
6082 * "matchstr()" function
6083 */
6084 static void
6085f_matchstr(typval_T *argvars, typval_T *rettv)
6086{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006087 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006088}
6089
6090/*
6091 * "matchstrpos()" function
6092 */
6093 static void
6094f_matchstrpos(typval_T *argvars, typval_T *rettv)
6095{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006096 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006097}
6098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006099 static void
6100max_min(typval_T *argvars, typval_T *rettv, int domax)
6101{
6102 varnumber_T n = 0;
6103 varnumber_T i;
6104 int error = FALSE;
6105
6106 if (argvars[0].v_type == VAR_LIST)
6107 {
6108 list_T *l;
6109 listitem_T *li;
6110
6111 l = argvars[0].vval.v_list;
6112 if (l != NULL)
6113 {
6114 li = l->lv_first;
6115 if (li != NULL)
6116 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006117 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006118 for (;;)
6119 {
6120 li = li->li_next;
6121 if (li == NULL)
6122 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006123 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006124 if (domax ? i > n : i < n)
6125 n = i;
6126 }
6127 }
6128 }
6129 }
6130 else if (argvars[0].v_type == VAR_DICT)
6131 {
6132 dict_T *d;
6133 int first = TRUE;
6134 hashitem_T *hi;
6135 int todo;
6136
6137 d = argvars[0].vval.v_dict;
6138 if (d != NULL)
6139 {
6140 todo = (int)d->dv_hashtab.ht_used;
6141 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
6142 {
6143 if (!HASHITEM_EMPTY(hi))
6144 {
6145 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006146 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006147 if (first)
6148 {
6149 n = i;
6150 first = FALSE;
6151 }
6152 else if (domax ? i > n : i < n)
6153 n = i;
6154 }
6155 }
6156 }
6157 }
6158 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006159 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006160 rettv->vval.v_number = error ? 0 : n;
6161}
6162
6163/*
6164 * "max()" function
6165 */
6166 static void
6167f_max(typval_T *argvars, typval_T *rettv)
6168{
6169 max_min(argvars, rettv, TRUE);
6170}
6171
6172/*
6173 * "min()" function
6174 */
6175 static void
6176f_min(typval_T *argvars, typval_T *rettv)
6177{
6178 max_min(argvars, rettv, FALSE);
6179}
6180
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006181/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006182 * "mode()" function
6183 */
6184 static void
6185f_mode(typval_T *argvars, typval_T *rettv)
6186{
Bram Moolenaar612cc382018-07-29 15:34:26 +02006187 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188
Bram Moolenaar612cc382018-07-29 15:34:26 +02006189 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190
6191 if (time_for_testing == 93784)
6192 {
6193 /* Testing the two-character code. */
6194 buf[0] = 'x';
6195 buf[1] = '!';
6196 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02006197#ifdef FEAT_TERMINAL
6198 else if (term_use_loop())
6199 buf[0] = 't';
6200#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006201 else if (VIsual_active)
6202 {
6203 if (VIsual_select)
6204 buf[0] = VIsual_mode + 's' - 'v';
6205 else
6206 buf[0] = VIsual_mode;
6207 }
6208 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
6209 || State == CONFIRM)
6210 {
6211 buf[0] = 'r';
6212 if (State == ASKMORE)
6213 buf[1] = 'm';
6214 else if (State == CONFIRM)
6215 buf[1] = '?';
6216 }
6217 else if (State == EXTERNCMD)
6218 buf[0] = '!';
6219 else if (State & INSERT)
6220 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006221 if (State & VREPLACE_FLAG)
6222 {
6223 buf[0] = 'R';
6224 buf[1] = 'v';
6225 }
6226 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01006227 {
6228 if (State & REPLACE_FLAG)
6229 buf[0] = 'R';
6230 else
6231 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006232 if (ins_compl_active())
6233 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01006234 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01006235 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006236 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006237 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01006238 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006239 {
6240 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006241 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006242 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006243 else if (exmode_active == EXMODE_NORMAL)
6244 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006245 }
6246 else
6247 {
6248 buf[0] = 'n';
6249 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01006250 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006251 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01006252 // to be able to detect force-linewise/blockwise/characterwise operations
6253 buf[2] = motion_force;
6254 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02006255 else if (restart_edit == 'I' || restart_edit == 'R'
6256 || restart_edit == 'V')
6257 {
6258 buf[1] = 'i';
6259 buf[2] = restart_edit;
6260 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006261 }
6262
6263 /* Clear out the minor mode when the argument is not a non-zero number or
6264 * non-empty string. */
6265 if (!non_zero_arg(&argvars[0]))
6266 buf[1] = NUL;
6267
6268 rettv->vval.v_string = vim_strsave(buf);
6269 rettv->v_type = VAR_STRING;
6270}
6271
6272#if defined(FEAT_MZSCHEME) || defined(PROTO)
6273/*
6274 * "mzeval()" function
6275 */
6276 static void
6277f_mzeval(typval_T *argvars, typval_T *rettv)
6278{
6279 char_u *str;
6280 char_u buf[NUMBUFLEN];
6281
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006282 if (check_restricted() || check_secure())
6283 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006284 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006285 do_mzeval(str, rettv);
6286}
6287
6288 void
6289mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
6290{
6291 typval_T argvars[3];
6292
6293 argvars[0].v_type = VAR_STRING;
6294 argvars[0].vval.v_string = name;
6295 copy_tv(args, &argvars[1]);
6296 argvars[2].v_type = VAR_UNKNOWN;
6297 f_call(argvars, rettv);
6298 clear_tv(&argvars[1]);
6299}
6300#endif
6301
6302/*
6303 * "nextnonblank()" function
6304 */
6305 static void
6306f_nextnonblank(typval_T *argvars, typval_T *rettv)
6307{
6308 linenr_T lnum;
6309
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006310 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006311 {
6312 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
6313 {
6314 lnum = 0;
6315 break;
6316 }
6317 if (*skipwhite(ml_get(lnum)) != NUL)
6318 break;
6319 }
6320 rettv->vval.v_number = lnum;
6321}
6322
6323/*
6324 * "nr2char()" function
6325 */
6326 static void
6327f_nr2char(typval_T *argvars, typval_T *rettv)
6328{
6329 char_u buf[NUMBUFLEN];
6330
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006331 if (has_mbyte)
6332 {
6333 int utf8 = 0;
6334
6335 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006336 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006337 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01006338 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006339 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006340 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341 }
6342 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006344 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345 buf[1] = NUL;
6346 }
6347 rettv->v_type = VAR_STRING;
6348 rettv->vval.v_string = vim_strsave(buf);
6349}
6350
6351/*
6352 * "or(expr, expr)" function
6353 */
6354 static void
6355f_or(typval_T *argvars, typval_T *rettv)
6356{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006357 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
6358 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006359}
6360
6361/*
6362 * "pathshorten()" function
6363 */
6364 static void
6365f_pathshorten(typval_T *argvars, typval_T *rettv)
6366{
6367 char_u *p;
6368
6369 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006370 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006371 if (p == NULL)
6372 rettv->vval.v_string = NULL;
6373 else
6374 {
6375 p = vim_strsave(p);
6376 rettv->vval.v_string = p;
6377 if (p != NULL)
6378 shorten_dir(p);
6379 }
6380}
6381
6382#ifdef FEAT_PERL
6383/*
6384 * "perleval()" function
6385 */
6386 static void
6387f_perleval(typval_T *argvars, typval_T *rettv)
6388{
6389 char_u *str;
6390 char_u buf[NUMBUFLEN];
6391
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006392 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006393 do_perleval(str, rettv);
6394}
6395#endif
6396
6397#ifdef FEAT_FLOAT
6398/*
6399 * "pow()" function
6400 */
6401 static void
6402f_pow(typval_T *argvars, typval_T *rettv)
6403{
6404 float_T fx = 0.0, fy = 0.0;
6405
6406 rettv->v_type = VAR_FLOAT;
6407 if (get_float_arg(argvars, &fx) == OK
6408 && get_float_arg(&argvars[1], &fy) == OK)
6409 rettv->vval.v_float = pow(fx, fy);
6410 else
6411 rettv->vval.v_float = 0.0;
6412}
6413#endif
6414
6415/*
6416 * "prevnonblank()" function
6417 */
6418 static void
6419f_prevnonblank(typval_T *argvars, typval_T *rettv)
6420{
6421 linenr_T lnum;
6422
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006423 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006424 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
6425 lnum = 0;
6426 else
6427 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
6428 --lnum;
6429 rettv->vval.v_number = lnum;
6430}
6431
6432/* This dummy va_list is here because:
6433 * - passing a NULL pointer doesn't work when va_list isn't a pointer
6434 * - locally in the function results in a "used before set" warning
6435 * - using va_start() to initialize it gives "function with fixed args" error */
6436static va_list ap;
6437
6438/*
6439 * "printf()" function
6440 */
6441 static void
6442f_printf(typval_T *argvars, typval_T *rettv)
6443{
6444 char_u buf[NUMBUFLEN];
6445 int len;
6446 char_u *s;
6447 int saved_did_emsg = did_emsg;
6448 char *fmt;
6449
6450 rettv->v_type = VAR_STRING;
6451 rettv->vval.v_string = NULL;
6452
6453 /* Get the required length, allocate the buffer and do it for real. */
6454 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006455 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006456 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006457 if (!did_emsg)
6458 {
6459 s = alloc(len + 1);
6460 if (s != NULL)
6461 {
6462 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006463 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
6464 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006465 }
6466 }
6467 did_emsg |= saved_did_emsg;
6468}
6469
6470/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006471 * "pum_getpos()" function
6472 */
6473 static void
6474f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6475{
6476 if (rettv_dict_alloc(rettv) != OK)
6477 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006478 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006479}
6480
6481/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006482 * "pumvisible()" function
6483 */
6484 static void
6485f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6486{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006487 if (pum_visible())
6488 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489}
6490
6491#ifdef FEAT_PYTHON3
6492/*
6493 * "py3eval()" function
6494 */
6495 static void
6496f_py3eval(typval_T *argvars, typval_T *rettv)
6497{
6498 char_u *str;
6499 char_u buf[NUMBUFLEN];
6500
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006501 if (check_restricted() || check_secure())
6502 return;
6503
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006504 if (p_pyx == 0)
6505 p_pyx = 3;
6506
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006507 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508 do_py3eval(str, rettv);
6509}
6510#endif
6511
6512#ifdef FEAT_PYTHON
6513/*
6514 * "pyeval()" function
6515 */
6516 static void
6517f_pyeval(typval_T *argvars, typval_T *rettv)
6518{
6519 char_u *str;
6520 char_u buf[NUMBUFLEN];
6521
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006522 if (check_restricted() || check_secure())
6523 return;
6524
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006525 if (p_pyx == 0)
6526 p_pyx = 2;
6527
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006528 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006529 do_pyeval(str, rettv);
6530}
6531#endif
6532
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006533#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
6534/*
6535 * "pyxeval()" function
6536 */
6537 static void
6538f_pyxeval(typval_T *argvars, typval_T *rettv)
6539{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006540 if (check_restricted() || check_secure())
6541 return;
6542
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006543# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
6544 init_pyxversion();
6545 if (p_pyx == 2)
6546 f_pyeval(argvars, rettv);
6547 else
6548 f_py3eval(argvars, rettv);
6549# elif defined(FEAT_PYTHON)
6550 f_pyeval(argvars, rettv);
6551# elif defined(FEAT_PYTHON3)
6552 f_py3eval(argvars, rettv);
6553# endif
6554}
6555#endif
6556
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006557/*
6558 * "range()" function
6559 */
6560 static void
6561f_range(typval_T *argvars, typval_T *rettv)
6562{
6563 varnumber_T start;
6564 varnumber_T end;
6565 varnumber_T stride = 1;
6566 varnumber_T i;
6567 int error = FALSE;
6568
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006569 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 if (argvars[1].v_type == VAR_UNKNOWN)
6571 {
6572 end = start - 1;
6573 start = 0;
6574 }
6575 else
6576 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006577 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006578 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006579 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006580 }
6581
6582 if (error)
6583 return; /* type error; errmsg already given */
6584 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006585 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006586 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006587 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 else
6589 {
6590 if (rettv_list_alloc(rettv) == OK)
6591 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6592 if (list_append_number(rettv->vval.v_list,
6593 (varnumber_T)i) == FAIL)
6594 break;
6595 }
6596}
6597
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006598 static void
6599return_register(int regname, typval_T *rettv)
6600{
6601 char_u buf[2] = {0, 0};
6602
6603 buf[0] = (char_u)regname;
6604 rettv->v_type = VAR_STRING;
6605 rettv->vval.v_string = vim_strsave(buf);
6606}
6607
6608/*
6609 * "reg_executing()" function
6610 */
6611 static void
6612f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6613{
6614 return_register(reg_executing, rettv);
6615}
6616
6617/*
6618 * "reg_recording()" function
6619 */
6620 static void
6621f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6622{
6623 return_register(reg_recording, rettv);
6624}
6625
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006626#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006627/*
6628 * Convert a List to proftime_T.
6629 * Return FAIL when there is something wrong.
6630 */
6631 static int
6632list2proftime(typval_T *arg, proftime_T *tm)
6633{
6634 long n1, n2;
6635 int error = FALSE;
6636
6637 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
6638 || arg->vval.v_list->lv_len != 2)
6639 return FAIL;
6640 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
6641 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01006642# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006643 tm->HighPart = n1;
6644 tm->LowPart = n2;
6645# else
6646 tm->tv_sec = n1;
6647 tm->tv_usec = n2;
6648# endif
6649 return error ? FAIL : OK;
6650}
6651#endif /* FEAT_RELTIME */
6652
6653/*
6654 * "reltime()" function
6655 */
6656 static void
6657f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6658{
6659#ifdef FEAT_RELTIME
6660 proftime_T res;
6661 proftime_T start;
6662
6663 if (argvars[0].v_type == VAR_UNKNOWN)
6664 {
6665 /* No arguments: get current time. */
6666 profile_start(&res);
6667 }
6668 else if (argvars[1].v_type == VAR_UNKNOWN)
6669 {
6670 if (list2proftime(&argvars[0], &res) == FAIL)
6671 return;
6672 profile_end(&res);
6673 }
6674 else
6675 {
6676 /* Two arguments: compute the difference. */
6677 if (list2proftime(&argvars[0], &start) == FAIL
6678 || list2proftime(&argvars[1], &res) == FAIL)
6679 return;
6680 profile_sub(&res, &start);
6681 }
6682
6683 if (rettv_list_alloc(rettv) == OK)
6684 {
6685 long n1, n2;
6686
Bram Moolenaar4f974752019-02-17 17:44:42 +01006687# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006688 n1 = res.HighPart;
6689 n2 = res.LowPart;
6690# else
6691 n1 = res.tv_sec;
6692 n2 = res.tv_usec;
6693# endif
6694 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
6695 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
6696 }
6697#endif
6698}
6699
6700#ifdef FEAT_FLOAT
6701/*
6702 * "reltimefloat()" function
6703 */
6704 static void
6705f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
6706{
6707# ifdef FEAT_RELTIME
6708 proftime_T tm;
6709# endif
6710
6711 rettv->v_type = VAR_FLOAT;
6712 rettv->vval.v_float = 0;
6713# ifdef FEAT_RELTIME
6714 if (list2proftime(&argvars[0], &tm) == OK)
6715 rettv->vval.v_float = profile_float(&tm);
6716# endif
6717}
6718#endif
6719
6720/*
6721 * "reltimestr()" function
6722 */
6723 static void
6724f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
6725{
6726#ifdef FEAT_RELTIME
6727 proftime_T tm;
6728#endif
6729
6730 rettv->v_type = VAR_STRING;
6731 rettv->vval.v_string = NULL;
6732#ifdef FEAT_RELTIME
6733 if (list2proftime(&argvars[0], &tm) == OK)
6734 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
6735#endif
6736}
6737
6738#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006739 static void
6740make_connection(void)
6741{
6742 if (X_DISPLAY == NULL
6743# ifdef FEAT_GUI
6744 && !gui.in_use
6745# endif
6746 )
6747 {
6748 x_force_connect = TRUE;
6749 setup_term_clip();
6750 x_force_connect = FALSE;
6751 }
6752}
6753
6754 static int
6755check_connection(void)
6756{
6757 make_connection();
6758 if (X_DISPLAY == NULL)
6759 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006760 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006761 return FAIL;
6762 }
6763 return OK;
6764}
6765#endif
6766
6767#ifdef FEAT_CLIENTSERVER
6768 static void
6769remote_common(typval_T *argvars, typval_T *rettv, int expr)
6770{
6771 char_u *server_name;
6772 char_u *keys;
6773 char_u *r = NULL;
6774 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006775 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006776# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006777 HWND w;
6778# else
6779 Window w;
6780# endif
6781
6782 if (check_restricted() || check_secure())
6783 return;
6784
6785# ifdef FEAT_X11
6786 if (check_connection() == FAIL)
6787 return;
6788# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006789 if (argvars[2].v_type != VAR_UNKNOWN
6790 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006791 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006792
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006793 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794 if (server_name == NULL)
6795 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006796 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01006797# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006798 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006799# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006800 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
6801 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802# endif
6803 {
6804 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006805 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006806 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006807 vim_free(r);
6808 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006809 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006810 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006811 return;
6812 }
6813
6814 rettv->vval.v_string = r;
6815
6816 if (argvars[2].v_type != VAR_UNKNOWN)
6817 {
6818 dictitem_T v;
6819 char_u str[30];
6820 char_u *idvar;
6821
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006822 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006823 if (idvar != NULL && *idvar != NUL)
6824 {
6825 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
6826 v.di_tv.v_type = VAR_STRING;
6827 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006828 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006829 vim_free(v.di_tv.vval.v_string);
6830 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831 }
6832}
6833#endif
6834
6835/*
6836 * "remote_expr()" function
6837 */
6838 static void
6839f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
6840{
6841 rettv->v_type = VAR_STRING;
6842 rettv->vval.v_string = NULL;
6843#ifdef FEAT_CLIENTSERVER
6844 remote_common(argvars, rettv, TRUE);
6845#endif
6846}
6847
6848/*
6849 * "remote_foreground()" function
6850 */
6851 static void
6852f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6853{
6854#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006855# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006856 /* On Win32 it's done in this application. */
6857 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006858 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006859
6860 if (server_name != NULL)
6861 serverForeground(server_name);
6862 }
6863# else
6864 /* Send a foreground() expression to the server. */
6865 argvars[1].v_type = VAR_STRING;
6866 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
6867 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006868 rettv->v_type = VAR_STRING;
6869 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006870 remote_common(argvars, rettv, TRUE);
6871 vim_free(argvars[1].vval.v_string);
6872# endif
6873#endif
6874}
6875
6876 static void
6877f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
6878{
6879#ifdef FEAT_CLIENTSERVER
6880 dictitem_T v;
6881 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006882# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006883 long_u n = 0;
6884# endif
6885 char_u *serverid;
6886
6887 if (check_restricted() || check_secure())
6888 {
6889 rettv->vval.v_number = -1;
6890 return;
6891 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006892 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893 if (serverid == NULL)
6894 {
6895 rettv->vval.v_number = -1;
6896 return; /* type error; errmsg already given */
6897 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01006898# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006899 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
6900 if (n == 0)
6901 rettv->vval.v_number = -1;
6902 else
6903 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006904 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006905 rettv->vval.v_number = (s != NULL);
6906 }
6907# else
6908 if (check_connection() == FAIL)
6909 return;
6910
6911 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
6912 serverStrToWin(serverid), &s);
6913# endif
6914
6915 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
6916 {
6917 char_u *retvar;
6918
6919 v.di_tv.v_type = VAR_STRING;
6920 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006921 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006922 if (retvar != NULL)
6923 set_var(retvar, &v.di_tv, FALSE);
6924 vim_free(v.di_tv.vval.v_string);
6925 }
6926#else
6927 rettv->vval.v_number = -1;
6928#endif
6929}
6930
6931 static void
6932f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
6933{
6934 char_u *r = NULL;
6935
6936#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006937 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006938
6939 if (serverid != NULL && !check_restricted() && !check_secure())
6940 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006941 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006942# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01006943 /* The server's HWND is encoded in the 'id' parameter */
6944 long_u n = 0;
6945# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006946
6947 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006948 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006949
Bram Moolenaar4f974752019-02-17 17:44:42 +01006950# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006951 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
6952 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006953 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954 if (r == NULL)
6955# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006956 if (check_connection() == FAIL
6957 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
6958 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006959# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006960 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961 }
6962#endif
6963 rettv->v_type = VAR_STRING;
6964 rettv->vval.v_string = r;
6965}
6966
6967/*
6968 * "remote_send()" function
6969 */
6970 static void
6971f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
6972{
6973 rettv->v_type = VAR_STRING;
6974 rettv->vval.v_string = NULL;
6975#ifdef FEAT_CLIENTSERVER
6976 remote_common(argvars, rettv, FALSE);
6977#endif
6978}
6979
6980/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006981 * "remote_startserver()" function
6982 */
6983 static void
6984f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6985{
6986#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006987 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006988
6989 if (server == NULL)
6990 return; /* type error; errmsg already given */
6991 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006992 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006993 else
6994 {
6995# ifdef FEAT_X11
6996 if (check_connection() == OK)
6997 serverRegisterName(X_DISPLAY, server);
6998# else
6999 serverSetName(server);
7000# endif
7001 }
7002#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007003 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01007004#endif
7005}
7006
7007/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007008 * "rename({from}, {to})" function
7009 */
7010 static void
7011f_rename(typval_T *argvars, typval_T *rettv)
7012{
7013 char_u buf[NUMBUFLEN];
7014
7015 if (check_restricted() || check_secure())
7016 rettv->vval.v_number = -1;
7017 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007018 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
7019 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007020}
7021
7022/*
7023 * "repeat()" function
7024 */
7025 static void
7026f_repeat(typval_T *argvars, typval_T *rettv)
7027{
7028 char_u *p;
7029 int n;
7030 int slen;
7031 int len;
7032 char_u *r;
7033 int i;
7034
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007035 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036 if (argvars[0].v_type == VAR_LIST)
7037 {
7038 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
7039 while (n-- > 0)
7040 if (list_extend(rettv->vval.v_list,
7041 argvars[0].vval.v_list, NULL) == FAIL)
7042 break;
7043 }
7044 else
7045 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007046 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007047 rettv->v_type = VAR_STRING;
7048 rettv->vval.v_string = NULL;
7049
7050 slen = (int)STRLEN(p);
7051 len = slen * n;
7052 if (len <= 0)
7053 return;
7054
7055 r = alloc(len + 1);
7056 if (r != NULL)
7057 {
7058 for (i = 0; i < n; i++)
7059 mch_memmove(r + i * slen, p, (size_t)slen);
7060 r[len] = NUL;
7061 }
7062
7063 rettv->vval.v_string = r;
7064 }
7065}
7066
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007067#define SP_NOMOVE 0x01 /* don't move cursor */
7068#define SP_REPEAT 0x02 /* repeat to find outer pair */
7069#define SP_RETCOUNT 0x04 /* return matchcount */
7070#define SP_SETPCMARK 0x08 /* set previous context mark */
7071#define SP_START 0x10 /* accept match at start position */
7072#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
7073#define SP_END 0x40 /* leave cursor at end of match */
7074#define SP_COLUMN 0x80 /* start at cursor column */
7075
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007076/*
7077 * Get flags for a search function.
7078 * Possibly sets "p_ws".
7079 * Returns BACKWARD, FORWARD or zero (for an error).
7080 */
7081 static int
7082get_search_arg(typval_T *varp, int *flagsp)
7083{
7084 int dir = FORWARD;
7085 char_u *flags;
7086 char_u nbuf[NUMBUFLEN];
7087 int mask;
7088
7089 if (varp->v_type != VAR_UNKNOWN)
7090 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007091 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007092 if (flags == NULL)
7093 return 0; /* type error; errmsg already given */
7094 while (*flags != NUL)
7095 {
7096 switch (*flags)
7097 {
7098 case 'b': dir = BACKWARD; break;
7099 case 'w': p_ws = TRUE; break;
7100 case 'W': p_ws = FALSE; break;
7101 default: mask = 0;
7102 if (flagsp != NULL)
7103 switch (*flags)
7104 {
7105 case 'c': mask = SP_START; break;
7106 case 'e': mask = SP_END; break;
7107 case 'm': mask = SP_RETCOUNT; break;
7108 case 'n': mask = SP_NOMOVE; break;
7109 case 'p': mask = SP_SUBPAT; break;
7110 case 'r': mask = SP_REPEAT; break;
7111 case 's': mask = SP_SETPCMARK; break;
7112 case 'z': mask = SP_COLUMN; break;
7113 }
7114 if (mask == 0)
7115 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007116 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007117 dir = 0;
7118 }
7119 else
7120 *flagsp |= mask;
7121 }
7122 if (dir == 0)
7123 break;
7124 ++flags;
7125 }
7126 }
7127 return dir;
7128}
7129
7130/*
7131 * Shared by search() and searchpos() functions.
7132 */
7133 static int
7134search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
7135{
7136 int flags;
7137 char_u *pat;
7138 pos_T pos;
7139 pos_T save_cursor;
7140 int save_p_ws = p_ws;
7141 int dir;
7142 int retval = 0; /* default: FAIL */
7143 long lnum_stop = 0;
7144 proftime_T tm;
7145#ifdef FEAT_RELTIME
7146 long time_limit = 0;
7147#endif
7148 int options = SEARCH_KEEP;
7149 int subpatnum;
7150
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007151 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007152 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
7153 if (dir == 0)
7154 goto theend;
7155 flags = *flagsp;
7156 if (flags & SP_START)
7157 options |= SEARCH_START;
7158 if (flags & SP_END)
7159 options |= SEARCH_END;
7160 if (flags & SP_COLUMN)
7161 options |= SEARCH_COL;
7162
7163 /* Optional arguments: line number to stop searching and timeout. */
7164 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
7165 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007166 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007167 if (lnum_stop < 0)
7168 goto theend;
7169#ifdef FEAT_RELTIME
7170 if (argvars[3].v_type != VAR_UNKNOWN)
7171 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007172 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007173 if (time_limit < 0)
7174 goto theend;
7175 }
7176#endif
7177 }
7178
7179#ifdef FEAT_RELTIME
7180 /* Set the time limit, if there is one. */
7181 profile_setlimit(time_limit, &tm);
7182#endif
7183
7184 /*
7185 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
7186 * Check to make sure only those flags are set.
7187 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
7188 * flags cannot be set. Check for that condition also.
7189 */
7190 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
7191 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7192 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007193 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007194 goto theend;
7195 }
7196
7197 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007198 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007199 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007200 if (subpatnum != FAIL)
7201 {
7202 if (flags & SP_SUBPAT)
7203 retval = subpatnum;
7204 else
7205 retval = pos.lnum;
7206 if (flags & SP_SETPCMARK)
7207 setpcmark();
7208 curwin->w_cursor = pos;
7209 if (match_pos != NULL)
7210 {
7211 /* Store the match cursor position */
7212 match_pos->lnum = pos.lnum;
7213 match_pos->col = pos.col + 1;
7214 }
7215 /* "/$" will put the cursor after the end of the line, may need to
7216 * correct that here */
7217 check_cursor();
7218 }
7219
7220 /* If 'n' flag is used: restore cursor position. */
7221 if (flags & SP_NOMOVE)
7222 curwin->w_cursor = save_cursor;
7223 else
7224 curwin->w_set_curswant = TRUE;
7225theend:
7226 p_ws = save_p_ws;
7227
7228 return retval;
7229}
7230
7231#ifdef FEAT_FLOAT
7232
7233/*
7234 * round() is not in C90, use ceil() or floor() instead.
7235 */
7236 float_T
7237vim_round(float_T f)
7238{
7239 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
7240}
7241
7242/*
7243 * "round({float})" function
7244 */
7245 static void
7246f_round(typval_T *argvars, typval_T *rettv)
7247{
7248 float_T f = 0.0;
7249
7250 rettv->v_type = VAR_FLOAT;
7251 if (get_float_arg(argvars, &f) == OK)
7252 rettv->vval.v_float = vim_round(f);
7253 else
7254 rettv->vval.v_float = 0.0;
7255}
7256#endif
7257
Bram Moolenaare99be0e2019-03-26 22:51:09 +01007258#ifdef FEAT_RUBY
7259/*
7260 * "rubyeval()" function
7261 */
7262 static void
7263f_rubyeval(typval_T *argvars, typval_T *rettv)
7264{
7265 char_u *str;
7266 char_u buf[NUMBUFLEN];
7267
7268 str = tv_get_string_buf(&argvars[0], buf);
7269 do_rubyeval(str, rettv);
7270}
7271#endif
7272
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007273/*
7274 * "screenattr()" function
7275 */
7276 static void
7277f_screenattr(typval_T *argvars, typval_T *rettv)
7278{
7279 int row;
7280 int col;
7281 int c;
7282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007283 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7284 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285 if (row < 0 || row >= screen_Rows
7286 || col < 0 || col >= screen_Columns)
7287 c = -1;
7288 else
7289 c = ScreenAttrs[LineOffset[row] + col];
7290 rettv->vval.v_number = c;
7291}
7292
7293/*
7294 * "screenchar()" function
7295 */
7296 static void
7297f_screenchar(typval_T *argvars, typval_T *rettv)
7298{
7299 int row;
7300 int col;
7301 int off;
7302 int c;
7303
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007304 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7305 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007306 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007307 c = -1;
7308 else
7309 {
7310 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007311 if (enc_utf8 && ScreenLinesUC[off] != 0)
7312 c = ScreenLinesUC[off];
7313 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007314 c = ScreenLines[off];
7315 }
7316 rettv->vval.v_number = c;
7317}
7318
7319/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007320 * "screenchars()" function
7321 */
7322 static void
7323f_screenchars(typval_T *argvars, typval_T *rettv)
7324{
7325 int row;
7326 int col;
7327 int off;
7328 int c;
7329 int i;
7330
7331 if (rettv_list_alloc(rettv) == FAIL)
7332 return;
7333 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7334 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7335 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7336 return;
7337
7338 off = LineOffset[row] + col;
7339 if (enc_utf8 && ScreenLinesUC[off] != 0)
7340 c = ScreenLinesUC[off];
7341 else
7342 c = ScreenLines[off];
7343 list_append_number(rettv->vval.v_list, (varnumber_T)c);
7344
7345 if (enc_utf8)
7346
7347 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7348 list_append_number(rettv->vval.v_list,
7349 (varnumber_T)ScreenLinesC[i][off]);
7350}
7351
7352/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007353 * "screencol()" function
7354 *
7355 * First column is 1 to be consistent with virtcol().
7356 */
7357 static void
7358f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
7359{
7360 rettv->vval.v_number = screen_screencol() + 1;
7361}
7362
7363/*
7364 * "screenrow()" function
7365 */
7366 static void
7367f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
7368{
7369 rettv->vval.v_number = screen_screenrow() + 1;
7370}
7371
7372/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007373 * "screenstring()" function
7374 */
7375 static void
7376f_screenstring(typval_T *argvars, typval_T *rettv)
7377{
7378 int row;
7379 int col;
7380 int off;
7381 int c;
7382 int i;
7383 char_u buf[MB_MAXBYTES + 1];
7384 int buflen = 0;
7385
7386 rettv->vval.v_string = NULL;
7387 rettv->v_type = VAR_STRING;
7388
7389 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7390 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7391 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7392 return;
7393
7394 off = LineOffset[row] + col;
7395 if (enc_utf8 && ScreenLinesUC[off] != 0)
7396 c = ScreenLinesUC[off];
7397 else
7398 c = ScreenLines[off];
7399 buflen += mb_char2bytes(c, buf);
7400
7401 if (enc_utf8)
7402 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7403 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
7404
7405 buf[buflen] = NUL;
7406 rettv->vval.v_string = vim_strsave(buf);
7407}
7408
7409/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007410 * "search()" function
7411 */
7412 static void
7413f_search(typval_T *argvars, typval_T *rettv)
7414{
7415 int flags = 0;
7416
7417 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
7418}
7419
7420/*
7421 * "searchdecl()" function
7422 */
7423 static void
7424f_searchdecl(typval_T *argvars, typval_T *rettv)
7425{
7426 int locally = 1;
7427 int thisblock = 0;
7428 int error = FALSE;
7429 char_u *name;
7430
7431 rettv->vval.v_number = 1; /* default: FAIL */
7432
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007433 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007434 if (argvars[1].v_type != VAR_UNKNOWN)
7435 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007436 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007437 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007438 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439 }
7440 if (!error && name != NULL)
7441 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
7442 locally, thisblock, SEARCH_KEEP) == FAIL;
7443}
7444
7445/*
7446 * Used by searchpair() and searchpairpos()
7447 */
7448 static int
7449searchpair_cmn(typval_T *argvars, pos_T *match_pos)
7450{
7451 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01007452 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007453 int save_p_ws = p_ws;
7454 int dir;
7455 int flags = 0;
7456 char_u nbuf1[NUMBUFLEN];
7457 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007458 int retval = 0; /* default: FAIL */
7459 long lnum_stop = 0;
7460 long time_limit = 0;
7461
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007462 /* Get the three pattern arguments: start, middle, end. Will result in an
7463 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007464 spat = tv_get_string_chk(&argvars[0]);
7465 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
7466 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007467 if (spat == NULL || mpat == NULL || epat == NULL)
7468 goto theend; /* type error */
7469
7470 /* Handle the optional fourth argument: flags */
7471 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
7472 if (dir == 0)
7473 goto theend;
7474
7475 /* Don't accept SP_END or SP_SUBPAT.
7476 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
7477 */
7478 if ((flags & (SP_END | SP_SUBPAT)) != 0
7479 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7480 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007481 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007482 goto theend;
7483 }
7484
7485 /* Using 'r' implies 'W', otherwise it doesn't work. */
7486 if (flags & SP_REPEAT)
7487 p_ws = FALSE;
7488
7489 /* Optional fifth argument: skip expression */
7490 if (argvars[3].v_type == VAR_UNKNOWN
7491 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01007492 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007493 else
7494 {
Bram Moolenaar48570482017-10-30 21:48:41 +01007495 skip = &argvars[4];
7496 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
7497 && skip->v_type != VAR_STRING)
7498 {
7499 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007500 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01007501 goto theend;
7502 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007503 if (argvars[5].v_type != VAR_UNKNOWN)
7504 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007505 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007506 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007507 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007508 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007509 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007510 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007511#ifdef FEAT_RELTIME
7512 if (argvars[6].v_type != VAR_UNKNOWN)
7513 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007514 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007515 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007516 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007517 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007518 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007519 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007520 }
7521#endif
7522 }
7523 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524
7525 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
7526 match_pos, lnum_stop, time_limit);
7527
7528theend:
7529 p_ws = save_p_ws;
7530
7531 return retval;
7532}
7533
7534/*
7535 * "searchpair()" function
7536 */
7537 static void
7538f_searchpair(typval_T *argvars, typval_T *rettv)
7539{
7540 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
7541}
7542
7543/*
7544 * "searchpairpos()" function
7545 */
7546 static void
7547f_searchpairpos(typval_T *argvars, typval_T *rettv)
7548{
7549 pos_T match_pos;
7550 int lnum = 0;
7551 int col = 0;
7552
7553 if (rettv_list_alloc(rettv) == FAIL)
7554 return;
7555
7556 if (searchpair_cmn(argvars, &match_pos) > 0)
7557 {
7558 lnum = match_pos.lnum;
7559 col = match_pos.col;
7560 }
7561
7562 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7563 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7564}
7565
7566/*
7567 * Search for a start/middle/end thing.
7568 * Used by searchpair(), see its documentation for the details.
7569 * Returns 0 or -1 for no match,
7570 */
7571 long
7572do_searchpair(
7573 char_u *spat, /* start pattern */
7574 char_u *mpat, /* middle pattern */
7575 char_u *epat, /* end pattern */
7576 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01007577 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007578 int flags, /* SP_SETPCMARK and other SP_ values */
7579 pos_T *match_pos,
7580 linenr_T lnum_stop, /* stop at this line if not zero */
7581 long time_limit UNUSED) /* stop after this many msec */
7582{
7583 char_u *save_cpo;
7584 char_u *pat, *pat2 = NULL, *pat3 = NULL;
7585 long retval = 0;
7586 pos_T pos;
7587 pos_T firstpos;
7588 pos_T foundpos;
7589 pos_T save_cursor;
7590 pos_T save_pos;
7591 int n;
7592 int r;
7593 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01007594 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007595 int err;
7596 int options = SEARCH_KEEP;
7597 proftime_T tm;
7598
7599 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7600 save_cpo = p_cpo;
7601 p_cpo = empty_option;
7602
7603#ifdef FEAT_RELTIME
7604 /* Set the time limit, if there is one. */
7605 profile_setlimit(time_limit, &tm);
7606#endif
7607
7608 /* Make two search patterns: start/end (pat2, for in nested pairs) and
7609 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02007610 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
7611 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007612 if (pat2 == NULL || pat3 == NULL)
7613 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007614 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007615 if (*mpat == NUL)
7616 STRCPY(pat3, pat2);
7617 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007618 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007619 spat, epat, mpat);
7620 if (flags & SP_START)
7621 options |= SEARCH_START;
7622
Bram Moolenaar48570482017-10-30 21:48:41 +01007623 if (skip != NULL)
7624 {
7625 /* Empty string means to not use the skip expression. */
7626 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
7627 use_skip = skip->vval.v_string != NULL
7628 && *skip->vval.v_string != NUL;
7629 }
7630
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007631 save_cursor = curwin->w_cursor;
7632 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007633 CLEAR_POS(&firstpos);
7634 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007635 pat = pat3;
7636 for (;;)
7637 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007638 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007639 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007640 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007641 /* didn't find it or found the first match again: FAIL */
7642 break;
7643
7644 if (firstpos.lnum == 0)
7645 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007646 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007647 {
7648 /* Found the same position again. Can happen with a pattern that
7649 * has "\zs" at the end and searching backwards. Advance one
7650 * character and try again. */
7651 if (dir == BACKWARD)
7652 decl(&pos);
7653 else
7654 incl(&pos);
7655 }
7656 foundpos = pos;
7657
7658 /* clear the start flag to avoid getting stuck here */
7659 options &= ~SEARCH_START;
7660
7661 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01007662 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007663 {
7664 save_pos = curwin->w_cursor;
7665 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007666 err = FALSE;
7667 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007668 curwin->w_cursor = save_pos;
7669 if (err)
7670 {
7671 /* Evaluating {skip} caused an error, break here. */
7672 curwin->w_cursor = save_cursor;
7673 retval = -1;
7674 break;
7675 }
7676 if (r)
7677 continue;
7678 }
7679
7680 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7681 {
7682 /* Found end when searching backwards or start when searching
7683 * forward: nested pair. */
7684 ++nest;
7685 pat = pat2; /* nested, don't search for middle */
7686 }
7687 else
7688 {
7689 /* Found end when searching forward or start when searching
7690 * backward: end of (nested) pair; or found middle in outer pair. */
7691 if (--nest == 1)
7692 pat = pat3; /* outer level, search for middle */
7693 }
7694
7695 if (nest == 0)
7696 {
7697 /* Found the match: return matchcount or line number. */
7698 if (flags & SP_RETCOUNT)
7699 ++retval;
7700 else
7701 retval = pos.lnum;
7702 if (flags & SP_SETPCMARK)
7703 setpcmark();
7704 curwin->w_cursor = pos;
7705 if (!(flags & SP_REPEAT))
7706 break;
7707 nest = 1; /* search for next unmatched */
7708 }
7709 }
7710
7711 if (match_pos != NULL)
7712 {
7713 /* Store the match cursor position */
7714 match_pos->lnum = curwin->w_cursor.lnum;
7715 match_pos->col = curwin->w_cursor.col + 1;
7716 }
7717
7718 /* If 'n' flag is used or search failed: restore cursor position. */
7719 if ((flags & SP_NOMOVE) || retval == 0)
7720 curwin->w_cursor = save_cursor;
7721
7722theend:
7723 vim_free(pat2);
7724 vim_free(pat3);
7725 if (p_cpo == empty_option)
7726 p_cpo = save_cpo;
7727 else
7728 /* Darn, evaluating the {skip} expression changed the value. */
7729 free_string_option(save_cpo);
7730
7731 return retval;
7732}
7733
7734/*
7735 * "searchpos()" function
7736 */
7737 static void
7738f_searchpos(typval_T *argvars, typval_T *rettv)
7739{
7740 pos_T match_pos;
7741 int lnum = 0;
7742 int col = 0;
7743 int n;
7744 int flags = 0;
7745
7746 if (rettv_list_alloc(rettv) == FAIL)
7747 return;
7748
7749 n = search_cmn(argvars, &match_pos, &flags);
7750 if (n > 0)
7751 {
7752 lnum = match_pos.lnum;
7753 col = match_pos.col;
7754 }
7755
7756 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7757 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7758 if (flags & SP_SUBPAT)
7759 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7760}
7761
7762 static void
7763f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
7764{
7765#ifdef FEAT_CLIENTSERVER
7766 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007767 char_u *server = tv_get_string_chk(&argvars[0]);
7768 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007769
7770 rettv->vval.v_number = -1;
7771 if (server == NULL || reply == NULL)
7772 return;
7773 if (check_restricted() || check_secure())
7774 return;
7775# ifdef FEAT_X11
7776 if (check_connection() == FAIL)
7777 return;
7778# endif
7779
7780 if (serverSendReply(server, reply) < 0)
7781 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007782 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007783 return;
7784 }
7785 rettv->vval.v_number = 0;
7786#else
7787 rettv->vval.v_number = -1;
7788#endif
7789}
7790
7791 static void
7792f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
7793{
7794 char_u *r = NULL;
7795
7796#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01007797# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007798 r = serverGetVimNames();
7799# else
7800 make_connection();
7801 if (X_DISPLAY != NULL)
7802 r = serverGetVimNames(X_DISPLAY);
7803# endif
7804#endif
7805 rettv->v_type = VAR_STRING;
7806 rettv->vval.v_string = r;
7807}
7808
7809/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007810 * "setbufline()" function
7811 */
7812 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02007813f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007814{
7815 linenr_T lnum;
7816 buf_T *buf;
7817
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007818 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007819 if (buf == NULL)
7820 rettv->vval.v_number = 1; /* FAIL */
7821 else
7822 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007823 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02007824 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007825 }
7826}
7827
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007828 static void
7829f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7830{
7831 dict_T *d;
7832 dictitem_T *di;
7833 char_u *csearch;
7834
7835 if (argvars[0].v_type != VAR_DICT)
7836 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007837 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007838 return;
7839 }
7840
7841 if ((d = argvars[0].vval.v_dict) != NULL)
7842 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007843 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007844 if (csearch != NULL)
7845 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846 if (enc_utf8)
7847 {
7848 int pcc[MAX_MCO];
7849 int c = utfc_ptr2char(csearch, pcc);
7850
7851 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7852 }
7853 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007854 set_last_csearch(PTR2CHAR(csearch),
7855 csearch, MB_PTR2LEN(csearch));
7856 }
7857
7858 di = dict_find(d, (char_u *)"forward", -1);
7859 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007860 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007861 ? FORWARD : BACKWARD);
7862
7863 di = dict_find(d, (char_u *)"until", -1);
7864 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007865 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007866 }
7867}
7868
7869/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007870 * "setenv()" function
7871 */
7872 static void
7873f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7874{
7875 char_u namebuf[NUMBUFLEN];
7876 char_u valbuf[NUMBUFLEN];
7877 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7878
7879 if (argvars[1].v_type == VAR_SPECIAL
7880 && argvars[1].vval.v_number == VVAL_NULL)
7881 vim_unsetenv(name);
7882 else
7883 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7884}
7885
7886/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 * "setfperm({fname}, {mode})" function
7888 */
7889 static void
7890f_setfperm(typval_T *argvars, typval_T *rettv)
7891{
7892 char_u *fname;
7893 char_u modebuf[NUMBUFLEN];
7894 char_u *mode_str;
7895 int i;
7896 int mask;
7897 int mode = 0;
7898
7899 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007900 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007901 if (fname == NULL)
7902 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007903 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007904 if (mode_str == NULL)
7905 return;
7906 if (STRLEN(mode_str) != 9)
7907 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007908 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007909 return;
7910 }
7911
7912 mask = 1;
7913 for (i = 8; i >= 0; --i)
7914 {
7915 if (mode_str[i] != '-')
7916 mode |= mask;
7917 mask = mask << 1;
7918 }
7919 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7920}
7921
7922/*
7923 * "setline()" function
7924 */
7925 static void
7926f_setline(typval_T *argvars, typval_T *rettv)
7927{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007928 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007929
Bram Moolenaarca851592018-06-06 21:04:07 +02007930 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931}
7932
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007933/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007934 * "setpos()" function
7935 */
7936 static void
7937f_setpos(typval_T *argvars, typval_T *rettv)
7938{
7939 pos_T pos;
7940 int fnum;
7941 char_u *name;
7942 colnr_T curswant = -1;
7943
7944 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007945 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007946 if (name != NULL)
7947 {
7948 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7949 {
7950 if (--pos.col < 0)
7951 pos.col = 0;
7952 if (name[0] == '.' && name[1] == NUL)
7953 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007954 /* set cursor; "fnum" is ignored */
7955 curwin->w_cursor = pos;
7956 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007957 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007958 curwin->w_curswant = curswant - 1;
7959 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007960 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007961 check_cursor();
7962 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007963 }
7964 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7965 {
7966 /* set mark */
7967 if (setmark_pos(name[1], &pos, fnum) == OK)
7968 rettv->vval.v_number = 0;
7969 }
7970 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007971 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007972 }
7973 }
7974}
7975
7976/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007977 * "setreg()" function
7978 */
7979 static void
7980f_setreg(typval_T *argvars, typval_T *rettv)
7981{
7982 int regname;
7983 char_u *strregname;
7984 char_u *stropt;
7985 char_u *strval;
7986 int append;
7987 char_u yank_type;
7988 long block_len;
7989
7990 block_len = -1;
7991 yank_type = MAUTO;
7992 append = FALSE;
7993
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007994 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007995 rettv->vval.v_number = 1; /* FAIL is default */
7996
7997 if (strregname == NULL)
7998 return; /* type error; errmsg already given */
7999 regname = *strregname;
8000 if (regname == 0 || regname == '@')
8001 regname = '"';
8002
8003 if (argvars[2].v_type != VAR_UNKNOWN)
8004 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008005 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008006 if (stropt == NULL)
8007 return; /* type error */
8008 for (; *stropt != NUL; ++stropt)
8009 switch (*stropt)
8010 {
8011 case 'a': case 'A': /* append */
8012 append = TRUE;
8013 break;
8014 case 'v': case 'c': /* character-wise selection */
8015 yank_type = MCHAR;
8016 break;
8017 case 'V': case 'l': /* line-wise selection */
8018 yank_type = MLINE;
8019 break;
8020 case 'b': case Ctrl_V: /* block-wise selection */
8021 yank_type = MBLOCK;
8022 if (VIM_ISDIGIT(stropt[1]))
8023 {
8024 ++stropt;
8025 block_len = getdigits(&stropt) - 1;
8026 --stropt;
8027 }
8028 break;
8029 }
8030 }
8031
8032 if (argvars[1].v_type == VAR_LIST)
8033 {
8034 char_u **lstval;
8035 char_u **allocval;
8036 char_u buf[NUMBUFLEN];
8037 char_u **curval;
8038 char_u **curallocval;
8039 list_T *ll = argvars[1].vval.v_list;
8040 listitem_T *li;
8041 int len;
8042
8043 /* If the list is NULL handle like an empty list. */
8044 len = ll == NULL ? 0 : ll->lv_len;
8045
8046 /* First half: use for pointers to result lines; second half: use for
8047 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008048 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008049 if (lstval == NULL)
8050 return;
8051 curval = lstval;
8052 allocval = lstval + len + 2;
8053 curallocval = allocval;
8054
8055 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
8056 li = li->li_next)
8057 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008058 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008059 if (strval == NULL)
8060 goto free_lstval;
8061 if (strval == buf)
8062 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008063 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008064 * overwrite the string. */
8065 strval = vim_strsave(buf);
8066 if (strval == NULL)
8067 goto free_lstval;
8068 *curallocval++ = strval;
8069 }
8070 *curval++ = strval;
8071 }
8072 *curval++ = NULL;
8073
8074 write_reg_contents_lst(regname, lstval, -1,
8075 append, yank_type, block_len);
8076free_lstval:
8077 while (curallocval > allocval)
8078 vim_free(*--curallocval);
8079 vim_free(lstval);
8080 }
8081 else
8082 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008083 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008084 if (strval == NULL)
8085 return;
8086 write_reg_contents_ex(regname, strval, -1,
8087 append, yank_type, block_len);
8088 }
8089 rettv->vval.v_number = 0;
8090}
8091
8092/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008093 * "settagstack()" function
8094 */
8095 static void
8096f_settagstack(typval_T *argvars, typval_T *rettv)
8097{
8098 static char *e_invact2 = N_("E962: Invalid action: '%s'");
8099 win_T *wp;
8100 dict_T *d;
8101 int action = 'r';
8102
8103 rettv->vval.v_number = -1;
8104
8105 // first argument: window number or id
8106 wp = find_win_by_nr_or_id(&argvars[0]);
8107 if (wp == NULL)
8108 return;
8109
8110 // second argument: dict with items to set in the tag stack
8111 if (argvars[1].v_type != VAR_DICT)
8112 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008113 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008114 return;
8115 }
8116 d = argvars[1].vval.v_dict;
8117 if (d == NULL)
8118 return;
8119
8120 // third argument: action - 'a' for append and 'r' for replace.
8121 // default is to replace the stack.
8122 if (argvars[2].v_type == VAR_UNKNOWN)
8123 action = 'r';
8124 else if (argvars[2].v_type == VAR_STRING)
8125 {
8126 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008127 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008128 if (actstr == NULL)
8129 return;
8130 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
8131 action = *actstr;
8132 else
8133 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008134 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008135 return;
8136 }
8137 }
8138 else
8139 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008140 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008141 return;
8142 }
8143
8144 if (set_tagstack(wp, d, action) == OK)
8145 rettv->vval.v_number = 0;
8146}
8147
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008148#ifdef FEAT_CRYPT
8149/*
8150 * "sha256({string})" function
8151 */
8152 static void
8153f_sha256(typval_T *argvars, typval_T *rettv)
8154{
8155 char_u *p;
8156
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008157 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008158 rettv->vval.v_string = vim_strsave(
8159 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
8160 rettv->v_type = VAR_STRING;
8161}
8162#endif /* FEAT_CRYPT */
8163
8164/*
8165 * "shellescape({string})" function
8166 */
8167 static void
8168f_shellescape(typval_T *argvars, typval_T *rettv)
8169{
Bram Moolenaar20615522017-06-05 18:46:26 +02008170 int do_special = non_zero_arg(&argvars[1]);
8171
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008172 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008173 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174 rettv->v_type = VAR_STRING;
8175}
8176
8177/*
8178 * shiftwidth() function
8179 */
8180 static void
8181f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
8182{
Bram Moolenaarf9514162018-11-22 03:08:29 +01008183 rettv->vval.v_number = 0;
8184
8185 if (argvars[0].v_type != VAR_UNKNOWN)
8186 {
8187 long col;
8188
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008189 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01008190 if (col < 0)
8191 return; // type error; errmsg already given
8192#ifdef FEAT_VARTABS
8193 rettv->vval.v_number = get_sw_value_col(curbuf, col);
8194 return;
8195#endif
8196 }
8197
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008198 rettv->vval.v_number = get_sw_value(curbuf);
8199}
8200
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201#ifdef FEAT_FLOAT
8202/*
8203 * "sin()" function
8204 */
8205 static void
8206f_sin(typval_T *argvars, typval_T *rettv)
8207{
8208 float_T f = 0.0;
8209
8210 rettv->v_type = VAR_FLOAT;
8211 if (get_float_arg(argvars, &f) == OK)
8212 rettv->vval.v_float = sin(f);
8213 else
8214 rettv->vval.v_float = 0.0;
8215}
8216
8217/*
8218 * "sinh()" function
8219 */
8220 static void
8221f_sinh(typval_T *argvars, typval_T *rettv)
8222{
8223 float_T f = 0.0;
8224
8225 rettv->v_type = VAR_FLOAT;
8226 if (get_float_arg(argvars, &f) == OK)
8227 rettv->vval.v_float = sinh(f);
8228 else
8229 rettv->vval.v_float = 0.0;
8230}
8231#endif
8232
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008233/*
8234 * "soundfold({word})" function
8235 */
8236 static void
8237f_soundfold(typval_T *argvars, typval_T *rettv)
8238{
8239 char_u *s;
8240
8241 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008242 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008243#ifdef FEAT_SPELL
8244 rettv->vval.v_string = eval_soundfold(s);
8245#else
8246 rettv->vval.v_string = vim_strsave(s);
8247#endif
8248}
8249
8250/*
8251 * "spellbadword()" function
8252 */
8253 static void
8254f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
8255{
8256 char_u *word = (char_u *)"";
8257 hlf_T attr = HLF_COUNT;
8258 int len = 0;
8259
8260 if (rettv_list_alloc(rettv) == FAIL)
8261 return;
8262
8263#ifdef FEAT_SPELL
8264 if (argvars[0].v_type == VAR_UNKNOWN)
8265 {
8266 /* Find the start and length of the badly spelled word. */
8267 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
8268 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008269 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008270 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008271 curwin->w_set_curswant = TRUE;
8272 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008273 }
8274 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
8275 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008276 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008277 int capcol = -1;
8278
8279 if (str != NULL)
8280 {
8281 /* Check the argument for spelling. */
8282 while (*str != NUL)
8283 {
8284 len = spell_check(curwin, str, &attr, &capcol, FALSE);
8285 if (attr != HLF_COUNT)
8286 {
8287 word = str;
8288 break;
8289 }
8290 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02008291 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02008292 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008293 }
8294 }
8295 }
8296#endif
8297
8298 list_append_string(rettv->vval.v_list, word, len);
8299 list_append_string(rettv->vval.v_list, (char_u *)(
8300 attr == HLF_SPB ? "bad" :
8301 attr == HLF_SPR ? "rare" :
8302 attr == HLF_SPL ? "local" :
8303 attr == HLF_SPC ? "caps" :
8304 ""), -1);
8305}
8306
8307/*
8308 * "spellsuggest()" function
8309 */
8310 static void
8311f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
8312{
8313#ifdef FEAT_SPELL
8314 char_u *str;
8315 int typeerr = FALSE;
8316 int maxcount;
8317 garray_T ga;
8318 int i;
8319 listitem_T *li;
8320 int need_capital = FALSE;
8321#endif
8322
8323 if (rettv_list_alloc(rettv) == FAIL)
8324 return;
8325
8326#ifdef FEAT_SPELL
8327 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
8328 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008329 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008330 if (argvars[1].v_type != VAR_UNKNOWN)
8331 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008332 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008333 if (maxcount <= 0)
8334 return;
8335 if (argvars[2].v_type != VAR_UNKNOWN)
8336 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008337 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008338 if (typeerr)
8339 return;
8340 }
8341 }
8342 else
8343 maxcount = 25;
8344
8345 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
8346
8347 for (i = 0; i < ga.ga_len; ++i)
8348 {
8349 str = ((char_u **)ga.ga_data)[i];
8350
8351 li = listitem_alloc();
8352 if (li == NULL)
8353 vim_free(str);
8354 else
8355 {
8356 li->li_tv.v_type = VAR_STRING;
8357 li->li_tv.v_lock = 0;
8358 li->li_tv.vval.v_string = str;
8359 list_append(rettv->vval.v_list, li);
8360 }
8361 }
8362 ga_clear(&ga);
8363 }
8364#endif
8365}
8366
8367 static void
8368f_split(typval_T *argvars, typval_T *rettv)
8369{
8370 char_u *str;
8371 char_u *end;
8372 char_u *pat = NULL;
8373 regmatch_T regmatch;
8374 char_u patbuf[NUMBUFLEN];
8375 char_u *save_cpo;
8376 int match;
8377 colnr_T col = 0;
8378 int keepempty = FALSE;
8379 int typeerr = FALSE;
8380
8381 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8382 save_cpo = p_cpo;
8383 p_cpo = (char_u *)"";
8384
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008385 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008386 if (argvars[1].v_type != VAR_UNKNOWN)
8387 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008388 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008389 if (pat == NULL)
8390 typeerr = TRUE;
8391 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008392 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008393 }
8394 if (pat == NULL || *pat == NUL)
8395 pat = (char_u *)"[\\x01- ]\\+";
8396
8397 if (rettv_list_alloc(rettv) == FAIL)
8398 return;
8399 if (typeerr)
8400 return;
8401
8402 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8403 if (regmatch.regprog != NULL)
8404 {
8405 regmatch.rm_ic = FALSE;
8406 while (*str != NUL || keepempty)
8407 {
8408 if (*str == NUL)
8409 match = FALSE; /* empty item at the end */
8410 else
8411 match = vim_regexec_nl(&regmatch, str, col);
8412 if (match)
8413 end = regmatch.startp[0];
8414 else
8415 end = str + STRLEN(str);
8416 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
8417 && *str != NUL && match && end < regmatch.endp[0]))
8418 {
8419 if (list_append_string(rettv->vval.v_list, str,
8420 (int)(end - str)) == FAIL)
8421 break;
8422 }
8423 if (!match)
8424 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01008425 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008426 if (regmatch.endp[0] > str)
8427 col = 0;
8428 else
Bram Moolenaar13505972019-01-24 15:04:48 +01008429 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008430 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008431 str = regmatch.endp[0];
8432 }
8433
8434 vim_regfree(regmatch.regprog);
8435 }
8436
8437 p_cpo = save_cpo;
8438}
8439
8440#ifdef FEAT_FLOAT
8441/*
8442 * "sqrt()" function
8443 */
8444 static void
8445f_sqrt(typval_T *argvars, typval_T *rettv)
8446{
8447 float_T f = 0.0;
8448
8449 rettv->v_type = VAR_FLOAT;
8450 if (get_float_arg(argvars, &f) == OK)
8451 rettv->vval.v_float = sqrt(f);
8452 else
8453 rettv->vval.v_float = 0.0;
8454}
8455
8456/*
8457 * "str2float()" function
8458 */
8459 static void
8460f_str2float(typval_T *argvars, typval_T *rettv)
8461{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008462 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008463 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008464
Bram Moolenaar08243d22017-01-10 16:12:29 +01008465 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008466 p = skipwhite(p + 1);
8467 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01008468 if (isneg)
8469 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008470 rettv->v_type = VAR_FLOAT;
8471}
8472#endif
8473
8474/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02008475 * "str2list()" function
8476 */
8477 static void
8478f_str2list(typval_T *argvars, typval_T *rettv)
8479{
8480 char_u *p;
8481 int utf8 = FALSE;
8482
8483 if (rettv_list_alloc(rettv) == FAIL)
8484 return;
8485
8486 if (argvars[1].v_type != VAR_UNKNOWN)
8487 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
8488
8489 p = tv_get_string(&argvars[0]);
8490
8491 if (has_mbyte || utf8)
8492 {
8493 int (*ptr2len)(char_u *);
8494 int (*ptr2char)(char_u *);
8495
8496 if (utf8 || enc_utf8)
8497 {
8498 ptr2len = utf_ptr2len;
8499 ptr2char = utf_ptr2char;
8500 }
8501 else
8502 {
8503 ptr2len = mb_ptr2len;
8504 ptr2char = mb_ptr2char;
8505 }
8506
8507 for ( ; *p != NUL; p += (*ptr2len)(p))
8508 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
8509 }
8510 else
8511 for ( ; *p != NUL; ++p)
8512 list_append_number(rettv->vval.v_list, *p);
8513}
8514
8515/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008516 * "str2nr()" function
8517 */
8518 static void
8519f_str2nr(typval_T *argvars, typval_T *rettv)
8520{
8521 int base = 10;
8522 char_u *p;
8523 varnumber_T n;
8524 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +01008525 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008526
8527 if (argvars[1].v_type != VAR_UNKNOWN)
8528 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008529 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008530 if (base != 2 && base != 8 && base != 10 && base != 16)
8531 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008532 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008533 return;
8534 }
8535 }
8536
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008537 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008538 isneg = (*p == '-');
8539 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008540 p = skipwhite(p + 1);
8541 switch (base)
8542 {
8543 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
8544 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
8545 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
8546 default: what = 0;
8547 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02008548 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
8549 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01008550 if (isneg)
8551 rettv->vval.v_number = -n;
8552 else
8553 rettv->vval.v_number = n;
8554
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008555}
8556
8557#ifdef HAVE_STRFTIME
8558/*
8559 * "strftime({format}[, {time}])" function
8560 */
8561 static void
8562f_strftime(typval_T *argvars, typval_T *rettv)
8563{
8564 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02008565 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008566 struct tm *curtime;
8567 time_t seconds;
8568 char_u *p;
8569
8570 rettv->v_type = VAR_STRING;
8571
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008572 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008573 if (argvars[1].v_type == VAR_UNKNOWN)
8574 seconds = time(NULL);
8575 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008576 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02008577 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008578 /* MSVC returns NULL for an invalid value of seconds. */
8579 if (curtime == NULL)
8580 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
8581 else
8582 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008583 vimconv_T conv;
8584 char_u *enc;
8585
8586 conv.vc_type = CONV_NONE;
8587 enc = enc_locale();
8588 convert_setup(&conv, p_enc, enc);
8589 if (conv.vc_type != CONV_NONE)
8590 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008591 if (p != NULL)
8592 (void)strftime((char *)result_buf, sizeof(result_buf),
8593 (char *)p, curtime);
8594 else
8595 result_buf[0] = NUL;
8596
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008597 if (conv.vc_type != CONV_NONE)
8598 vim_free(p);
8599 convert_setup(&conv, enc, p_enc);
8600 if (conv.vc_type != CONV_NONE)
8601 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
8602 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008603 rettv->vval.v_string = vim_strsave(result_buf);
8604
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008605 /* Release conversion descriptors */
8606 convert_setup(&conv, NULL, NULL);
8607 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008608 }
8609}
8610#endif
8611
8612/*
8613 * "strgetchar()" function
8614 */
8615 static void
8616f_strgetchar(typval_T *argvars, typval_T *rettv)
8617{
8618 char_u *str;
8619 int len;
8620 int error = FALSE;
8621 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01008622 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008623
8624 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008625 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008626 if (str == NULL)
8627 return;
8628 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008629 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008630 if (error)
8631 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008632
Bram Moolenaar13505972019-01-24 15:04:48 +01008633 while (charidx >= 0 && byteidx < len)
8634 {
8635 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008636 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008637 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8638 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008639 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008640 --charidx;
8641 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008642 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008643}
8644
8645/*
8646 * "stridx()" function
8647 */
8648 static void
8649f_stridx(typval_T *argvars, typval_T *rettv)
8650{
8651 char_u buf[NUMBUFLEN];
8652 char_u *needle;
8653 char_u *haystack;
8654 char_u *save_haystack;
8655 char_u *pos;
8656 int start_idx;
8657
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008658 needle = tv_get_string_chk(&argvars[1]);
8659 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008660 rettv->vval.v_number = -1;
8661 if (needle == NULL || haystack == NULL)
8662 return; /* type error; errmsg already given */
8663
8664 if (argvars[2].v_type != VAR_UNKNOWN)
8665 {
8666 int error = FALSE;
8667
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008668 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008669 if (error || start_idx >= (int)STRLEN(haystack))
8670 return;
8671 if (start_idx >= 0)
8672 haystack += start_idx;
8673 }
8674
8675 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8676 if (pos != NULL)
8677 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8678}
8679
8680/*
8681 * "string()" function
8682 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008683 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008684f_string(typval_T *argvars, typval_T *rettv)
8685{
8686 char_u *tofree;
8687 char_u numbuf[NUMBUFLEN];
8688
8689 rettv->v_type = VAR_STRING;
8690 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8691 get_copyID());
8692 /* Make a copy if we have a value but it's not in allocated memory. */
8693 if (rettv->vval.v_string != NULL && tofree == NULL)
8694 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8695}
8696
8697/*
8698 * "strlen()" function
8699 */
8700 static void
8701f_strlen(typval_T *argvars, typval_T *rettv)
8702{
8703 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008704 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008705}
8706
8707/*
8708 * "strchars()" function
8709 */
8710 static void
8711f_strchars(typval_T *argvars, typval_T *rettv)
8712{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008713 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008714 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008715 varnumber_T len = 0;
8716 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008717
8718 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008719 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008721 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008722 else
8723 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008724 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8725 while (*s != NUL)
8726 {
8727 func_mb_ptr2char_adv(&s);
8728 ++len;
8729 }
8730 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008731 }
8732}
8733
8734/*
8735 * "strdisplaywidth()" function
8736 */
8737 static void
8738f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8739{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008740 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008741 int col = 0;
8742
8743 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008744 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008745
8746 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8747}
8748
8749/*
8750 * "strwidth()" function
8751 */
8752 static void
8753f_strwidth(typval_T *argvars, typval_T *rettv)
8754{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008755 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008756
Bram Moolenaar13505972019-01-24 15:04:48 +01008757 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008758}
8759
8760/*
8761 * "strcharpart()" function
8762 */
8763 static void
8764f_strcharpart(typval_T *argvars, typval_T *rettv)
8765{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008766 char_u *p;
8767 int nchar;
8768 int nbyte = 0;
8769 int charlen;
8770 int len = 0;
8771 int slen;
8772 int error = FALSE;
8773
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008774 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008775 slen = (int)STRLEN(p);
8776
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008777 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008778 if (!error)
8779 {
8780 if (nchar > 0)
8781 while (nchar > 0 && nbyte < slen)
8782 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008783 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008784 --nchar;
8785 }
8786 else
8787 nbyte = nchar;
8788 if (argvars[2].v_type != VAR_UNKNOWN)
8789 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008790 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008791 while (charlen > 0 && nbyte + len < slen)
8792 {
8793 int off = nbyte + len;
8794
8795 if (off < 0)
8796 len += 1;
8797 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008798 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008799 --charlen;
8800 }
8801 }
8802 else
8803 len = slen - nbyte; /* default: all bytes that are available. */
8804 }
8805
8806 /*
8807 * Only return the overlap between the specified part and the actual
8808 * string.
8809 */
8810 if (nbyte < 0)
8811 {
8812 len += nbyte;
8813 nbyte = 0;
8814 }
8815 else if (nbyte > slen)
8816 nbyte = slen;
8817 if (len < 0)
8818 len = 0;
8819 else if (nbyte + len > slen)
8820 len = slen - nbyte;
8821
8822 rettv->v_type = VAR_STRING;
8823 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008824}
8825
8826/*
8827 * "strpart()" function
8828 */
8829 static void
8830f_strpart(typval_T *argvars, typval_T *rettv)
8831{
8832 char_u *p;
8833 int n;
8834 int len;
8835 int slen;
8836 int error = FALSE;
8837
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008838 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008839 slen = (int)STRLEN(p);
8840
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008841 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008842 if (error)
8843 len = 0;
8844 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008845 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008846 else
8847 len = slen - n; /* default len: all bytes that are available. */
8848
8849 /*
8850 * Only return the overlap between the specified part and the actual
8851 * string.
8852 */
8853 if (n < 0)
8854 {
8855 len += n;
8856 n = 0;
8857 }
8858 else if (n > slen)
8859 n = slen;
8860 if (len < 0)
8861 len = 0;
8862 else if (n + len > slen)
8863 len = slen - n;
8864
8865 rettv->v_type = VAR_STRING;
8866 rettv->vval.v_string = vim_strnsave(p + n, len);
8867}
8868
8869/*
8870 * "strridx()" function
8871 */
8872 static void
8873f_strridx(typval_T *argvars, typval_T *rettv)
8874{
8875 char_u buf[NUMBUFLEN];
8876 char_u *needle;
8877 char_u *haystack;
8878 char_u *rest;
8879 char_u *lastmatch = NULL;
8880 int haystack_len, end_idx;
8881
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008882 needle = tv_get_string_chk(&argvars[1]);
8883 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008884
8885 rettv->vval.v_number = -1;
8886 if (needle == NULL || haystack == NULL)
8887 return; /* type error; errmsg already given */
8888
8889 haystack_len = (int)STRLEN(haystack);
8890 if (argvars[2].v_type != VAR_UNKNOWN)
8891 {
8892 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008893 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008894 if (end_idx < 0)
8895 return; /* can never find a match */
8896 }
8897 else
8898 end_idx = haystack_len;
8899
8900 if (*needle == NUL)
8901 {
8902 /* Empty string matches past the end. */
8903 lastmatch = haystack + end_idx;
8904 }
8905 else
8906 {
8907 for (rest = haystack; *rest != '\0'; ++rest)
8908 {
8909 rest = (char_u *)strstr((char *)rest, (char *)needle);
8910 if (rest == NULL || rest > haystack + end_idx)
8911 break;
8912 lastmatch = rest;
8913 }
8914 }
8915
8916 if (lastmatch == NULL)
8917 rettv->vval.v_number = -1;
8918 else
8919 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8920}
8921
8922/*
8923 * "strtrans()" function
8924 */
8925 static void
8926f_strtrans(typval_T *argvars, typval_T *rettv)
8927{
8928 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008929 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008930}
8931
8932/*
8933 * "submatch()" function
8934 */
8935 static void
8936f_submatch(typval_T *argvars, typval_T *rettv)
8937{
8938 int error = FALSE;
8939 int no;
8940 int retList = 0;
8941
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008942 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008943 if (error)
8944 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008945 if (no < 0 || no >= NSUBEXP)
8946 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008947 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008948 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008949 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008950 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008951 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008952 if (error)
8953 return;
8954
8955 if (retList == 0)
8956 {
8957 rettv->v_type = VAR_STRING;
8958 rettv->vval.v_string = reg_submatch(no);
8959 }
8960 else
8961 {
8962 rettv->v_type = VAR_LIST;
8963 rettv->vval.v_list = reg_submatch_list(no);
8964 }
8965}
8966
8967/*
8968 * "substitute()" function
8969 */
8970 static void
8971f_substitute(typval_T *argvars, typval_T *rettv)
8972{
8973 char_u patbuf[NUMBUFLEN];
8974 char_u subbuf[NUMBUFLEN];
8975 char_u flagsbuf[NUMBUFLEN];
8976
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008977 char_u *str = tv_get_string_chk(&argvars[0]);
8978 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008979 char_u *sub = NULL;
8980 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008981 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008982
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008983 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8984 expr = &argvars[2];
8985 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008986 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008987
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008988 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008989 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8990 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008991 rettv->vval.v_string = NULL;
8992 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008993 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008994}
8995
8996/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008997 * "swapinfo(swap_filename)" function
8998 */
8999 static void
9000f_swapinfo(typval_T *argvars, typval_T *rettv)
9001{
9002 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009003 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02009004}
9005
9006/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02009007 * "swapname(expr)" function
9008 */
9009 static void
9010f_swapname(typval_T *argvars, typval_T *rettv)
9011{
9012 buf_T *buf;
9013
9014 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009015 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02009016 if (buf == NULL || buf->b_ml.ml_mfp == NULL
9017 || buf->b_ml.ml_mfp->mf_fname == NULL)
9018 rettv->vval.v_string = NULL;
9019 else
9020 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
9021}
9022
9023/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009024 * "synID(lnum, col, trans)" function
9025 */
9026 static void
9027f_synID(typval_T *argvars UNUSED, typval_T *rettv)
9028{
9029 int id = 0;
9030#ifdef FEAT_SYN_HL
9031 linenr_T lnum;
9032 colnr_T col;
9033 int trans;
9034 int transerr = FALSE;
9035
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009036 lnum = tv_get_lnum(argvars); /* -1 on type error */
9037 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
9038 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009039
9040 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9041 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
9042 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
9043#endif
9044
9045 rettv->vval.v_number = id;
9046}
9047
9048/*
9049 * "synIDattr(id, what [, mode])" function
9050 */
9051 static void
9052f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
9053{
9054 char_u *p = NULL;
9055#ifdef FEAT_SYN_HL
9056 int id;
9057 char_u *what;
9058 char_u *mode;
9059 char_u modebuf[NUMBUFLEN];
9060 int modec;
9061
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009062 id = (int)tv_get_number(&argvars[0]);
9063 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009064 if (argvars[2].v_type != VAR_UNKNOWN)
9065 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009066 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009067 modec = TOLOWER_ASC(mode[0]);
9068 if (modec != 't' && modec != 'c' && modec != 'g')
9069 modec = 0; /* replace invalid with current */
9070 }
9071 else
9072 {
9073#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
9074 if (USE_24BIT)
9075 modec = 'g';
9076 else
9077#endif
9078 if (t_colors > 1)
9079 modec = 'c';
9080 else
9081 modec = 't';
9082 }
9083
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009084 switch (TOLOWER_ASC(what[0]))
9085 {
9086 case 'b':
9087 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
9088 p = highlight_color(id, what, modec);
9089 else /* bold */
9090 p = highlight_has_attr(id, HL_BOLD, modec);
9091 break;
9092
9093 case 'f': /* fg[#] or font */
9094 p = highlight_color(id, what, modec);
9095 break;
9096
9097 case 'i':
9098 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
9099 p = highlight_has_attr(id, HL_INVERSE, modec);
9100 else /* italic */
9101 p = highlight_has_attr(id, HL_ITALIC, modec);
9102 break;
9103
9104 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02009105 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009106 break;
9107
9108 case 'r': /* reverse */
9109 p = highlight_has_attr(id, HL_INVERSE, modec);
9110 break;
9111
9112 case 's':
9113 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
9114 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02009115 /* strikeout */
9116 else if (TOLOWER_ASC(what[1]) == 't' &&
9117 TOLOWER_ASC(what[2]) == 'r')
9118 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009119 else /* standout */
9120 p = highlight_has_attr(id, HL_STANDOUT, modec);
9121 break;
9122
9123 case 'u':
9124 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
9125 /* underline */
9126 p = highlight_has_attr(id, HL_UNDERLINE, modec);
9127 else
9128 /* undercurl */
9129 p = highlight_has_attr(id, HL_UNDERCURL, modec);
9130 break;
9131 }
9132
9133 if (p != NULL)
9134 p = vim_strsave(p);
9135#endif
9136 rettv->v_type = VAR_STRING;
9137 rettv->vval.v_string = p;
9138}
9139
9140/*
9141 * "synIDtrans(id)" function
9142 */
9143 static void
9144f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
9145{
9146 int id;
9147
9148#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009149 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009150
9151 if (id > 0)
9152 id = syn_get_final_id(id);
9153 else
9154#endif
9155 id = 0;
9156
9157 rettv->vval.v_number = id;
9158}
9159
9160/*
9161 * "synconcealed(lnum, col)" function
9162 */
9163 static void
9164f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
9165{
9166#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9167 linenr_T lnum;
9168 colnr_T col;
9169 int syntax_flags = 0;
9170 int cchar;
9171 int matchid = 0;
9172 char_u str[NUMBUFLEN];
9173#endif
9174
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009175 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009176
9177#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009178 lnum = tv_get_lnum(argvars); /* -1 on type error */
9179 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009180
9181 vim_memset(str, NUL, sizeof(str));
9182
9183 if (rettv_list_alloc(rettv) != FAIL)
9184 {
9185 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9186 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9187 && curwin->w_p_cole > 0)
9188 {
9189 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
9190 syntax_flags = get_syntax_info(&matchid);
9191
9192 /* get the conceal character */
9193 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
9194 {
9195 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02009196 if (cchar == NUL && curwin->w_p_cole == 1)
9197 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009198 if (cchar != NUL)
9199 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009200 if (has_mbyte)
9201 (*mb_char2bytes)(cchar, str);
9202 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009203 str[0] = cchar;
9204 }
9205 }
9206 }
9207
9208 list_append_number(rettv->vval.v_list,
9209 (syntax_flags & HL_CONCEAL) != 0);
9210 /* -1 to auto-determine strlen */
9211 list_append_string(rettv->vval.v_list, str, -1);
9212 list_append_number(rettv->vval.v_list, matchid);
9213 }
9214#endif
9215}
9216
9217/*
9218 * "synstack(lnum, col)" function
9219 */
9220 static void
9221f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
9222{
9223#ifdef FEAT_SYN_HL
9224 linenr_T lnum;
9225 colnr_T col;
9226 int i;
9227 int id;
9228#endif
9229
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009230 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009231
9232#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009233 lnum = tv_get_lnum(argvars); /* -1 on type error */
9234 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009235
9236 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9237 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9238 && rettv_list_alloc(rettv) != FAIL)
9239 {
9240 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
9241 for (i = 0; ; ++i)
9242 {
9243 id = syn_get_stack_item(i);
9244 if (id < 0)
9245 break;
9246 if (list_append_number(rettv->vval.v_list, id) == FAIL)
9247 break;
9248 }
9249 }
9250#endif
9251}
9252
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009253/*
9254 * "tabpagebuflist()" function
9255 */
9256 static void
9257f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9258{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009259 tabpage_T *tp;
9260 win_T *wp = NULL;
9261
9262 if (argvars[0].v_type == VAR_UNKNOWN)
9263 wp = firstwin;
9264 else
9265 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009266 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009267 if (tp != NULL)
9268 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9269 }
9270 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
9271 {
9272 for (; wp != NULL; wp = wp->w_next)
9273 if (list_append_number(rettv->vval.v_list,
9274 wp->w_buffer->b_fnum) == FAIL)
9275 break;
9276 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009277}
9278
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009279/*
9280 * "tabpagenr()" function
9281 */
9282 static void
9283f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
9284{
9285 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009286 char_u *arg;
9287
9288 if (argvars[0].v_type != VAR_UNKNOWN)
9289 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009290 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009291 nr = 0;
9292 if (arg != NULL)
9293 {
9294 if (STRCMP(arg, "$") == 0)
9295 nr = tabpage_index(NULL) - 1;
9296 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009297 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009298 }
9299 }
9300 else
9301 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009302 rettv->vval.v_number = nr;
9303}
9304
9305
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009306/*
9307 * Common code for tabpagewinnr() and winnr().
9308 */
9309 static int
9310get_winnr(tabpage_T *tp, typval_T *argvar)
9311{
9312 win_T *twin;
9313 int nr = 1;
9314 win_T *wp;
9315 char_u *arg;
9316
9317 twin = (tp == curtab) ? curwin : tp->tp_curwin;
9318 if (argvar->v_type != VAR_UNKNOWN)
9319 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +02009320 int invalid_arg = FALSE;
9321
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009322 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009323 if (arg == NULL)
9324 nr = 0; /* type error; errmsg already given */
9325 else if (STRCMP(arg, "$") == 0)
9326 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
9327 else if (STRCMP(arg, "#") == 0)
9328 {
9329 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
9330 if (twin == NULL)
9331 nr = 0;
9332 }
9333 else
9334 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +02009335 long count;
9336 char_u *endp;
9337
9338 // Extract the window count (if specified). e.g. winnr('3j')
9339 count = strtol((char *)arg, (char **)&endp, 10);
9340 if (count <= 0)
9341 count = 1; // if count is not specified, default to 1
9342 if (endp != NULL && *endp != '\0')
9343 {
9344 if (STRCMP(endp, "j") == 0)
9345 twin = win_vert_neighbor(tp, twin, FALSE, count);
9346 else if (STRCMP(endp, "k") == 0)
9347 twin = win_vert_neighbor(tp, twin, TRUE, count);
9348 else if (STRCMP(endp, "h") == 0)
9349 twin = win_horz_neighbor(tp, twin, TRUE, count);
9350 else if (STRCMP(endp, "l") == 0)
9351 twin = win_horz_neighbor(tp, twin, FALSE, count);
9352 else
9353 invalid_arg = TRUE;
9354 }
9355 else
9356 invalid_arg = TRUE;
9357 }
9358
9359 if (invalid_arg)
9360 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009361 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009362 nr = 0;
9363 }
9364 }
9365
9366 if (nr > 0)
9367 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9368 wp != twin; wp = wp->w_next)
9369 {
9370 if (wp == NULL)
9371 {
9372 /* didn't find it in this tabpage */
9373 nr = 0;
9374 break;
9375 }
9376 ++nr;
9377 }
9378 return nr;
9379}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009380
9381/*
9382 * "tabpagewinnr()" function
9383 */
9384 static void
9385f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
9386{
9387 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009388 tabpage_T *tp;
9389
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009390 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009391 if (tp == NULL)
9392 nr = 0;
9393 else
9394 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009395 rettv->vval.v_number = nr;
9396}
9397
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009398/*
9399 * "tagfiles()" function
9400 */
9401 static void
9402f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
9403{
9404 char_u *fname;
9405 tagname_T tn;
9406 int first;
9407
9408 if (rettv_list_alloc(rettv) == FAIL)
9409 return;
9410 fname = alloc(MAXPATHL);
9411 if (fname == NULL)
9412 return;
9413
9414 for (first = TRUE; ; first = FALSE)
9415 if (get_tagfname(&tn, first, fname) == FAIL
9416 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
9417 break;
9418 tagname_free(&tn);
9419 vim_free(fname);
9420}
9421
9422/*
9423 * "taglist()" function
9424 */
9425 static void
9426f_taglist(typval_T *argvars, typval_T *rettv)
9427{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009428 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009429 char_u *tag_pattern;
9430
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009431 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009432
9433 rettv->vval.v_number = FALSE;
9434 if (*tag_pattern == NUL)
9435 return;
9436
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009437 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009438 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009439 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009440 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009441}
9442
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009443#ifdef FEAT_FLOAT
9444/*
9445 * "tan()" function
9446 */
9447 static void
9448f_tan(typval_T *argvars, typval_T *rettv)
9449{
9450 float_T f = 0.0;
9451
9452 rettv->v_type = VAR_FLOAT;
9453 if (get_float_arg(argvars, &f) == OK)
9454 rettv->vval.v_float = tan(f);
9455 else
9456 rettv->vval.v_float = 0.0;
9457}
9458
9459/*
9460 * "tanh()" function
9461 */
9462 static void
9463f_tanh(typval_T *argvars, typval_T *rettv)
9464{
9465 float_T f = 0.0;
9466
9467 rettv->v_type = VAR_FLOAT;
9468 if (get_float_arg(argvars, &f) == OK)
9469 rettv->vval.v_float = tanh(f);
9470 else
9471 rettv->vval.v_float = 0.0;
9472}
9473#endif
9474
9475/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009476 * Get a callback from "arg". It can be a Funcref or a function name.
9477 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009478 * "cb_name" is not allocated.
9479 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009480 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009481 callback_T
9482get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009483{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009484 callback_T res;
9485
9486 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
9488 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009489 res.cb_partial = arg->vval.v_partial;
9490 ++res.cb_partial->pt_refcount;
9491 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009492 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009493 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009494 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009495 res.cb_partial = NULL;
9496 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
9497 {
9498 // Note that we don't make a copy of the string.
9499 res.cb_name = arg->vval.v_string;
9500 func_ref(res.cb_name);
9501 }
9502 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
9503 {
9504 res.cb_name = (char_u *)"";
9505 }
9506 else
9507 {
9508 emsg(_("E921: Invalid callback argument"));
9509 res.cb_name = NULL;
9510 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009511 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009512 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009513}
9514
9515/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009516 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009517 */
9518 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009519put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009520{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009521 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009522 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009523 tv->v_type = VAR_PARTIAL;
9524 tv->vval.v_partial = cb->cb_partial;
9525 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009526 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009527 else
9528 {
9529 tv->v_type = VAR_FUNC;
9530 tv->vval.v_string = vim_strsave(cb->cb_name);
9531 func_ref(cb->cb_name);
9532 }
9533}
9534
9535/*
9536 * Make a copy of "src" into "dest", allocating the function name if needed,
9537 * without incrementing the refcount.
9538 */
9539 void
9540set_callback(callback_T *dest, callback_T *src)
9541{
9542 if (src->cb_partial == NULL)
9543 {
9544 // just a function name, make a copy
9545 dest->cb_name = vim_strsave(src->cb_name);
9546 dest->cb_free_name = TRUE;
9547 }
9548 else
9549 {
9550 // cb_name is a pointer into cb_partial
9551 dest->cb_name = src->cb_name;
9552 dest->cb_free_name = FALSE;
9553 }
9554 dest->cb_partial = src->cb_partial;
9555}
9556
9557/*
9558 * Unref/free "callback" returned by get_callback() or set_callback().
9559 */
9560 void
9561free_callback(callback_T *callback)
9562{
9563 if (callback->cb_partial != NULL)
9564 {
9565 partial_unref(callback->cb_partial);
9566 callback->cb_partial = NULL;
9567 }
9568 else if (callback->cb_name != NULL)
9569 func_unref(callback->cb_name);
9570 if (callback->cb_free_name)
9571 {
9572 vim_free(callback->cb_name);
9573 callback->cb_free_name = FALSE;
9574 }
9575 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009576}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009577
9578#ifdef FEAT_TIMERS
9579/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02009580 * "timer_info([timer])" function
9581 */
9582 static void
9583f_timer_info(typval_T *argvars, typval_T *rettv)
9584{
9585 timer_T *timer = NULL;
9586
9587 if (rettv_list_alloc(rettv) != OK)
9588 return;
9589 if (argvars[0].v_type != VAR_UNKNOWN)
9590 {
9591 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009592 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02009593 else
9594 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009595 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02009596 if (timer != NULL)
9597 add_timer_info(rettv, timer);
9598 }
9599 }
9600 else
9601 add_timer_info_all(rettv);
9602}
9603
9604/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009605 * "timer_pause(timer, paused)" function
9606 */
9607 static void
9608f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
9609{
9610 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009611 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009612
9613 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009614 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009615 else
9616 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009617 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009618 if (timer != NULL)
9619 timer->tr_paused = paused;
9620 }
9621}
9622
9623/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009624 * "timer_start(time, callback [, options])" function
9625 */
9626 static void
9627f_timer_start(typval_T *argvars, typval_T *rettv)
9628{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009629 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +02009630 timer_T *timer;
9631 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009632 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +02009633 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009634
Bram Moolenaar75537a92016-09-05 22:45:28 +02009635 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009636 if (check_secure())
9637 return;
9638 if (argvars[2].v_type != VAR_UNKNOWN)
9639 {
9640 if (argvars[2].v_type != VAR_DICT
9641 || (dict = argvars[2].vval.v_dict) == NULL)
9642 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009643 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009644 return;
9645 }
9646 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009647 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009648 }
9649
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009650 callback = get_callback(&argvars[1]);
9651 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +02009652 return;
9653
9654 timer = create_timer(msec, repeat);
9655 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009656 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009657 else
9658 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009659 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +02009660 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009661 }
9662}
9663
9664/*
9665 * "timer_stop(timer)" function
9666 */
9667 static void
9668f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
9669{
9670 timer_T *timer;
9671
9672 if (argvars[0].v_type != VAR_NUMBER)
9673 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009674 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009675 return;
9676 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009677 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009678 if (timer != NULL)
9679 stop_timer(timer);
9680}
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009681
9682/*
9683 * "timer_stopall()" function
9684 */
9685 static void
9686f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9687{
9688 stop_all_timers();
9689}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009690#endif
9691
9692/*
9693 * "tolower(string)" function
9694 */
9695 static void
9696f_tolower(typval_T *argvars, typval_T *rettv)
9697{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009698 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009699 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009700}
9701
9702/*
9703 * "toupper(string)" function
9704 */
9705 static void
9706f_toupper(typval_T *argvars, typval_T *rettv)
9707{
9708 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009709 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009710}
9711
9712/*
9713 * "tr(string, fromstr, tostr)" function
9714 */
9715 static void
9716f_tr(typval_T *argvars, typval_T *rettv)
9717{
9718 char_u *in_str;
9719 char_u *fromstr;
9720 char_u *tostr;
9721 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009722 int inlen;
9723 int fromlen;
9724 int tolen;
9725 int idx;
9726 char_u *cpstr;
9727 int cplen;
9728 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009729 char_u buf[NUMBUFLEN];
9730 char_u buf2[NUMBUFLEN];
9731 garray_T ga;
9732
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009733 in_str = tv_get_string(&argvars[0]);
9734 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
9735 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009736
9737 /* Default return value: empty string. */
9738 rettv->v_type = VAR_STRING;
9739 rettv->vval.v_string = NULL;
9740 if (fromstr == NULL || tostr == NULL)
9741 return; /* type error; errmsg already given */
9742 ga_init2(&ga, (int)sizeof(char), 80);
9743
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009744 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009745 /* not multi-byte: fromstr and tostr must be the same length */
9746 if (STRLEN(fromstr) != STRLEN(tostr))
9747 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009748error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009749 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009750 ga_clear(&ga);
9751 return;
9752 }
9753
9754 /* fromstr and tostr have to contain the same number of chars */
9755 while (*in_str != NUL)
9756 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009757 if (has_mbyte)
9758 {
9759 inlen = (*mb_ptr2len)(in_str);
9760 cpstr = in_str;
9761 cplen = inlen;
9762 idx = 0;
9763 for (p = fromstr; *p != NUL; p += fromlen)
9764 {
9765 fromlen = (*mb_ptr2len)(p);
9766 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
9767 {
9768 for (p = tostr; *p != NUL; p += tolen)
9769 {
9770 tolen = (*mb_ptr2len)(p);
9771 if (idx-- == 0)
9772 {
9773 cplen = tolen;
9774 cpstr = p;
9775 break;
9776 }
9777 }
9778 if (*p == NUL) /* tostr is shorter than fromstr */
9779 goto error;
9780 break;
9781 }
9782 ++idx;
9783 }
9784
9785 if (first && cpstr == in_str)
9786 {
9787 /* Check that fromstr and tostr have the same number of
9788 * (multi-byte) characters. Done only once when a character
9789 * of in_str doesn't appear in fromstr. */
9790 first = FALSE;
9791 for (p = tostr; *p != NUL; p += tolen)
9792 {
9793 tolen = (*mb_ptr2len)(p);
9794 --idx;
9795 }
9796 if (idx != 0)
9797 goto error;
9798 }
9799
9800 (void)ga_grow(&ga, cplen);
9801 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
9802 ga.ga_len += cplen;
9803
9804 in_str += inlen;
9805 }
9806 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009807 {
9808 /* When not using multi-byte chars we can do it faster. */
9809 p = vim_strchr(fromstr, *in_str);
9810 if (p != NULL)
9811 ga_append(&ga, tostr[p - fromstr]);
9812 else
9813 ga_append(&ga, *in_str);
9814 ++in_str;
9815 }
9816 }
9817
9818 /* add a terminating NUL */
9819 (void)ga_grow(&ga, 1);
9820 ga_append(&ga, NUL);
9821
9822 rettv->vval.v_string = ga.ga_data;
9823}
9824
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009825/*
9826 * "trim({expr})" function
9827 */
9828 static void
9829f_trim(typval_T *argvars, typval_T *rettv)
9830{
9831 char_u buf1[NUMBUFLEN];
9832 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009833 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009834 char_u *mask = NULL;
9835 char_u *tail;
9836 char_u *prev;
9837 char_u *p;
9838 int c1;
9839
9840 rettv->v_type = VAR_STRING;
9841 if (head == NULL)
9842 {
9843 rettv->vval.v_string = NULL;
9844 return;
9845 }
9846
9847 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009848 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01009849
9850 while (*head != NUL)
9851 {
9852 c1 = PTR2CHAR(head);
9853 if (mask == NULL)
9854 {
9855 if (c1 > ' ' && c1 != 0xa0)
9856 break;
9857 }
9858 else
9859 {
9860 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9861 if (c1 == PTR2CHAR(p))
9862 break;
9863 if (*p == NUL)
9864 break;
9865 }
9866 MB_PTR_ADV(head);
9867 }
9868
9869 for (tail = head + STRLEN(head); tail > head; tail = prev)
9870 {
9871 prev = tail;
9872 MB_PTR_BACK(head, prev);
9873 c1 = PTR2CHAR(prev);
9874 if (mask == NULL)
9875 {
9876 if (c1 > ' ' && c1 != 0xa0)
9877 break;
9878 }
9879 else
9880 {
9881 for (p = mask; *p != NUL; MB_PTR_ADV(p))
9882 if (c1 == PTR2CHAR(p))
9883 break;
9884 if (*p == NUL)
9885 break;
9886 }
9887 }
9888 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
9889}
9890
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009891#ifdef FEAT_FLOAT
9892/*
9893 * "trunc({float})" function
9894 */
9895 static void
9896f_trunc(typval_T *argvars, typval_T *rettv)
9897{
9898 float_T f = 0.0;
9899
9900 rettv->v_type = VAR_FLOAT;
9901 if (get_float_arg(argvars, &f) == OK)
9902 /* trunc() is not in C90, use floor() or ceil() instead. */
9903 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
9904 else
9905 rettv->vval.v_float = 0.0;
9906}
9907#endif
9908
9909/*
9910 * "type(expr)" function
9911 */
9912 static void
9913f_type(typval_T *argvars, typval_T *rettv)
9914{
9915 int n = -1;
9916
9917 switch (argvars[0].v_type)
9918 {
Bram Moolenaarf562e722016-07-19 17:25:25 +02009919 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
9920 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009921 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +02009922 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
9923 case VAR_LIST: n = VAR_TYPE_LIST; break;
9924 case VAR_DICT: n = VAR_TYPE_DICT; break;
9925 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009926 case VAR_SPECIAL:
9927 if (argvars[0].vval.v_number == VVAL_FALSE
9928 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +02009929 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009930 else
Bram Moolenaarf562e722016-07-19 17:25:25 +02009931 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009932 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +02009933 case VAR_JOB: n = VAR_TYPE_JOB; break;
9934 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009935 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009936 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01009937 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009938 n = -1;
9939 break;
9940 }
9941 rettv->vval.v_number = n;
9942}
9943
9944/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009945 * "virtcol(string)" function
9946 */
9947 static void
9948f_virtcol(typval_T *argvars, typval_T *rettv)
9949{
9950 colnr_T vcol = 0;
9951 pos_T *fp;
9952 int fnum = curbuf->b_fnum;
9953
9954 fp = var2fpos(&argvars[0], FALSE, &fnum);
9955 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
9956 && fnum == curbuf->b_fnum)
9957 {
9958 getvvcol(curwin, fp, NULL, NULL, &vcol);
9959 ++vcol;
9960 }
9961
9962 rettv->vval.v_number = vcol;
9963}
9964
9965/*
9966 * "visualmode()" function
9967 */
9968 static void
9969f_visualmode(typval_T *argvars, typval_T *rettv)
9970{
9971 char_u str[2];
9972
9973 rettv->v_type = VAR_STRING;
9974 str[0] = curbuf->b_visual_mode_eval;
9975 str[1] = NUL;
9976 rettv->vval.v_string = vim_strsave(str);
9977
9978 /* A non-zero number or non-empty string argument: reset mode. */
9979 if (non_zero_arg(&argvars[0]))
9980 curbuf->b_visual_mode_eval = NUL;
9981}
9982
9983/*
9984 * "wildmenumode()" function
9985 */
9986 static void
9987f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9988{
9989#ifdef FEAT_WILDMENU
9990 if (wild_menu_showing)
9991 rettv->vval.v_number = 1;
9992#endif
9993}
9994
9995/*
9996 * "winbufnr(nr)" function
9997 */
9998 static void
9999f_winbufnr(typval_T *argvars, typval_T *rettv)
10000{
10001 win_T *wp;
10002
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010003 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010004 if (wp == NULL)
10005 rettv->vval.v_number = -1;
10006 else
10007 rettv->vval.v_number = wp->w_buffer->b_fnum;
10008}
10009
10010/*
10011 * "wincol()" function
10012 */
10013 static void
10014f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
10015{
10016 validate_cursor();
10017 rettv->vval.v_number = curwin->w_wcol + 1;
10018}
10019
10020/*
10021 * "winheight(nr)" function
10022 */
10023 static void
10024f_winheight(typval_T *argvars, typval_T *rettv)
10025{
10026 win_T *wp;
10027
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010028 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010029 if (wp == NULL)
10030 rettv->vval.v_number = -1;
10031 else
10032 rettv->vval.v_number = wp->w_height;
10033}
10034
10035/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020010036 * "winlayout()" function
10037 */
10038 static void
10039f_winlayout(typval_T *argvars, typval_T *rettv)
10040{
10041 tabpage_T *tp;
10042
10043 if (rettv_list_alloc(rettv) != OK)
10044 return;
10045
10046 if (argvars[0].v_type == VAR_UNKNOWN)
10047 tp = curtab;
10048 else
10049 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010050 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020010051 if (tp == NULL)
10052 return;
10053 }
10054
10055 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
10056}
10057
10058/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010059 * "winline()" function
10060 */
10061 static void
10062f_winline(typval_T *argvars UNUSED, typval_T *rettv)
10063{
10064 validate_cursor();
10065 rettv->vval.v_number = curwin->w_wrow + 1;
10066}
10067
10068/*
10069 * "winnr()" function
10070 */
10071 static void
10072f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
10073{
10074 int nr = 1;
10075
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010076 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010077 rettv->vval.v_number = nr;
10078}
10079
10080/*
10081 * "winrestcmd()" function
10082 */
10083 static void
10084f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
10085{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010086 win_T *wp;
10087 int winnr = 1;
10088 garray_T ga;
10089 char_u buf[50];
10090
10091 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020010092 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010093 {
10094 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
10095 ga_concat(&ga, buf);
10096 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
10097 ga_concat(&ga, buf);
10098 ++winnr;
10099 }
10100 ga_append(&ga, NUL);
10101
10102 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010103 rettv->v_type = VAR_STRING;
10104}
10105
10106/*
10107 * "winrestview()" function
10108 */
10109 static void
10110f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
10111{
10112 dict_T *dict;
10113
10114 if (argvars[0].v_type != VAR_DICT
10115 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010116 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010117 else
10118 {
10119 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010120 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010121 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010122 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010123 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010124 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010125 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
10126 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010127 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010128 curwin->w_set_curswant = FALSE;
10129 }
10130
10131 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010132 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010133#ifdef FEAT_DIFF
10134 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010135 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010136#endif
10137 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010138 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010139 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010140 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010141
10142 check_cursor();
10143 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020010144 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010145 changed_window_setting();
10146
10147 if (curwin->w_topline <= 0)
10148 curwin->w_topline = 1;
10149 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
10150 curwin->w_topline = curbuf->b_ml.ml_line_count;
10151#ifdef FEAT_DIFF
10152 check_topfill(curwin, TRUE);
10153#endif
10154 }
10155}
10156
10157/*
10158 * "winsaveview()" function
10159 */
10160 static void
10161f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
10162{
10163 dict_T *dict;
10164
10165 if (rettv_dict_alloc(rettv) == FAIL)
10166 return;
10167 dict = rettv->vval.v_dict;
10168
Bram Moolenaare0be1672018-07-08 16:50:37 +020010169 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
10170 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020010171 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010172 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020010173 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010174
Bram Moolenaare0be1672018-07-08 16:50:37 +020010175 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010176#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020010177 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010178#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020010179 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
10180 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010181}
10182
10183/*
10184 * "winwidth(nr)" function
10185 */
10186 static void
10187f_winwidth(typval_T *argvars, typval_T *rettv)
10188{
10189 win_T *wp;
10190
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010191 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010192 if (wp == NULL)
10193 rettv->vval.v_number = -1;
10194 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010195 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010196}
10197
10198/*
10199 * "wordcount()" function
10200 */
10201 static void
10202f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
10203{
10204 if (rettv_dict_alloc(rettv) == FAIL)
10205 return;
10206 cursor_pos_info(rettv->vval.v_dict);
10207}
10208
10209/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010210 * "xor(expr, expr)" function
10211 */
10212 static void
10213f_xor(typval_T *argvars, typval_T *rettv)
10214{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010215 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
10216 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010217}
10218
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010219#endif /* FEAT_EVAL */