blob: 4fbecc304d3065b4ccf73f026c1f92adc96363af [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);
285static void f_system(typval_T *argvars, typval_T *rettv);
286static void f_systemlist(typval_T *argvars, typval_T *rettv);
287static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
288static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
289static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
290static void f_taglist(typval_T *argvars, typval_T *rettv);
291static void f_tagfiles(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200292#ifdef FEAT_FLOAT
293static void f_tan(typval_T *argvars, typval_T *rettv);
294static void f_tanh(typval_T *argvars, typval_T *rettv);
295#endif
296#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200297static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200298static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200299static void f_timer_start(typval_T *argvars, typval_T *rettv);
300static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200301static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200302#endif
303static void f_tolower(typval_T *argvars, typval_T *rettv);
304static void f_toupper(typval_T *argvars, typval_T *rettv);
305static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100306static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200307#ifdef FEAT_FLOAT
308static void f_trunc(typval_T *argvars, typval_T *rettv);
309#endif
310static void f_type(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200311static void f_virtcol(typval_T *argvars, typval_T *rettv);
312static void f_visualmode(typval_T *argvars, typval_T *rettv);
313static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200314static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200315static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
316static void f_win_getid(typval_T *argvars, typval_T *rettv);
317static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
318static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
319static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100320static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200321static void f_winbufnr(typval_T *argvars, typval_T *rettv);
322static void f_wincol(typval_T *argvars, typval_T *rettv);
323static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200324static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200325static void f_winline(typval_T *argvars, typval_T *rettv);
326static void f_winnr(typval_T *argvars, typval_T *rettv);
327static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
328static void f_winrestview(typval_T *argvars, typval_T *rettv);
329static void f_winsaveview(typval_T *argvars, typval_T *rettv);
330static void f_winwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200331static void f_wordcount(typval_T *argvars, typval_T *rettv);
332static void f_xor(typval_T *argvars, typval_T *rettv);
333
334/*
335 * Array with names and number of arguments of all internal functions
336 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
337 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200338typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200339{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200340 char *f_name; // function name
341 char f_min_argc; // minimal number of arguments
342 char f_max_argc; // maximal number of arguments
343 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200344 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200345 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200346} funcentry_T;
347
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200348// values for f_argtype; zero means it cannot be used as a method
349#define FEARG_1 1 // base is the first argument
350#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200351#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200352#define FEARG_LAST 9 // base is the last argument
353
Bram Moolenaarac92e252019-08-03 21:58:38 +0200354static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200355{
356#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200357 {"abs", 1, 1, FEARG_1, f_abs},
358 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200359#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200360 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200361 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200362 {"append", 2, 2, FEARG_LAST, f_append},
363 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
364 {"argc", 0, 1, 0, f_argc},
365 {"argidx", 0, 0, 0, f_argidx},
366 {"arglistid", 0, 2, 0, f_arglistid},
367 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200368#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200369 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200370#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200371 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200372 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200373 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200374 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200375 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
376 {"assert_false", 1, 2, FEARG_1, f_assert_false},
377 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
378 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200379 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200380 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200381 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200382 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200383#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200384 {"atan", 1, 1, FEARG_1, f_atan},
385 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200386#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100387#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200388 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200389 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100390# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200391 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100392# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100393#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200394 {"browse", 4, 4, 0, f_browse},
395 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200396 {"bufadd", 1, 1, FEARG_1, f_bufadd},
397 {"bufexists", 1, 1, FEARG_1, f_bufexists},
398 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200399 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
400 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200401 {"buflisted", 1, 1, FEARG_1, f_buflisted},
402 {"bufload", 1, 1, FEARG_1, f_bufload},
403 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200404 {"bufname", 0, 1, FEARG_1, f_bufname},
405 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200406 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
407 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200408 {"byte2line", 1, 1, FEARG_1, f_byte2line},
409 {"byteidx", 2, 2, FEARG_1, f_byteidx},
410 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
411 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200412#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200413 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200414#endif
415#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200416 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
417 {"ch_close", 1, 1, FEARG_1, f_ch_close},
418 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
419 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
420 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
421 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
422 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
423 {"ch_info", 1, 1, FEARG_1, f_ch_info},
424 {"ch_log", 1, 2, FEARG_1, f_ch_log},
425 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
426 {"ch_open", 1, 2, FEARG_1, f_ch_open},
427 {"ch_read", 1, 2, FEARG_1, f_ch_read},
428 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
429 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
430 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
431 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
432 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
433 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200434#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200435 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200436 {"char2nr", 1, 2, FEARG_1, f_char2nr},
437 {"chdir", 1, 1, FEARG_1, f_chdir},
438 {"cindent", 1, 1, FEARG_1, f_cindent},
439 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
440 {"col", 1, 1, FEARG_1, f_col},
441 {"complete", 2, 2, FEARG_2, f_complete},
442 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200443 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200444 {"complete_info", 0, 1, FEARG_1, f_complete_info},
445 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200446 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200447#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200448 {"cos", 1, 1, FEARG_1, f_cos},
449 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200450#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200451 {"count", 2, 4, FEARG_1, f_count},
452 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200453 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100454#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200455 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200456#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200457 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
458 {"delete", 1, 2, FEARG_1, f_delete},
459 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200460 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200461 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
462 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200463 {"empty", 1, 1, FEARG_1, f_empty},
464 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200465 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200466 {"eval", 1, 1, FEARG_1, f_eval},
467 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200468 {"executable", 1, 1, FEARG_1, f_executable},
469 {"execute", 1, 2, FEARG_1, f_execute},
470 {"exepath", 1, 1, FEARG_1, f_exepath},
471 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200472#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200473 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200474#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200475 {"expand", 1, 3, FEARG_1, f_expand},
476 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200477 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200478 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
479 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
480 {"filereadable", 1, 1, FEARG_1, f_filereadable},
481 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200482 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200483 {"finddir", 1, 3, FEARG_1, f_finddir},
484 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200485#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200486 {"float2nr", 1, 1, FEARG_1, f_float2nr},
487 {"floor", 1, 1, FEARG_1, f_floor},
488 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200489#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200490 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
491 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
492 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
493 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
494 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200495 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200496 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200497 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200498 {"funcref", 1, 3, FEARG_1, f_funcref},
499 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200500 {"garbagecollect", 0, 1, 0, f_garbagecollect},
501 {"get", 2, 3, FEARG_1, f_get},
502 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200503 {"getbufline", 2, 3, FEARG_1, f_getbufline},
504 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
505 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200506 {"getchar", 0, 1, 0, f_getchar},
507 {"getcharmod", 0, 0, 0, f_getcharmod},
508 {"getcharsearch", 0, 0, 0, f_getcharsearch},
509 {"getcmdline", 0, 0, 0, f_getcmdline},
510 {"getcmdpos", 0, 0, 0, f_getcmdpos},
511 {"getcmdtype", 0, 0, 0, f_getcmdtype},
512 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200513 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200514 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200515 {"getcwd", 0, 2, FEARG_1, f_getcwd},
516 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200517 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200518 {"getfperm", 1, 1, FEARG_1, f_getfperm},
519 {"getfsize", 1, 1, FEARG_1, f_getfsize},
520 {"getftime", 1, 1, FEARG_1, f_getftime},
521 {"getftype", 1, 1, FEARG_1, f_getftype},
522 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
523 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200524 {"getloclist", 1, 2, 0, f_getloclist},
525 {"getmatches", 0, 1, 0, f_getmatches},
526 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200527 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200528 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200529 {"getreg", 0, 3, FEARG_1, f_getreg},
530 {"getregtype", 0, 1, FEARG_1, f_getregtype},
531 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
532 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
533 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200534 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
535 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
536 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200537 {"getwinposx", 0, 0, 0, f_getwinposx},
538 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200539 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
540 {"glob", 1, 4, FEARG_1, f_glob},
541 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
542 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200543 {"has", 1, 1, 0, f_has},
544 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200545 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
546 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
547 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
548 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
549 {"histadd", 2, 2, FEARG_2, f_histadd},
550 {"histdel", 1, 2, FEARG_1, f_histdel},
551 {"histget", 1, 2, FEARG_1, f_histget},
552 {"histnr", 1, 1, FEARG_1, f_histnr},
553 {"hlID", 1, 1, FEARG_1, f_hlID},
554 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200555 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200556 {"iconv", 3, 3, FEARG_1, f_iconv},
557 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200558 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200559 {"input", 1, 3, FEARG_1, f_input},
560 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
561 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200562 {"inputrestore", 0, 0, 0, f_inputrestore},
563 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200564 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200565 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200566 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200567 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200568#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200569 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200570#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200571 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200572#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200573 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200574#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200575 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200576#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200577 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
578 {"job_info", 0, 1, FEARG_1, f_job_info},
579 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
580 {"job_start", 1, 2, FEARG_1, f_job_start},
581 {"job_status", 1, 1, FEARG_1, f_job_status},
582 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200583#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200584 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200585 {"js_decode", 1, 1, FEARG_1, f_js_decode},
586 {"js_encode", 1, 1, FEARG_1, f_js_encode},
587 {"json_decode", 1, 1, FEARG_1, f_json_decode},
588 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200589 {"keys", 1, 1, FEARG_1, f_keys},
590 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
591 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200592 {"libcall", 3, 3, FEARG_3, f_libcall},
593 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200594 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200595 {"line2byte", 1, 1, FEARG_1, f_line2byte},
596 {"lispindent", 1, 1, FEARG_1, f_lispindent},
597 {"list2str", 1, 2, FEARG_1, f_list2str},
598 {"listener_add", 1, 2, FEARG_2, f_listener_add},
599 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
600 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200601 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200602#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200603 {"log", 1, 1, FEARG_1, f_log},
604 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200605#endif
606#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200607 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200608#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200609 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200610 {"maparg", 1, 4, FEARG_1, f_maparg},
611 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
612 {"match", 2, 4, FEARG_1, f_match},
613 {"matchadd", 2, 5, FEARG_1, f_matchadd},
614 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
615 {"matcharg", 1, 1, FEARG_1, f_matcharg},
616 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
617 {"matchend", 2, 4, FEARG_1, f_matchend},
618 {"matchlist", 2, 4, FEARG_1, f_matchlist},
619 {"matchstr", 2, 4, FEARG_1, f_matchstr},
620 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200621 {"max", 1, 1, FEARG_1, f_max},
622 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200623 {"mkdir", 1, 3, FEARG_1, f_mkdir},
624 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200625#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200626 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200627#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200628 {"nextnonblank", 1, 1, 0, f_nextnonblank},
629 {"nr2char", 1, 2, 0, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200630 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200631 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200632#ifdef FEAT_PERL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200633 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200634#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200635#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200636 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
637 {"popup_beval", 2, 2, 0, f_popup_beval},
638 {"popup_clear", 0, 0, 0, f_popup_clear},
639 {"popup_close", 1, 2, 0, f_popup_close},
640 {"popup_create", 2, 2, 0, f_popup_create},
641 {"popup_dialog", 2, 2, 0, f_popup_dialog},
642 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
643 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200644 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
645 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200646 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
647 {"popup_getpos", 1, 1, 0, f_popup_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200648 {"popup_hide", 1, 1, 0, f_popup_hide},
649 {"popup_locate", 2, 2, 0, f_popup_locate},
650 {"popup_menu", 2, 2, 0, f_popup_menu},
651 {"popup_move", 2, 2, 0, f_popup_move},
652 {"popup_notification", 2, 2, 0, f_popup_notification},
653 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
654 {"popup_settext", 2, 2, 0, f_popup_settext},
655 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200656#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200657#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200658 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200659#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200660 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200661 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200662#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200663 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
664 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
665 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200666#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100667#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200668 {"prop_add", 3, 3, 0, f_prop_add},
669 {"prop_clear", 1, 3, 0, f_prop_clear},
670 {"prop_list", 1, 2, 0, f_prop_list},
671 {"prop_remove", 1, 3, 0, f_prop_remove},
672 {"prop_type_add", 2, 2, 0, f_prop_type_add},
673 {"prop_type_change", 2, 2, 0, f_prop_type_change},
674 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
675 {"prop_type_get", 1, 2, 0, f_prop_type_get},
676 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100677#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200678 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200679 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200681 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200682#endif
683#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200684 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100686#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200687 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100688#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200689 {"range", 1, 3, 0, f_range},
690 {"readdir", 1, 2, 0, f_readdir},
691 {"readfile", 1, 3, 0, f_readfile},
692 {"reg_executing", 0, 0, 0, f_reg_executing},
693 {"reg_recording", 0, 0, 0, f_reg_recording},
694 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200695#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200696 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200697#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200698 {"reltimestr", 1, 1, 0, f_reltimestr},
699 {"remote_expr", 2, 4, 0, f_remote_expr},
700 {"remote_foreground", 1, 1, 0, f_remote_foreground},
701 {"remote_peek", 1, 2, 0, f_remote_peek},
702 {"remote_read", 1, 2, 0, f_remote_read},
703 {"remote_send", 2, 3, 0, f_remote_send},
704 {"remote_startserver", 1, 1, 0, f_remote_startserver},
705 {"remove", 2, 3, FEARG_1, f_remove},
706 {"rename", 2, 2, 0, f_rename},
707 {"repeat", 2, 2, FEARG_1, f_repeat},
708 {"resolve", 1, 1, 0, f_resolve},
709 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200710#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200711 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200712#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100713#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200714 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100715#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200716 {"screenattr", 2, 2, 0, f_screenattr},
717 {"screenchar", 2, 2, 0, f_screenchar},
718 {"screenchars", 2, 2, 0, f_screenchars},
719 {"screencol", 0, 0, 0, f_screencol},
720 {"screenpos", 3, 3, 0, f_screenpos},
721 {"screenrow", 0, 0, 0, f_screenrow},
722 {"screenstring", 2, 2, 0, f_screenstring},
723 {"search", 1, 4, 0, f_search},
724 {"searchdecl", 1, 3, 0, f_searchdecl},
725 {"searchpair", 3, 7, 0, f_searchpair},
726 {"searchpairpos", 3, 7, 0, f_searchpairpos},
727 {"searchpos", 1, 4, 0, f_searchpos},
728 {"server2client", 2, 2, 0, f_server2client},
729 {"serverlist", 0, 0, 0, f_serverlist},
730 {"setbufline", 3, 3, 0, f_setbufline},
731 {"setbufvar", 3, 3, 0, f_setbufvar},
732 {"setcharsearch", 1, 1, 0, f_setcharsearch},
733 {"setcmdpos", 1, 1, 0, f_setcmdpos},
734 {"setenv", 2, 2, 0, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200735 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200736 {"setline", 2, 2, 0, f_setline},
737 {"setloclist", 2, 4, 0, f_setloclist},
738 {"setmatches", 1, 2, 0, f_setmatches},
739 {"setpos", 2, 2, 0, f_setpos},
740 {"setqflist", 1, 3, 0, f_setqflist},
741 {"setreg", 2, 3, 0, f_setreg},
742 {"settabvar", 3, 3, 0, f_settabvar},
743 {"settabwinvar", 4, 4, 0, f_settabwinvar},
744 {"settagstack", 2, 3, 0, f_settagstack},
745 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200746#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200747 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200748#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200749 {"shellescape", 1, 2, 0, f_shellescape},
750 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100751#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200752 {"sign_define", 1, 2, 0, f_sign_define},
753 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
754 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
755 {"sign_jump", 3, 3, 0, f_sign_jump},
756 {"sign_place", 4, 5, 0, f_sign_place},
757 {"sign_placelist", 1, 1, 0, f_sign_placelist},
758 {"sign_undefine", 0, 1, 0, f_sign_undefine},
759 {"sign_unplace", 1, 2, 0, f_sign_unplace},
760 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100761#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200762 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200763#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200764 {"sin", 1, 1, FEARG_1, f_sin},
765 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200766#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200767 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200768#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200769 {"sound_clear", 0, 0, 0, f_sound_clear},
770 {"sound_playevent", 1, 2, 0, f_sound_playevent},
771 {"sound_playfile", 1, 2, 0, f_sound_playfile},
772 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200773#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200774 {"soundfold", 1, 1, 0, f_soundfold},
775 {"spellbadword", 0, 1, 0, f_spellbadword},
776 {"spellsuggest", 1, 3, 0, f_spellsuggest},
777 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200778#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200779 {"sqrt", 1, 1, FEARG_1, f_sqrt},
780 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200781#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200782 {"str2list", 1, 2, FEARG_1, f_str2list},
783 {"str2nr", 1, 2, 0, f_str2nr},
784 {"strcharpart", 2, 3, 0, f_strcharpart},
785 {"strchars", 1, 2, 0, f_strchars},
786 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200787#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200788 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200789#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200790 {"strgetchar", 2, 2, 0, f_strgetchar},
791 {"stridx", 2, 3, 0, f_stridx},
792 {"string", 1, 1, FEARG_1, f_string},
793 {"strlen", 1, 1, FEARG_1, f_strlen},
794 {"strpart", 2, 3, 0, f_strpart},
795 {"strridx", 2, 3, 0, f_strridx},
796 {"strtrans", 1, 1, FEARG_1, f_strtrans},
797 {"strwidth", 1, 1, FEARG_1, f_strwidth},
798 {"submatch", 1, 2, 0, f_submatch},
799 {"substitute", 4, 4, FEARG_1, f_substitute},
800 {"swapinfo", 1, 1, 0, f_swapinfo},
801 {"swapname", 1, 1, 0, f_swapname},
802 {"synID", 3, 3, 0, f_synID},
803 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
804 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
805 {"synconcealed", 2, 2, 0, f_synconcealed},
806 {"synstack", 2, 2, 0, f_synstack},
807 {"system", 1, 2, FEARG_1, f_system},
808 {"systemlist", 1, 2, FEARG_1, f_systemlist},
809 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
810 {"tabpagenr", 0, 1, 0, f_tabpagenr},
811 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
812 {"tagfiles", 0, 0, 0, f_tagfiles},
813 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200814#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200815 {"tan", 1, 1, FEARG_1, f_tan},
816 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200818 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200819#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200820 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
821 {"term_dumpload", 1, 2, 0, f_term_dumpload},
822 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
823 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200824# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200825 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200826# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200827 {"term_getattr", 2, 2, 0, f_term_getattr},
828 {"term_getcursor", 1, 1, 0, f_term_getcursor},
829 {"term_getjob", 1, 1, 0, f_term_getjob},
830 {"term_getline", 2, 2, 0, f_term_getline},
831 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
832 {"term_getsize", 1, 1, 0, f_term_getsize},
833 {"term_getstatus", 1, 1, 0, f_term_getstatus},
834 {"term_gettitle", 1, 1, 0, f_term_gettitle},
835 {"term_gettty", 1, 2, 0, f_term_gettty},
836 {"term_list", 0, 0, 0, f_term_list},
837 {"term_scrape", 2, 2, 0, f_term_scrape},
838 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200839# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200840 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200841# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200842 {"term_setkill", 2, 2, 0, f_term_setkill},
843 {"term_setrestore", 2, 2, 0, f_term_setrestore},
844 {"term_setsize", 3, 3, 0, f_term_setsize},
845 {"term_start", 1, 2, 0, f_term_start},
846 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200847#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200848 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
849 {"test_autochdir", 0, 0, 0, f_test_autochdir},
850 {"test_feedinput", 1, 1, 0, f_test_feedinput},
851 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
852 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
853 {"test_getvalue", 1, 1, 0, f_test_getvalue},
854 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
855 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200856#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200857 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200858#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200859 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200860#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200861 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200862#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200863 {"test_null_list", 0, 0, 0, f_test_null_list},
864 {"test_null_partial", 0, 0, 0, f_test_null_partial},
865 {"test_null_string", 0, 0, 0, f_test_null_string},
866 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
867 {"test_override", 2, 2, 0, f_test_override},
868 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200869#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200870 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200871#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200872#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200873 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200874#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200875 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200876#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200877 {"timer_info", 0, 1, 0, f_timer_info},
878 {"timer_pause", 2, 2, 0, f_timer_pause},
879 {"timer_start", 2, 3, 0, f_timer_start},
880 {"timer_stop", 1, 1, 0, f_timer_stop},
881 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200882#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200883 {"tolower", 1, 1, 0, f_tolower},
884 {"toupper", 1, 1, 0, f_toupper},
885 {"tr", 3, 3, 0, f_tr},
886 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200887#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200888 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200889#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200890 {"type", 1, 1, FEARG_1, f_type},
891 {"undofile", 1, 1, 0, f_undofile},
892 {"undotree", 0, 0, 0, f_undotree},
893 {"uniq", 1, 3, FEARG_1, f_uniq},
894 {"values", 1, 1, FEARG_1, f_values},
895 {"virtcol", 1, 1, 0, f_virtcol},
896 {"visualmode", 0, 1, 0, f_visualmode},
897 {"wildmenumode", 0, 0, 0, f_wildmenumode},
898 {"win_execute", 2, 3, 0, f_win_execute},
899 {"win_findbuf", 1, 1, 0, f_win_findbuf},
900 {"win_getid", 0, 2, 0, f_win_getid},
901 {"win_gotoid", 1, 1, 0, f_win_gotoid},
902 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
903 {"win_id2win", 1, 1, 0, f_win_id2win},
904 {"win_screenpos", 1, 1, 0, f_win_screenpos},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200905 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200906 {"wincol", 0, 0, 0, f_wincol},
907 {"winheight", 1, 1, 0, f_winheight},
908 {"winlayout", 0, 1, 0, f_winlayout},
909 {"winline", 0, 0, 0, f_winline},
910 {"winnr", 0, 1, 0, f_winnr},
911 {"winrestcmd", 0, 0, 0, f_winrestcmd},
912 {"winrestview", 1, 1, 0, f_winrestview},
913 {"winsaveview", 0, 0, 0, f_winsaveview},
914 {"winwidth", 1, 1, 0, f_winwidth},
915 {"wordcount", 0, 0, 0, f_wordcount},
916 {"writefile", 2, 3, 0, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200917 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200918};
919
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200920/*
921 * Function given to ExpandGeneric() to obtain the list of internal
922 * or user defined function names.
923 */
924 char_u *
925get_function_name(expand_T *xp, int idx)
926{
927 static int intidx = -1;
928 char_u *name;
929
930 if (idx == 0)
931 intidx = -1;
932 if (intidx < 0)
933 {
934 name = get_user_func_name(xp, idx);
935 if (name != NULL)
936 return name;
937 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200938 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200939 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200940 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200941 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200942 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200943 STRCAT(IObuff, ")");
944 return IObuff;
945 }
946
947 return NULL;
948}
949
950/*
951 * Function given to ExpandGeneric() to obtain the list of internal or
952 * user defined variable or function names.
953 */
954 char_u *
955get_expr_name(expand_T *xp, int idx)
956{
957 static int intidx = -1;
958 char_u *name;
959
960 if (idx == 0)
961 intidx = -1;
962 if (intidx < 0)
963 {
964 name = get_function_name(xp, idx);
965 if (name != NULL)
966 return name;
967 }
968 return get_user_var_name(xp, ++intidx);
969}
970
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200971/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200972 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200973 * Return index, or -1 if not found
974 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200975 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200976find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200977{
978 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200979 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200980 int cmp;
981 int x;
982
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200983 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +0200984
985 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200986 while (first <= last)
987 {
988 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200989 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200990 if (cmp < 0)
991 last = x - 1;
992 else if (cmp > 0)
993 first = x + 1;
994 else
995 return x;
996 }
997 return -1;
998}
999
1000 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001001has_internal_func(char_u *name)
1002{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001003 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001004}
1005
1006 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001007call_internal_func(
1008 char_u *name,
1009 int argcount,
1010 typval_T *argvars,
1011 typval_T *rettv)
1012{
1013 int i;
1014
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001015 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001016 if (i < 0)
1017 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001018 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001020 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001021 return ERROR_TOOMANY;
1022 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001023 global_functions[i].f_func(argvars, rettv);
1024 return ERROR_NONE;
1025}
1026
1027/*
1028 * Invoke a method for base->method().
1029 */
1030 int
1031call_internal_method(
1032 char_u *name,
1033 int argcount,
1034 typval_T *argvars,
1035 typval_T *rettv,
1036 typval_T *basetv)
1037{
1038 int i;
1039 int fi;
1040 typval_T argv[MAX_FUNC_ARGS + 1];
1041
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001042 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001043 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001044 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001045 if (global_functions[fi].f_argtype == 0)
1046 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001047 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001048 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001049 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001050 return ERROR_TOOMANY;
1051
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001052 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001053 {
1054 // base value goes last
1055 for (i = 0; i < argcount; ++i)
1056 argv[i] = argvars[i];
1057 argv[argcount] = *basetv;
1058 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001059 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001060 {
1061 // base value goes second
1062 argv[0] = argvars[0];
1063 argv[1] = *basetv;
1064 for (i = 1; i < argcount; ++i)
1065 argv[i + 1] = argvars[i];
1066 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001067 else if (global_functions[fi].f_argtype == FEARG_3)
1068 {
1069 // base value goes third
1070 argv[0] = argvars[0];
1071 argv[1] = argvars[1];
1072 argv[2] = *basetv;
1073 for (i = 2; i < argcount; ++i)
1074 argv[i + 1] = argvars[i];
1075 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001076 else
1077 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001078 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001079 argv[0] = *basetv;
1080 for (i = 0; i < argcount; ++i)
1081 argv[i + 1] = argvars[i];
1082 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001083 argv[argcount + 1].v_type = VAR_UNKNOWN;
1084
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001085 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001086 return ERROR_NONE;
1087}
1088
1089/*
1090 * Return TRUE for a non-zero Number and a non-empty String.
1091 */
1092 static int
1093non_zero_arg(typval_T *argvars)
1094{
1095 return ((argvars[0].v_type == VAR_NUMBER
1096 && argvars[0].vval.v_number != 0)
1097 || (argvars[0].v_type == VAR_SPECIAL
1098 && argvars[0].vval.v_number == VVAL_TRUE)
1099 || (argvars[0].v_type == VAR_STRING
1100 && argvars[0].vval.v_string != NULL
1101 && *argvars[0].vval.v_string != NUL));
1102}
1103
1104/*
1105 * Get the lnum from the first argument.
1106 * Also accepts ".", "$", etc., but that only works for the current buffer.
1107 * Returns -1 on error.
1108 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001109 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001110tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001111{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001112 linenr_T lnum;
1113
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001114 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001115 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001116 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001117 int fnum;
1118 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1119
1120 if (fp != NULL)
1121 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001122 }
1123 return lnum;
1124}
1125
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001126/*
1127 * Get the lnum from the first argument.
1128 * Also accepts "$", then "buf" is used.
1129 * Returns 0 on error.
1130 */
1131 static linenr_T
1132tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1133{
1134 if (argvars[0].v_type == VAR_STRING
1135 && argvars[0].vval.v_string != NULL
1136 && argvars[0].vval.v_string[0] == '$'
1137 && buf != NULL)
1138 return buf->b_ml.ml_line_count;
1139 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1140}
1141
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001142#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001143/*
1144 * Get the float value of "argvars[0]" into "f".
1145 * Returns FAIL when the argument is not a Number or Float.
1146 */
1147 static int
1148get_float_arg(typval_T *argvars, float_T *f)
1149{
1150 if (argvars[0].v_type == VAR_FLOAT)
1151 {
1152 *f = argvars[0].vval.v_float;
1153 return OK;
1154 }
1155 if (argvars[0].v_type == VAR_NUMBER)
1156 {
1157 *f = (float_T)argvars[0].vval.v_number;
1158 return OK;
1159 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001160 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001161 return FAIL;
1162}
1163
1164/*
1165 * "abs(expr)" function
1166 */
1167 static void
1168f_abs(typval_T *argvars, typval_T *rettv)
1169{
1170 if (argvars[0].v_type == VAR_FLOAT)
1171 {
1172 rettv->v_type = VAR_FLOAT;
1173 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1174 }
1175 else
1176 {
1177 varnumber_T n;
1178 int error = FALSE;
1179
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001180 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001181 if (error)
1182 rettv->vval.v_number = -1;
1183 else if (n > 0)
1184 rettv->vval.v_number = n;
1185 else
1186 rettv->vval.v_number = -n;
1187 }
1188}
1189
1190/*
1191 * "acos()" function
1192 */
1193 static void
1194f_acos(typval_T *argvars, typval_T *rettv)
1195{
1196 float_T f = 0.0;
1197
1198 rettv->v_type = VAR_FLOAT;
1199 if (get_float_arg(argvars, &f) == OK)
1200 rettv->vval.v_float = acos(f);
1201 else
1202 rettv->vval.v_float = 0.0;
1203}
1204#endif
1205
1206/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001207 * "and(expr, expr)" function
1208 */
1209 static void
1210f_and(typval_T *argvars, typval_T *rettv)
1211{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001212 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1213 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001214}
1215
1216/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001217 * If there is a window for "curbuf", make it the current window.
1218 */
1219 static void
1220find_win_for_curbuf(void)
1221{
1222 wininfo_T *wip;
1223
1224 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1225 {
1226 if (wip->wi_win != NULL)
1227 {
1228 curwin = wip->wi_win;
1229 break;
1230 }
1231 }
1232}
1233
1234/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001235 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001236 */
1237 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001238set_buffer_lines(
1239 buf_T *buf,
1240 linenr_T lnum_arg,
1241 int append,
1242 typval_T *lines,
1243 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001244{
Bram Moolenaarca851592018-06-06 21:04:07 +02001245 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1246 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001247 list_T *l = NULL;
1248 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001249 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001250 linenr_T append_lnum;
1251 buf_T *curbuf_save = NULL;
1252 win_T *curwin_save = NULL;
1253 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001254
Bram Moolenaarca851592018-06-06 21:04:07 +02001255 /* When using the current buffer ml_mfp will be set if needed. Useful when
1256 * setline() is used on startup. For other buffers the buffer must be
1257 * loaded. */
1258 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001259 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001260 rettv->vval.v_number = 1; /* FAIL */
1261 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001262 }
1263
Bram Moolenaarca851592018-06-06 21:04:07 +02001264 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001265 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001266 curbuf_save = curbuf;
1267 curwin_save = curwin;
1268 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001269 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001270 }
1271
1272 if (append)
1273 // appendbufline() uses the line number below which we insert
1274 append_lnum = lnum - 1;
1275 else
1276 // setbufline() uses the line number above which we insert, we only
1277 // append if it's below the last line
1278 append_lnum = curbuf->b_ml.ml_line_count;
1279
1280 if (lines->v_type == VAR_LIST)
1281 {
1282 l = lines->vval.v_list;
1283 li = l->lv_first;
1284 }
1285 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001286 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001287
1288 /* default result is zero == OK */
1289 for (;;)
1290 {
1291 if (l != NULL)
1292 {
1293 /* list argument, get next string */
1294 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001295 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001296 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001297 li = li->li_next;
1298 }
1299
Bram Moolenaarca851592018-06-06 21:04:07 +02001300 rettv->vval.v_number = 1; /* FAIL */
1301 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1302 break;
1303
1304 /* When coming here from Insert mode, sync undo, so that this can be
1305 * undone separately from what was previously inserted. */
1306 if (u_sync_once == 2)
1307 {
1308 u_sync_once = 1; /* notify that u_sync() was called */
1309 u_sync(TRUE);
1310 }
1311
1312 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1313 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001314 // Existing line, replace it.
1315 // Removes any existing text properties.
1316 if (u_savesub(lnum) == OK && ml_replace_len(
1317 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001318 {
1319 changed_bytes(lnum, 0);
1320 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1321 check_cursor_col();
1322 rettv->vval.v_number = 0; /* OK */
1323 }
1324 }
1325 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1326 {
1327 /* append the line */
1328 ++added;
1329 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1330 rettv->vval.v_number = 0; /* OK */
1331 }
1332
1333 if (l == NULL) /* only one string argument */
1334 break;
1335 ++lnum;
1336 }
1337
1338 if (added > 0)
1339 {
1340 win_T *wp;
1341 tabpage_T *tp;
1342
1343 appended_lines_mark(append_lnum, added);
Bram Moolenaard2007022019-08-27 21:56:06 +02001344
1345 // Only adjust the cursor for buffers other than the current, unless it
1346 // is the current window. For curbuf and other windows it has been
1347 // done in mark_adjust_internal().
Bram Moolenaarca851592018-06-06 21:04:07 +02001348 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaard2007022019-08-27 21:56:06 +02001349 if (wp->w_buffer == buf
1350 && (wp->w_buffer != curbuf || wp == curwin)
1351 && wp->w_cursor.lnum > append_lnum)
Bram Moolenaarca851592018-06-06 21:04:07 +02001352 wp->w_cursor.lnum += added;
1353 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001354 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001355 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001356
1357 if (!is_curbuf)
1358 {
1359 curbuf = curbuf_save;
1360 curwin = curwin_save;
1361 }
1362}
1363
1364/*
1365 * "append(lnum, string/list)" function
1366 */
1367 static void
1368f_append(typval_T *argvars, typval_T *rettv)
1369{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001370 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001371
1372 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1373}
1374
1375/*
1376 * "appendbufline(buf, lnum, string/list)" function
1377 */
1378 static void
1379f_appendbufline(typval_T *argvars, typval_T *rettv)
1380{
1381 linenr_T lnum;
1382 buf_T *buf;
1383
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001384 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001385 if (buf == NULL)
1386 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001387 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001388 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001389 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001390 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1391 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001392}
1393
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001394#ifdef FEAT_FLOAT
1395/*
1396 * "asin()" function
1397 */
1398 static void
1399f_asin(typval_T *argvars, typval_T *rettv)
1400{
1401 float_T f = 0.0;
1402
1403 rettv->v_type = VAR_FLOAT;
1404 if (get_float_arg(argvars, &f) == OK)
1405 rettv->vval.v_float = asin(f);
1406 else
1407 rettv->vval.v_float = 0.0;
1408}
1409
1410/*
1411 * "atan()" function
1412 */
1413 static void
1414f_atan(typval_T *argvars, typval_T *rettv)
1415{
1416 float_T f = 0.0;
1417
1418 rettv->v_type = VAR_FLOAT;
1419 if (get_float_arg(argvars, &f) == OK)
1420 rettv->vval.v_float = atan(f);
1421 else
1422 rettv->vval.v_float = 0.0;
1423}
1424
1425/*
1426 * "atan2()" function
1427 */
1428 static void
1429f_atan2(typval_T *argvars, typval_T *rettv)
1430{
1431 float_T fx = 0.0, fy = 0.0;
1432
1433 rettv->v_type = VAR_FLOAT;
1434 if (get_float_arg(argvars, &fx) == OK
1435 && get_float_arg(&argvars[1], &fy) == OK)
1436 rettv->vval.v_float = atan2(fx, fy);
1437 else
1438 rettv->vval.v_float = 0.0;
1439}
1440#endif
1441
1442/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001443 * "balloon_show()" function
1444 */
1445#ifdef FEAT_BEVAL
1446 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001447f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1448{
1449 rettv->v_type = VAR_STRING;
1450 if (balloonEval != NULL)
1451 {
1452 if (balloonEval->msg == NULL)
1453 rettv->vval.v_string = NULL;
1454 else
1455 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1456 }
1457}
1458
1459 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001460f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1461{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001462 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001463 {
1464 if (argvars[0].v_type == VAR_LIST
1465# ifdef FEAT_GUI
1466 && !gui.in_use
1467# endif
1468 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001469 {
1470 list_T *l = argvars[0].vval.v_list;
1471
1472 // empty list removes the balloon
1473 post_balloon(balloonEval, NULL,
1474 l == NULL || l->lv_len == 0 ? NULL : l);
1475 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001476 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001477 {
1478 char_u *mesg = tv_get_string_chk(&argvars[0]);
1479
1480 if (mesg != NULL)
1481 // empty string removes the balloon
1482 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1483 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001484 }
1485}
1486
Bram Moolenaar669a8282017-11-19 20:13:05 +01001487# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001488 static void
1489f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1490{
1491 if (rettv_list_alloc(rettv) == OK)
1492 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001493 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001494
1495 if (msg != NULL)
1496 {
1497 pumitem_T *array;
1498 int size = split_message(msg, &array);
1499 int i;
1500
1501 /* Skip the first and last item, they are always empty. */
1502 for (i = 1; i < size - 1; ++i)
1503 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001504 while (size > 0)
1505 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001506 vim_free(array);
1507 }
1508 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001509}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001510# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001511#endif
1512
1513/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001514 * Find a buffer by number or exact name.
1515 */
1516 static buf_T *
1517find_buffer(typval_T *avar)
1518{
1519 buf_T *buf = NULL;
1520
1521 if (avar->v_type == VAR_NUMBER)
1522 buf = buflist_findnr((int)avar->vval.v_number);
1523 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1524 {
1525 buf = buflist_findname_exp(avar->vval.v_string);
1526 if (buf == NULL)
1527 {
1528 /* No full path name match, try a match with a URL or a "nofile"
1529 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001530 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001531 if (buf->b_fname != NULL
1532 && (path_with_url(buf->b_fname)
1533#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001534 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001535#endif
1536 )
1537 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1538 break;
1539 }
1540 }
1541 return buf;
1542}
1543
1544/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001545 * "bufadd(expr)" function
1546 */
1547 static void
1548f_bufadd(typval_T *argvars, typval_T *rettv)
1549{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001550 char_u *name = tv_get_string(&argvars[0]);
1551
1552 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001553}
1554
1555/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001556 * "bufexists(expr)" function
1557 */
1558 static void
1559f_bufexists(typval_T *argvars, typval_T *rettv)
1560{
1561 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1562}
1563
1564/*
1565 * "buflisted(expr)" function
1566 */
1567 static void
1568f_buflisted(typval_T *argvars, typval_T *rettv)
1569{
1570 buf_T *buf;
1571
1572 buf = find_buffer(&argvars[0]);
1573 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1574}
1575
1576/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001577 * "bufload(expr)" function
1578 */
1579 static void
1580f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1581{
1582 buf_T *buf = get_buf_arg(&argvars[0]);
1583
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001584 if (buf != NULL)
1585 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001586}
1587
1588/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001589 * "bufloaded(expr)" function
1590 */
1591 static void
1592f_bufloaded(typval_T *argvars, typval_T *rettv)
1593{
1594 buf_T *buf;
1595
1596 buf = find_buffer(&argvars[0]);
1597 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1598}
1599
1600 buf_T *
1601buflist_find_by_name(char_u *name, int curtab_only)
1602{
1603 int save_magic;
1604 char_u *save_cpo;
1605 buf_T *buf;
1606
1607 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1608 save_magic = p_magic;
1609 p_magic = TRUE;
1610 save_cpo = p_cpo;
1611 p_cpo = (char_u *)"";
1612
1613 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1614 TRUE, FALSE, curtab_only));
1615
1616 p_magic = save_magic;
1617 p_cpo = save_cpo;
1618 return buf;
1619}
1620
1621/*
1622 * Get buffer by number or pattern.
1623 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001624 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001625tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001626{
1627 char_u *name = tv->vval.v_string;
1628 buf_T *buf;
1629
1630 if (tv->v_type == VAR_NUMBER)
1631 return buflist_findnr((int)tv->vval.v_number);
1632 if (tv->v_type != VAR_STRING)
1633 return NULL;
1634 if (name == NULL || *name == NUL)
1635 return curbuf;
1636 if (name[0] == '$' && name[1] == NUL)
1637 return lastbuf;
1638
1639 buf = buflist_find_by_name(name, curtab_only);
1640
1641 /* If not found, try expanding the name, like done for bufexists(). */
1642 if (buf == NULL)
1643 buf = find_buffer(tv);
1644
1645 return buf;
1646}
1647
1648/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001649 * Get the buffer from "arg" and give an error and return NULL if it is not
1650 * valid.
1651 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001652 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001653get_buf_arg(typval_T *arg)
1654{
1655 buf_T *buf;
1656
1657 ++emsg_off;
1658 buf = tv_get_buf(arg, FALSE);
1659 --emsg_off;
1660 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001661 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001662 return buf;
1663}
1664
1665/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001666 * "bufname(expr)" function
1667 */
1668 static void
1669f_bufname(typval_T *argvars, typval_T *rettv)
1670{
1671 buf_T *buf;
1672
Bram Moolenaara8eee212019-08-24 22:14:58 +02001673 if (argvars[0].v_type == VAR_UNKNOWN)
1674 buf = curbuf;
1675 else
1676 {
1677 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1678 ++emsg_off;
1679 buf = tv_get_buf(&argvars[0], FALSE);
1680 --emsg_off;
1681 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001682 rettv->v_type = VAR_STRING;
1683 if (buf != NULL && buf->b_fname != NULL)
1684 rettv->vval.v_string = vim_strsave(buf->b_fname);
1685 else
1686 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001687}
1688
1689/*
1690 * "bufnr(expr)" function
1691 */
1692 static void
1693f_bufnr(typval_T *argvars, typval_T *rettv)
1694{
1695 buf_T *buf;
1696 int error = FALSE;
1697 char_u *name;
1698
Bram Moolenaara8eee212019-08-24 22:14:58 +02001699 if (argvars[0].v_type == VAR_UNKNOWN)
1700 buf = curbuf;
1701 else
1702 {
1703 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1704 ++emsg_off;
1705 buf = tv_get_buf(&argvars[0], FALSE);
1706 --emsg_off;
1707 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001708
Bram Moolenaara8eee212019-08-24 22:14:58 +02001709 // If the buffer isn't found and the second argument is not zero create a
1710 // new buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001711 if (buf == NULL
1712 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001713 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001714 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001715 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001716 && !error)
1717 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1718
1719 if (buf != NULL)
1720 rettv->vval.v_number = buf->b_fnum;
1721 else
1722 rettv->vval.v_number = -1;
1723}
1724
1725 static void
1726buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1727{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001728 win_T *wp;
1729 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001730 buf_T *buf;
1731
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001732 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001733 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001734 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001735 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001736 {
1737 ++winnr;
1738 if (wp->w_buffer == buf)
1739 break;
1740 }
1741 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001742 --emsg_off;
1743}
1744
1745/*
1746 * "bufwinid(nr)" function
1747 */
1748 static void
1749f_bufwinid(typval_T *argvars, typval_T *rettv)
1750{
1751 buf_win_common(argvars, rettv, FALSE);
1752}
1753
1754/*
1755 * "bufwinnr(nr)" function
1756 */
1757 static void
1758f_bufwinnr(typval_T *argvars, typval_T *rettv)
1759{
1760 buf_win_common(argvars, rettv, TRUE);
1761}
1762
1763/*
1764 * "byte2line(byte)" function
1765 */
1766 static void
1767f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1768{
1769#ifndef FEAT_BYTEOFF
1770 rettv->vval.v_number = -1;
1771#else
1772 long boff = 0;
1773
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001774 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001775 if (boff < 0)
1776 rettv->vval.v_number = -1;
1777 else
1778 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1779 (linenr_T)0, &boff);
1780#endif
1781}
1782
1783 static void
1784byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1785{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001786 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001787 char_u *str;
1788 varnumber_T idx;
1789
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001790 str = tv_get_string_chk(&argvars[0]);
1791 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001792 rettv->vval.v_number = -1;
1793 if (str == NULL || idx < 0)
1794 return;
1795
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001796 t = str;
1797 for ( ; idx > 0; idx--)
1798 {
1799 if (*t == NUL) /* EOL reached */
1800 return;
1801 if (enc_utf8 && comp)
1802 t += utf_ptr2len(t);
1803 else
1804 t += (*mb_ptr2len)(t);
1805 }
1806 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001807}
1808
1809/*
1810 * "byteidx()" function
1811 */
1812 static void
1813f_byteidx(typval_T *argvars, typval_T *rettv)
1814{
1815 byteidx(argvars, rettv, FALSE);
1816}
1817
1818/*
1819 * "byteidxcomp()" function
1820 */
1821 static void
1822f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1823{
1824 byteidx(argvars, rettv, TRUE);
1825}
1826
1827/*
1828 * "call(func, arglist [, dict])" function
1829 */
1830 static void
1831f_call(typval_T *argvars, typval_T *rettv)
1832{
1833 char_u *func;
1834 partial_T *partial = NULL;
1835 dict_T *selfdict = NULL;
1836
1837 if (argvars[1].v_type != VAR_LIST)
1838 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001839 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001840 return;
1841 }
1842 if (argvars[1].vval.v_list == NULL)
1843 return;
1844
1845 if (argvars[0].v_type == VAR_FUNC)
1846 func = argvars[0].vval.v_string;
1847 else if (argvars[0].v_type == VAR_PARTIAL)
1848 {
1849 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001850 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001851 }
1852 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001853 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001854 if (*func == NUL)
1855 return; /* type error or empty name */
1856
1857 if (argvars[2].v_type != VAR_UNKNOWN)
1858 {
1859 if (argvars[2].v_type != VAR_DICT)
1860 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001861 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001862 return;
1863 }
1864 selfdict = argvars[2].vval.v_dict;
1865 }
1866
1867 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
1868}
1869
1870#ifdef FEAT_FLOAT
1871/*
1872 * "ceil({float})" function
1873 */
1874 static void
1875f_ceil(typval_T *argvars, typval_T *rettv)
1876{
1877 float_T f = 0.0;
1878
1879 rettv->v_type = VAR_FLOAT;
1880 if (get_float_arg(argvars, &f) == OK)
1881 rettv->vval.v_float = ceil(f);
1882 else
1883 rettv->vval.v_float = 0.0;
1884}
1885#endif
1886
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001887/*
1888 * "changenr()" function
1889 */
1890 static void
1891f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
1892{
1893 rettv->vval.v_number = curbuf->b_u_seq_cur;
1894}
1895
1896/*
1897 * "char2nr(string)" function
1898 */
1899 static void
1900f_char2nr(typval_T *argvars, typval_T *rettv)
1901{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001902 if (has_mbyte)
1903 {
1904 int utf8 = 0;
1905
1906 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001907 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001908
1909 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01001910 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001911 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001912 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001913 }
1914 else
Bram Moolenaar13505972019-01-24 15:04:48 +01001915 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001916}
1917
1918/*
1919 * "cindent(lnum)" function
1920 */
1921 static void
1922f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1923{
1924#ifdef FEAT_CINDENT
1925 pos_T pos;
1926 linenr_T lnum;
1927
1928 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001929 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001930 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1931 {
1932 curwin->w_cursor.lnum = lnum;
1933 rettv->vval.v_number = get_c_indent();
1934 curwin->w_cursor = pos;
1935 }
1936 else
1937#endif
1938 rettv->vval.v_number = -1;
1939}
1940
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02001941 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01001942get_optional_window(typval_T *argvars, int idx)
1943{
1944 win_T *win = curwin;
1945
1946 if (argvars[idx].v_type != VAR_UNKNOWN)
1947 {
1948 win = find_win_by_nr_or_id(&argvars[idx]);
1949 if (win == NULL)
1950 {
1951 emsg(_(e_invalwindow));
1952 return NULL;
1953 }
1954 }
1955 return win;
1956}
1957
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001958/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001959 * "col(string)" function
1960 */
1961 static void
1962f_col(typval_T *argvars, typval_T *rettv)
1963{
1964 colnr_T col = 0;
1965 pos_T *fp;
1966 int fnum = curbuf->b_fnum;
1967
1968 fp = var2fpos(&argvars[0], FALSE, &fnum);
1969 if (fp != NULL && fnum == curbuf->b_fnum)
1970 {
1971 if (fp->col == MAXCOL)
1972 {
1973 /* '> can be MAXCOL, get the length of the line then */
1974 if (fp->lnum <= curbuf->b_ml.ml_line_count)
1975 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
1976 else
1977 col = MAXCOL;
1978 }
1979 else
1980 {
1981 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001982 /* col(".") when the cursor is on the NUL at the end of the line
1983 * because of "coladd" can be seen as an extra column. */
1984 if (virtual_active() && fp == &curwin->w_cursor)
1985 {
1986 char_u *p = ml_get_cursor();
1987
1988 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
1989 curwin->w_virtcol - curwin->w_cursor.coladd))
1990 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991 int l;
1992
1993 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
1994 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001995 }
1996 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001997 }
1998 }
1999 rettv->vval.v_number = col;
2000}
2001
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002002/*
2003 * "confirm(message, buttons[, default [, type]])" function
2004 */
2005 static void
2006f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2007{
2008#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2009 char_u *message;
2010 char_u *buttons = NULL;
2011 char_u buf[NUMBUFLEN];
2012 char_u buf2[NUMBUFLEN];
2013 int def = 1;
2014 int type = VIM_GENERIC;
2015 char_u *typestr;
2016 int error = FALSE;
2017
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002018 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002019 if (message == NULL)
2020 error = TRUE;
2021 if (argvars[1].v_type != VAR_UNKNOWN)
2022 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002023 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002024 if (buttons == NULL)
2025 error = TRUE;
2026 if (argvars[2].v_type != VAR_UNKNOWN)
2027 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002028 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002029 if (argvars[3].v_type != VAR_UNKNOWN)
2030 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002031 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002032 if (typestr == NULL)
2033 error = TRUE;
2034 else
2035 {
2036 switch (TOUPPER_ASC(*typestr))
2037 {
2038 case 'E': type = VIM_ERROR; break;
2039 case 'Q': type = VIM_QUESTION; break;
2040 case 'I': type = VIM_INFO; break;
2041 case 'W': type = VIM_WARNING; break;
2042 case 'G': type = VIM_GENERIC; break;
2043 }
2044 }
2045 }
2046 }
2047 }
2048
2049 if (buttons == NULL || *buttons == NUL)
2050 buttons = (char_u *)_("&Ok");
2051
2052 if (!error)
2053 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2054 def, NULL, FALSE);
2055#endif
2056}
2057
2058/*
2059 * "copy()" function
2060 */
2061 static void
2062f_copy(typval_T *argvars, typval_T *rettv)
2063{
2064 item_copy(&argvars[0], rettv, FALSE, 0);
2065}
2066
2067#ifdef FEAT_FLOAT
2068/*
2069 * "cos()" function
2070 */
2071 static void
2072f_cos(typval_T *argvars, typval_T *rettv)
2073{
2074 float_T f = 0.0;
2075
2076 rettv->v_type = VAR_FLOAT;
2077 if (get_float_arg(argvars, &f) == OK)
2078 rettv->vval.v_float = cos(f);
2079 else
2080 rettv->vval.v_float = 0.0;
2081}
2082
2083/*
2084 * "cosh()" function
2085 */
2086 static void
2087f_cosh(typval_T *argvars, typval_T *rettv)
2088{
2089 float_T f = 0.0;
2090
2091 rettv->v_type = VAR_FLOAT;
2092 if (get_float_arg(argvars, &f) == OK)
2093 rettv->vval.v_float = cosh(f);
2094 else
2095 rettv->vval.v_float = 0.0;
2096}
2097#endif
2098
2099/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002100 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2101 *
2102 * Checks the existence of a cscope connection.
2103 */
2104 static void
2105f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2106{
2107#ifdef FEAT_CSCOPE
2108 int num = 0;
2109 char_u *dbpath = NULL;
2110 char_u *prepend = NULL;
2111 char_u buf[NUMBUFLEN];
2112
2113 if (argvars[0].v_type != VAR_UNKNOWN
2114 && argvars[1].v_type != VAR_UNKNOWN)
2115 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002116 num = (int)tv_get_number(&argvars[0]);
2117 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002118 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002119 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002120 }
2121
2122 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2123#endif
2124}
2125
2126/*
2127 * "cursor(lnum, col)" function, or
2128 * "cursor(list)"
2129 *
2130 * Moves the cursor to the specified line and column.
2131 * Returns 0 when the position could be set, -1 otherwise.
2132 */
2133 static void
2134f_cursor(typval_T *argvars, typval_T *rettv)
2135{
2136 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002137 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138 int set_curswant = TRUE;
2139
2140 rettv->vval.v_number = -1;
2141 if (argvars[1].v_type == VAR_UNKNOWN)
2142 {
2143 pos_T pos;
2144 colnr_T curswant = -1;
2145
2146 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2147 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002148 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002149 return;
2150 }
2151 line = pos.lnum;
2152 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002153 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 if (curswant >= 0)
2155 {
2156 curwin->w_curswant = curswant - 1;
2157 set_curswant = FALSE;
2158 }
2159 }
2160 else
2161 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002162 line = tv_get_lnum(argvars);
2163 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002164 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002165 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002166 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002167 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002168 return; /* type error; errmsg already given */
2169 if (line > 0)
2170 curwin->w_cursor.lnum = line;
2171 if (col > 0)
2172 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002173 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002174
2175 /* Make sure the cursor is in a valid position. */
2176 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177 /* Correct cursor for multi-byte character. */
2178 if (has_mbyte)
2179 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002180
2181 curwin->w_set_curswant = set_curswant;
2182 rettv->vval.v_number = 0;
2183}
2184
Bram Moolenaar4f974752019-02-17 17:44:42 +01002185#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002186/*
2187 * "debugbreak()" function
2188 */
2189 static void
2190f_debugbreak(typval_T *argvars, typval_T *rettv)
2191{
2192 int pid;
2193
2194 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002195 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002196 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002197 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002198 else
2199 {
2200 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2201
2202 if (hProcess != NULL)
2203 {
2204 DebugBreakProcess(hProcess);
2205 CloseHandle(hProcess);
2206 rettv->vval.v_number = OK;
2207 }
2208 }
2209}
2210#endif
2211
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002212/*
2213 * "deepcopy()" function
2214 */
2215 static void
2216f_deepcopy(typval_T *argvars, typval_T *rettv)
2217{
2218 int noref = 0;
2219 int copyID;
2220
2221 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002222 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002223 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002224 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002225 else
2226 {
2227 copyID = get_copyID();
2228 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2229 }
2230}
2231
2232/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002233 * "deletebufline()" function
2234 */
2235 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002236f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002237{
2238 buf_T *buf;
2239 linenr_T first, last;
2240 linenr_T lnum;
2241 long count;
2242 int is_curbuf;
2243 buf_T *curbuf_save = NULL;
2244 win_T *curwin_save = NULL;
2245 tabpage_T *tp;
2246 win_T *wp;
2247
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002248 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002249 if (buf == NULL)
2250 {
2251 rettv->vval.v_number = 1; /* FAIL */
2252 return;
2253 }
2254 is_curbuf = buf == curbuf;
2255
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002256 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002257 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002258 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002259 else
2260 last = first;
2261
2262 if (buf->b_ml.ml_mfp == NULL || first < 1
2263 || first > buf->b_ml.ml_line_count || last < first)
2264 {
2265 rettv->vval.v_number = 1; /* FAIL */
2266 return;
2267 }
2268
2269 if (!is_curbuf)
2270 {
2271 curbuf_save = curbuf;
2272 curwin_save = curwin;
2273 curbuf = buf;
2274 find_win_for_curbuf();
2275 }
2276 if (last > curbuf->b_ml.ml_line_count)
2277 last = curbuf->b_ml.ml_line_count;
2278 count = last - first + 1;
2279
2280 // When coming here from Insert mode, sync undo, so that this can be
2281 // undone separately from what was previously inserted.
2282 if (u_sync_once == 2)
2283 {
2284 u_sync_once = 1; // notify that u_sync() was called
2285 u_sync(TRUE);
2286 }
2287
2288 if (u_save(first - 1, last + 1) == FAIL)
2289 {
2290 rettv->vval.v_number = 1; /* FAIL */
2291 return;
2292 }
2293
2294 for (lnum = first; lnum <= last; ++lnum)
2295 ml_delete(first, TRUE);
2296
2297 FOR_ALL_TAB_WINDOWS(tp, wp)
2298 if (wp->w_buffer == buf)
2299 {
2300 if (wp->w_cursor.lnum > last)
2301 wp->w_cursor.lnum -= count;
2302 else if (wp->w_cursor.lnum> first)
2303 wp->w_cursor.lnum = first;
2304 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2305 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2306 }
2307 check_cursor_col();
2308 deleted_lines_mark(first, count);
2309
2310 if (!is_curbuf)
2311 {
2312 curbuf = curbuf_save;
2313 curwin = curwin_save;
2314 }
2315}
2316
2317/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002318 * "did_filetype()" function
2319 */
2320 static void
2321f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2322{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002323 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002324}
2325
2326/*
2327 * "diff_filler()" function
2328 */
2329 static void
2330f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2331{
2332#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002333 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002334#endif
2335}
2336
2337/*
2338 * "diff_hlID()" function
2339 */
2340 static void
2341f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2342{
2343#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002344 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002345 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002346 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002347 static int fnum = 0;
2348 static int change_start = 0;
2349 static int change_end = 0;
2350 static hlf_T hlID = (hlf_T)0;
2351 int filler_lines;
2352 int col;
2353
2354 if (lnum < 0) /* ignore type error in {lnum} arg */
2355 lnum = 0;
2356 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002357 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002358 || fnum != curbuf->b_fnum)
2359 {
2360 /* New line, buffer, change: need to get the values. */
2361 filler_lines = diff_check(curwin, lnum);
2362 if (filler_lines < 0)
2363 {
2364 if (filler_lines == -1)
2365 {
2366 change_start = MAXCOL;
2367 change_end = -1;
2368 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2369 hlID = HLF_ADD; /* added line */
2370 else
2371 hlID = HLF_CHD; /* changed line */
2372 }
2373 else
2374 hlID = HLF_ADD; /* added line */
2375 }
2376 else
2377 hlID = (hlf_T)0;
2378 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002379 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002380 fnum = curbuf->b_fnum;
2381 }
2382
2383 if (hlID == HLF_CHD || hlID == HLF_TXD)
2384 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002385 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002386 if (col >= change_start && col <= change_end)
2387 hlID = HLF_TXD; /* changed text */
2388 else
2389 hlID = HLF_CHD; /* changed line */
2390 }
2391 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2392#endif
2393}
2394
2395/*
2396 * "empty({expr})" function
2397 */
2398 static void
2399f_empty(typval_T *argvars, typval_T *rettv)
2400{
2401 int n = FALSE;
2402
2403 switch (argvars[0].v_type)
2404 {
2405 case VAR_STRING:
2406 case VAR_FUNC:
2407 n = argvars[0].vval.v_string == NULL
2408 || *argvars[0].vval.v_string == NUL;
2409 break;
2410 case VAR_PARTIAL:
2411 n = FALSE;
2412 break;
2413 case VAR_NUMBER:
2414 n = argvars[0].vval.v_number == 0;
2415 break;
2416 case VAR_FLOAT:
2417#ifdef FEAT_FLOAT
2418 n = argvars[0].vval.v_float == 0.0;
2419 break;
2420#endif
2421 case VAR_LIST:
2422 n = argvars[0].vval.v_list == NULL
2423 || argvars[0].vval.v_list->lv_first == NULL;
2424 break;
2425 case VAR_DICT:
2426 n = argvars[0].vval.v_dict == NULL
2427 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2428 break;
2429 case VAR_SPECIAL:
2430 n = argvars[0].vval.v_number != VVAL_TRUE;
2431 break;
2432
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002433 case VAR_BLOB:
2434 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002435 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2436 break;
2437
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002438 case VAR_JOB:
2439#ifdef FEAT_JOB_CHANNEL
2440 n = argvars[0].vval.v_job == NULL
2441 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2442 break;
2443#endif
2444 case VAR_CHANNEL:
2445#ifdef FEAT_JOB_CHANNEL
2446 n = argvars[0].vval.v_channel == NULL
2447 || !channel_is_open(argvars[0].vval.v_channel);
2448 break;
2449#endif
2450 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002451 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452 n = TRUE;
2453 break;
2454 }
2455
2456 rettv->vval.v_number = n;
2457}
2458
2459/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002460 * "environ()" function
2461 */
2462 static void
2463f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2464{
2465#if !defined(AMIGA)
2466 int i = 0;
2467 char_u *entry, *value;
2468# ifdef MSWIN
2469 extern wchar_t **_wenviron;
2470# else
2471 extern char **environ;
2472# endif
2473
2474 if (rettv_dict_alloc(rettv) != OK)
2475 return;
2476
2477# ifdef MSWIN
2478 if (*_wenviron == NULL)
2479 return;
2480# else
2481 if (*environ == NULL)
2482 return;
2483# endif
2484
2485 for (i = 0; ; ++i)
2486 {
2487# ifdef MSWIN
2488 short_u *p;
2489
2490 if ((p = (short_u *)_wenviron[i]) == NULL)
2491 return;
2492 entry = utf16_to_enc(p, NULL);
2493# else
2494 if ((entry = (char_u *)environ[i]) == NULL)
2495 return;
2496 entry = vim_strsave(entry);
2497# endif
2498 if (entry == NULL) // out of memory
2499 return;
2500 if ((value = vim_strchr(entry, '=')) == NULL)
2501 {
2502 vim_free(entry);
2503 continue;
2504 }
2505 *value++ = NUL;
2506 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2507 vim_free(entry);
2508 }
2509#endif
2510}
2511
2512/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002513 * "escape({string}, {chars})" function
2514 */
2515 static void
2516f_escape(typval_T *argvars, typval_T *rettv)
2517{
2518 char_u buf[NUMBUFLEN];
2519
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002520 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2521 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002522 rettv->v_type = VAR_STRING;
2523}
2524
2525/*
2526 * "eval()" function
2527 */
2528 static void
2529f_eval(typval_T *argvars, typval_T *rettv)
2530{
2531 char_u *s, *p;
2532
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002533 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002534 if (s != NULL)
2535 s = skipwhite(s);
2536
2537 p = s;
2538 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2539 {
2540 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002541 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002542 need_clr_eos = FALSE;
2543 rettv->v_type = VAR_NUMBER;
2544 rettv->vval.v_number = 0;
2545 }
2546 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002547 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002548}
2549
2550/*
2551 * "eventhandler()" function
2552 */
2553 static void
2554f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2555{
2556 rettv->vval.v_number = vgetc_busy;
2557}
2558
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002559static garray_T redir_execute_ga;
2560
2561/*
2562 * Append "value[value_len]" to the execute() output.
2563 */
2564 void
2565execute_redir_str(char_u *value, int value_len)
2566{
2567 int len;
2568
2569 if (value_len == -1)
2570 len = (int)STRLEN(value); /* Append the entire string */
2571 else
2572 len = value_len; /* Append only "value_len" characters */
2573 if (ga_grow(&redir_execute_ga, len) == OK)
2574 {
2575 mch_memmove((char *)redir_execute_ga.ga_data
2576 + redir_execute_ga.ga_len, value, len);
2577 redir_execute_ga.ga_len += len;
2578 }
2579}
2580
2581/*
2582 * Get next line from a list.
2583 * Called by do_cmdline() to get the next line.
2584 * Returns allocated string, or NULL for end of function.
2585 */
2586
2587 static char_u *
2588get_list_line(
2589 int c UNUSED,
2590 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002591 int indent UNUSED,
2592 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002593{
2594 listitem_T **p = (listitem_T **)cookie;
2595 listitem_T *item = *p;
2596 char_u buf[NUMBUFLEN];
2597 char_u *s;
2598
2599 if (item == NULL)
2600 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002601 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 *p = item->li_next;
2603 return s == NULL ? NULL : vim_strsave(s);
2604}
2605
2606/*
2607 * "execute()" function
2608 */
2609 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002610execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002611{
2612 char_u *cmd = NULL;
2613 list_T *list = NULL;
2614 int save_msg_silent = msg_silent;
2615 int save_emsg_silent = emsg_silent;
2616 int save_emsg_noredir = emsg_noredir;
2617 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002618 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002619 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002620 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002621 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002622
2623 rettv->vval.v_string = NULL;
2624 rettv->v_type = VAR_STRING;
2625
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002626 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002627 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002628 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002629 if (list == NULL || list->lv_first == NULL)
2630 /* empty list, no commands, empty output */
2631 return;
2632 ++list->lv_refcount;
2633 }
2634 else
2635 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002636 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002637 if (cmd == NULL)
2638 return;
2639 }
2640
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002641 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002642 {
2643 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002644 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002645
2646 if (s == NULL)
2647 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002648 if (*s == NUL)
2649 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002650 if (STRNCMP(s, "silent", 6) == 0)
2651 ++msg_silent;
2652 if (STRCMP(s, "silent!") == 0)
2653 {
2654 emsg_silent = TRUE;
2655 emsg_noredir = TRUE;
2656 }
2657 }
2658 else
2659 ++msg_silent;
2660
2661 if (redir_execute)
2662 save_ga = redir_execute_ga;
2663 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2664 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002665 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002666 if (!echo_output)
2667 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002668
2669 if (cmd != NULL)
2670 do_cmdline_cmd(cmd);
2671 else
2672 {
2673 listitem_T *item = list->lv_first;
2674
2675 do_cmdline(NULL, get_list_line, (void *)&item,
2676 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
2677 --list->lv_refcount;
2678 }
2679
Bram Moolenaard297f352017-01-29 20:31:21 +01002680 /* Need to append a NUL to the result. */
2681 if (ga_grow(&redir_execute_ga, 1) == OK)
2682 {
2683 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
2684 rettv->vval.v_string = redir_execute_ga.ga_data;
2685 }
2686 else
2687 {
2688 ga_clear(&redir_execute_ga);
2689 rettv->vval.v_string = NULL;
2690 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002691 msg_silent = save_msg_silent;
2692 emsg_silent = save_emsg_silent;
2693 emsg_noredir = save_emsg_noredir;
2694
2695 redir_execute = save_redir_execute;
2696 if (redir_execute)
2697 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01002698 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002699
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002700 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002701 if (echo_output)
2702 // When not working silently: put it in column zero. A following
2703 // "echon" will overwrite the message, unavoidably.
2704 msg_col = 0;
2705 else
2706 // When working silently: Put it back where it was, since nothing
2707 // should have been written.
2708 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002709}
2710
2711/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002712 * "execute()" function
2713 */
2714 static void
2715f_execute(typval_T *argvars, typval_T *rettv)
2716{
2717 execute_common(argvars, rettv, 0);
2718}
2719
2720/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002721 * "exists()" function
2722 */
2723 static void
2724f_exists(typval_T *argvars, typval_T *rettv)
2725{
2726 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002727 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002728
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002729 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002730 if (*p == '$') /* environment variable */
2731 {
2732 /* first try "normal" environment variables (fast) */
2733 if (mch_getenv(p + 1) != NULL)
2734 n = TRUE;
2735 else
2736 {
2737 /* try expanding things like $VIM and ${HOME} */
2738 p = expand_env_save(p);
2739 if (p != NULL && *p != '$')
2740 n = TRUE;
2741 vim_free(p);
2742 }
2743 }
2744 else if (*p == '&' || *p == '+') /* option */
2745 {
2746 n = (get_option_tv(&p, NULL, TRUE) == OK);
2747 if (*skipwhite(p) != NUL)
2748 n = FALSE; /* trailing garbage */
2749 }
2750 else if (*p == '*') /* internal or user defined function */
2751 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02002752 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002753 }
2754 else if (*p == ':')
2755 {
2756 n = cmd_exists(p + 1);
2757 }
2758 else if (*p == '#')
2759 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002760 if (p[1] == '#')
2761 n = autocmd_supported(p + 2);
2762 else
2763 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002764 }
2765 else /* internal variable */
2766 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01002767 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002768 }
2769
2770 rettv->vval.v_number = n;
2771}
2772
2773#ifdef FEAT_FLOAT
2774/*
2775 * "exp()" function
2776 */
2777 static void
2778f_exp(typval_T *argvars, typval_T *rettv)
2779{
2780 float_T f = 0.0;
2781
2782 rettv->v_type = VAR_FLOAT;
2783 if (get_float_arg(argvars, &f) == OK)
2784 rettv->vval.v_float = exp(f);
2785 else
2786 rettv->vval.v_float = 0.0;
2787}
2788#endif
2789
2790/*
2791 * "expand()" function
2792 */
2793 static void
2794f_expand(typval_T *argvars, typval_T *rettv)
2795{
2796 char_u *s;
2797 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002798 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002799 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
2800 expand_T xpc;
2801 int error = FALSE;
2802 char_u *result;
2803
2804 rettv->v_type = VAR_STRING;
2805 if (argvars[1].v_type != VAR_UNKNOWN
2806 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002807 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002808 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02002809 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002810
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002811 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002812 if (*s == '%' || *s == '#' || *s == '<')
2813 {
2814 ++emsg_off;
2815 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
2816 --emsg_off;
2817 if (rettv->v_type == VAR_LIST)
2818 {
2819 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
2820 list_append_string(rettv->vval.v_list, result, -1);
2821 else
2822 vim_free(result);
2823 }
2824 else
2825 rettv->vval.v_string = result;
2826 }
2827 else
2828 {
2829 /* When the optional second argument is non-zero, don't remove matches
2830 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
2831 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002832 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002833 options |= WILD_KEEP_ALL;
2834 if (!error)
2835 {
2836 ExpandInit(&xpc);
2837 xpc.xp_context = EXPAND_FILES;
2838 if (p_wic)
2839 options += WILD_ICASE;
2840 if (rettv->v_type == VAR_STRING)
2841 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
2842 options, WILD_ALL);
2843 else if (rettv_list_alloc(rettv) != FAIL)
2844 {
2845 int i;
2846
2847 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
2848 for (i = 0; i < xpc.xp_numfiles; i++)
2849 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
2850 ExpandCleanup(&xpc);
2851 }
2852 }
2853 else
2854 rettv->vval.v_string = NULL;
2855 }
2856}
2857
2858/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02002859 * "expandcmd()" function
2860 * Expand all the special characters in a command string.
2861 */
2862 static void
2863f_expandcmd(typval_T *argvars, typval_T *rettv)
2864{
2865 exarg_T eap;
2866 char_u *cmdstr;
2867 char *errormsg = NULL;
2868
2869 rettv->v_type = VAR_STRING;
2870 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
2871
2872 memset(&eap, 0, sizeof(eap));
2873 eap.cmd = cmdstr;
2874 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02002875 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02002876 eap.usefilter = FALSE;
2877 eap.nextcmd = NULL;
2878 eap.cmdidx = CMD_USER;
2879
2880 expand_filename(&eap, &cmdstr, &errormsg);
2881 if (errormsg != NULL && *errormsg != NUL)
2882 emsg(errormsg);
2883
2884 rettv->vval.v_string = cmdstr;
2885}
2886
2887/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002888 * "feedkeys()" function
2889 */
2890 static void
2891f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
2892{
2893 int remap = TRUE;
2894 int insert = FALSE;
2895 char_u *keys, *flags;
2896 char_u nbuf[NUMBUFLEN];
2897 int typed = FALSE;
2898 int execute = FALSE;
2899 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002900 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002901 char_u *keys_esc;
2902
2903 /* This is not allowed in the sandbox. If the commands would still be
2904 * executed in the sandbox it would be OK, but it probably happens later,
2905 * when "sandbox" is no longer set. */
2906 if (check_secure())
2907 return;
2908
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002909 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002910
2911 if (argvars[1].v_type != VAR_UNKNOWN)
2912 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002913 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002914 for ( ; *flags != NUL; ++flags)
2915 {
2916 switch (*flags)
2917 {
2918 case 'n': remap = FALSE; break;
2919 case 'm': remap = TRUE; break;
2920 case 't': typed = TRUE; break;
2921 case 'i': insert = TRUE; break;
2922 case 'x': execute = TRUE; break;
2923 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002924 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002925 }
2926 }
2927 }
2928
2929 if (*keys != NUL || execute)
2930 {
2931 /* Need to escape K_SPECIAL and CSI before putting the string in the
2932 * typeahead buffer. */
2933 keys_esc = vim_strsave_escape_csi(keys);
2934 if (keys_esc != NULL)
2935 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002936 if (lowlevel)
2937 {
2938#ifdef USE_INPUT_BUF
2939 add_to_input_buf(keys, (int)STRLEN(keys));
2940#else
2941 emsg(_("E980: lowlevel input not supported"));
2942#endif
2943 }
2944 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002945 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01002946 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002947 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002948 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002949#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002950 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02002951#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01002952 )
2953 typebuf_was_filled = TRUE;
2954 }
2955 vim_free(keys_esc);
2956
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002957 if (execute)
2958 {
2959 int save_msg_scroll = msg_scroll;
2960
2961 /* Avoid a 1 second delay when the keys start Insert mode. */
2962 msg_scroll = FALSE;
2963
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002964 if (!dangerous)
2965 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02002966 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02002967 if (!dangerous)
2968 --ex_normal_busy;
2969
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002970 msg_scroll |= save_msg_scroll;
2971 }
2972 }
2973 }
2974}
2975
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002976#ifdef FEAT_FLOAT
2977/*
2978 * "float2nr({float})" function
2979 */
2980 static void
2981f_float2nr(typval_T *argvars, typval_T *rettv)
2982{
2983 float_T f = 0.0;
2984
2985 if (get_float_arg(argvars, &f) == OK)
2986 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002987 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002988 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02002989 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01002990 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002991 else
2992 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002993 }
2994}
2995
2996/*
2997 * "floor({float})" function
2998 */
2999 static void
3000f_floor(typval_T *argvars, typval_T *rettv)
3001{
3002 float_T f = 0.0;
3003
3004 rettv->v_type = VAR_FLOAT;
3005 if (get_float_arg(argvars, &f) == OK)
3006 rettv->vval.v_float = floor(f);
3007 else
3008 rettv->vval.v_float = 0.0;
3009}
3010
3011/*
3012 * "fmod()" function
3013 */
3014 static void
3015f_fmod(typval_T *argvars, typval_T *rettv)
3016{
3017 float_T fx = 0.0, fy = 0.0;
3018
3019 rettv->v_type = VAR_FLOAT;
3020 if (get_float_arg(argvars, &fx) == OK
3021 && get_float_arg(&argvars[1], &fy) == OK)
3022 rettv->vval.v_float = fmod(fx, fy);
3023 else
3024 rettv->vval.v_float = 0.0;
3025}
3026#endif
3027
3028/*
3029 * "fnameescape({string})" function
3030 */
3031 static void
3032f_fnameescape(typval_T *argvars, typval_T *rettv)
3033{
3034 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003035 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036 rettv->v_type = VAR_STRING;
3037}
3038
3039/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003040 * "foreground()" function
3041 */
3042 static void
3043f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3044{
3045#ifdef FEAT_GUI
3046 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003047 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003048 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003049 return;
3050 }
3051#endif
3052#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003053 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003054#endif
3055}
3056
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003057 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003058common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003059{
3060 char_u *s;
3061 char_u *name;
3062 int use_string = FALSE;
3063 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003064 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003065
3066 if (argvars[0].v_type == VAR_FUNC)
3067 {
3068 /* function(MyFunc, [arg], dict) */
3069 s = argvars[0].vval.v_string;
3070 }
3071 else if (argvars[0].v_type == VAR_PARTIAL
3072 && argvars[0].vval.v_partial != NULL)
3073 {
3074 /* function(dict.MyFunc, [arg]) */
3075 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003076 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 }
3078 else
3079 {
3080 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003081 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003082 use_string = TRUE;
3083 }
3084
Bram Moolenaar843b8842016-08-21 14:36:15 +02003085 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003086 {
3087 name = s;
3088 trans_name = trans_function_name(&name, FALSE,
3089 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3090 if (*name != NUL)
3091 s = NULL;
3092 }
3093
Bram Moolenaar843b8842016-08-21 14:36:15 +02003094 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3095 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003096 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003097 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003098 else if (trans_name != NULL && (is_funcref
3099 ? find_func(trans_name) == NULL
3100 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003101 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003102 else
3103 {
3104 int dict_idx = 0;
3105 int arg_idx = 0;
3106 list_T *list = NULL;
3107
3108 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3109 {
3110 char sid_buf[25];
3111 int off = *s == 's' ? 2 : 5;
3112
3113 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3114 * also be called from another script. Using trans_function_name()
3115 * would also work, but some plugins depend on the name being
3116 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003117 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003118 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003119 if (name != NULL)
3120 {
3121 STRCPY(name, sid_buf);
3122 STRCAT(name, s + off);
3123 }
3124 }
3125 else
3126 name = vim_strsave(s);
3127
3128 if (argvars[1].v_type != VAR_UNKNOWN)
3129 {
3130 if (argvars[2].v_type != VAR_UNKNOWN)
3131 {
3132 /* function(name, [args], dict) */
3133 arg_idx = 1;
3134 dict_idx = 2;
3135 }
3136 else if (argvars[1].v_type == VAR_DICT)
3137 /* function(name, dict) */
3138 dict_idx = 1;
3139 else
3140 /* function(name, [args]) */
3141 arg_idx = 1;
3142 if (dict_idx > 0)
3143 {
3144 if (argvars[dict_idx].v_type != VAR_DICT)
3145 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003146 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003147 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003148 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003149 }
3150 if (argvars[dict_idx].vval.v_dict == NULL)
3151 dict_idx = 0;
3152 }
3153 if (arg_idx > 0)
3154 {
3155 if (argvars[arg_idx].v_type != VAR_LIST)
3156 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003157 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003158 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003159 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003160 }
3161 list = argvars[arg_idx].vval.v_list;
3162 if (list == NULL || list->lv_len == 0)
3163 arg_idx = 0;
3164 }
3165 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003166 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003167 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003168 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003169
3170 /* result is a VAR_PARTIAL */
3171 if (pt == NULL)
3172 vim_free(name);
3173 else
3174 {
3175 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3176 {
3177 listitem_T *li;
3178 int i = 0;
3179 int arg_len = 0;
3180 int lv_len = 0;
3181
3182 if (arg_pt != NULL)
3183 arg_len = arg_pt->pt_argc;
3184 if (list != NULL)
3185 lv_len = list->lv_len;
3186 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003187 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003188 if (pt->pt_argv == NULL)
3189 {
3190 vim_free(pt);
3191 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003192 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003193 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003194 for (i = 0; i < arg_len; i++)
3195 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3196 if (lv_len > 0)
3197 for (li = list->lv_first; li != NULL;
3198 li = li->li_next)
3199 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003200 }
3201
3202 /* For "function(dict.func, [], dict)" and "func" is a partial
3203 * use "dict". That is backwards compatible. */
3204 if (dict_idx > 0)
3205 {
3206 /* The dict is bound explicitly, pt_auto is FALSE. */
3207 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3208 ++pt->pt_dict->dv_refcount;
3209 }
3210 else if (arg_pt != NULL)
3211 {
3212 /* If the dict was bound automatically the result is also
3213 * bound automatically. */
3214 pt->pt_dict = arg_pt->pt_dict;
3215 pt->pt_auto = arg_pt->pt_auto;
3216 if (pt->pt_dict != NULL)
3217 ++pt->pt_dict->dv_refcount;
3218 }
3219
3220 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003221 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3222 {
3223 pt->pt_func = arg_pt->pt_func;
3224 func_ptr_ref(pt->pt_func);
3225 vim_free(name);
3226 }
3227 else if (is_funcref)
3228 {
3229 pt->pt_func = find_func(trans_name);
3230 func_ptr_ref(pt->pt_func);
3231 vim_free(name);
3232 }
3233 else
3234 {
3235 pt->pt_name = name;
3236 func_ref(name);
3237 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 }
3239 rettv->v_type = VAR_PARTIAL;
3240 rettv->vval.v_partial = pt;
3241 }
3242 else
3243 {
3244 /* result is a VAR_FUNC */
3245 rettv->v_type = VAR_FUNC;
3246 rettv->vval.v_string = name;
3247 func_ref(name);
3248 }
3249 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003250theend:
3251 vim_free(trans_name);
3252}
3253
3254/*
3255 * "funcref()" function
3256 */
3257 static void
3258f_funcref(typval_T *argvars, typval_T *rettv)
3259{
3260 common_function(argvars, rettv, TRUE);
3261}
3262
3263/*
3264 * "function()" function
3265 */
3266 static void
3267f_function(typval_T *argvars, typval_T *rettv)
3268{
3269 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003270}
3271
3272/*
3273 * "garbagecollect()" function
3274 */
3275 static void
3276f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3277{
3278 /* This is postponed until we are back at the toplevel, because we may be
3279 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3280 want_garbage_collect = TRUE;
3281
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003282 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003283 garbage_collect_at_exit = TRUE;
3284}
3285
3286/*
3287 * "get()" function
3288 */
3289 static void
3290f_get(typval_T *argvars, typval_T *rettv)
3291{
3292 listitem_T *li;
3293 list_T *l;
3294 dictitem_T *di;
3295 dict_T *d;
3296 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003297 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003298
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003299 if (argvars[0].v_type == VAR_BLOB)
3300 {
3301 int error = FALSE;
3302 int idx = tv_get_number_chk(&argvars[1], &error);
3303
3304 if (!error)
3305 {
3306 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003307 if (idx < 0)
3308 idx = blob_len(argvars[0].vval.v_blob) + idx;
3309 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
3310 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003311 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003312 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003313 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003314 tv = rettv;
3315 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003316 }
3317 }
3318 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003319 {
3320 if ((l = argvars[0].vval.v_list) != NULL)
3321 {
3322 int error = FALSE;
3323
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003324 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003325 if (!error && li != NULL)
3326 tv = &li->li_tv;
3327 }
3328 }
3329 else if (argvars[0].v_type == VAR_DICT)
3330 {
3331 if ((d = argvars[0].vval.v_dict) != NULL)
3332 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003333 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003334 if (di != NULL)
3335 tv = &di->di_tv;
3336 }
3337 }
3338 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3339 {
3340 partial_T *pt;
3341 partial_T fref_pt;
3342
3343 if (argvars[0].v_type == VAR_PARTIAL)
3344 pt = argvars[0].vval.v_partial;
3345 else
3346 {
3347 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3348 fref_pt.pt_name = argvars[0].vval.v_string;
3349 pt = &fref_pt;
3350 }
3351
3352 if (pt != NULL)
3353 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003354 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003355 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003356
3357 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3358 {
3359 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003360 n = partial_name(pt);
3361 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003362 rettv->vval.v_string = NULL;
3363 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003364 {
3365 rettv->vval.v_string = vim_strsave(n);
3366 if (rettv->v_type == VAR_FUNC)
3367 func_ref(rettv->vval.v_string);
3368 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003369 }
3370 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003371 {
3372 what_is_dict = TRUE;
3373 if (pt->pt_dict != NULL)
3374 rettv_dict_set(rettv, pt->pt_dict);
3375 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003376 else if (STRCMP(what, "args") == 0)
3377 {
3378 rettv->v_type = VAR_LIST;
3379 if (rettv_list_alloc(rettv) == OK)
3380 {
3381 int i;
3382
3383 for (i = 0; i < pt->pt_argc; ++i)
3384 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3385 }
3386 }
3387 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003388 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003389
3390 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3391 // third argument
3392 if (!what_is_dict)
3393 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003394 }
3395 }
3396 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003397 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003398
3399 if (tv == NULL)
3400 {
3401 if (argvars[2].v_type != VAR_UNKNOWN)
3402 copy_tv(&argvars[2], rettv);
3403 }
3404 else
3405 copy_tv(tv, rettv);
3406}
3407
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003408/*
3409 * Returns buffer options, variables and other attributes in a dictionary.
3410 */
3411 static dict_T *
3412get_buffer_info(buf_T *buf)
3413{
3414 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003415 tabpage_T *tp;
3416 win_T *wp;
3417 list_T *windows;
3418
3419 dict = dict_alloc();
3420 if (dict == NULL)
3421 return NULL;
3422
Bram Moolenaare0be1672018-07-08 16:50:37 +02003423 dict_add_number(dict, "bufnr", buf->b_fnum);
3424 dict_add_string(dict, "name", buf->b_ffname);
3425 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
3426 : buflist_findlnum(buf));
3427 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
3428 dict_add_number(dict, "listed", buf->b_p_bl);
3429 dict_add_number(dict, "changed", bufIsChanged(buf));
3430 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
3431 dict_add_number(dict, "hidden",
3432 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003433
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003434 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02003435 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003436
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003437 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003438 windows = list_alloc();
3439 if (windows != NULL)
3440 {
3441 FOR_ALL_TAB_WINDOWS(tp, wp)
3442 if (wp->w_buffer == buf)
3443 list_append_number(windows, (varnumber_T)wp->w_id);
3444 dict_add_list(dict, "windows", windows);
3445 }
3446
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02003447#ifdef FEAT_TEXT_PROP
3448 // List of popup windows displaying this buffer
3449 windows = list_alloc();
3450 if (windows != NULL)
3451 {
3452 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
3453 if (wp->w_buffer == buf)
3454 list_append_number(windows, (varnumber_T)wp->w_id);
3455 FOR_ALL_TABPAGES(tp)
3456 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
3457 if (wp->w_buffer == buf)
3458 list_append_number(windows, (varnumber_T)wp->w_id);
3459
3460 dict_add_list(dict, "popups", windows);
3461 }
3462#endif
3463
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003464#ifdef FEAT_SIGNS
3465 if (buf->b_signlist != NULL)
3466 {
3467 /* List of signs placed in this buffer */
3468 list_T *signs = list_alloc();
3469 if (signs != NULL)
3470 {
3471 get_buffer_signs(buf, signs);
3472 dict_add_list(dict, "signs", signs);
3473 }
3474 }
3475#endif
3476
3477 return dict;
3478}
3479
3480/*
3481 * "getbufinfo()" function
3482 */
3483 static void
3484f_getbufinfo(typval_T *argvars, typval_T *rettv)
3485{
3486 buf_T *buf = NULL;
3487 buf_T *argbuf = NULL;
3488 dict_T *d;
3489 int filtered = FALSE;
3490 int sel_buflisted = FALSE;
3491 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003492 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003493
3494 if (rettv_list_alloc(rettv) != OK)
3495 return;
3496
3497 /* List of all the buffers or selected buffers */
3498 if (argvars[0].v_type == VAR_DICT)
3499 {
3500 dict_T *sel_d = argvars[0].vval.v_dict;
3501
3502 if (sel_d != NULL)
3503 {
3504 dictitem_T *di;
3505
3506 filtered = TRUE;
3507
3508 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003509 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003510 sel_buflisted = TRUE;
3511
3512 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003513 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003514 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003515
3516 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003517 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003518 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003519 }
3520 }
3521 else if (argvars[0].v_type != VAR_UNKNOWN)
3522 {
3523 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003524 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003525 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003526 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003527 --emsg_off;
3528 if (argbuf == NULL)
3529 return;
3530 }
3531
3532 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02003533 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003534 {
3535 if (argbuf != NULL && argbuf != buf)
3536 continue;
3537 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01003538 || (sel_buflisted && !buf->b_p_bl)
3539 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003540 continue;
3541
3542 d = get_buffer_info(buf);
3543 if (d != NULL)
3544 list_append_dict(rettv->vval.v_list, d);
3545 if (argbuf != NULL)
3546 return;
3547 }
3548}
3549
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003550/*
3551 * Get line or list of lines from buffer "buf" into "rettv".
3552 * Return a range (from start to end) of lines in rettv from the specified
3553 * buffer.
3554 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
3555 */
3556 static void
3557get_buffer_lines(
3558 buf_T *buf,
3559 linenr_T start,
3560 linenr_T end,
3561 int retlist,
3562 typval_T *rettv)
3563{
3564 char_u *p;
3565
3566 rettv->v_type = VAR_STRING;
3567 rettv->vval.v_string = NULL;
3568 if (retlist && rettv_list_alloc(rettv) == FAIL)
3569 return;
3570
3571 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
3572 return;
3573
3574 if (!retlist)
3575 {
3576 if (start >= 1 && start <= buf->b_ml.ml_line_count)
3577 p = ml_get_buf(buf, start, FALSE);
3578 else
3579 p = (char_u *)"";
3580 rettv->vval.v_string = vim_strsave(p);
3581 }
3582 else
3583 {
3584 if (end < start)
3585 return;
3586
3587 if (start < 1)
3588 start = 1;
3589 if (end > buf->b_ml.ml_line_count)
3590 end = buf->b_ml.ml_line_count;
3591 while (start <= end)
3592 if (list_append_string(rettv->vval.v_list,
3593 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
3594 break;
3595 }
3596}
3597
3598/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003599 * "getbufline()" function
3600 */
3601 static void
3602f_getbufline(typval_T *argvars, typval_T *rettv)
3603{
3604 linenr_T lnum;
3605 linenr_T end;
3606 buf_T *buf;
3607
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003608 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003609 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003610 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003611 --emsg_off;
3612
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003613 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003614 if (argvars[2].v_type == VAR_UNKNOWN)
3615 end = lnum;
3616 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003617 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003618
3619 get_buffer_lines(buf, lnum, end, TRUE, rettv);
3620}
3621
3622/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003623 * "getchangelist()" function
3624 */
3625 static void
3626f_getchangelist(typval_T *argvars, typval_T *rettv)
3627{
3628#ifdef FEAT_JUMPLIST
3629 buf_T *buf;
3630 int i;
3631 list_T *l;
3632 dict_T *d;
3633#endif
3634
3635 if (rettv_list_alloc(rettv) != OK)
3636 return;
3637
3638#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02003639 if (argvars[0].v_type == VAR_UNKNOWN)
3640 buf = curbuf;
3641 else
3642 {
3643 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
3644 ++emsg_off;
3645 buf = tv_get_buf(&argvars[0], FALSE);
3646 --emsg_off;
3647 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003648 if (buf == NULL)
3649 return;
3650
3651 l = list_alloc();
3652 if (l == NULL)
3653 return;
3654
3655 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3656 return;
3657 /*
3658 * The current window change list index tracks only the position in the
3659 * current buffer change list. For other buffers, use the change list
3660 * length as the current index.
3661 */
3662 list_append_number(rettv->vval.v_list,
3663 (varnumber_T)((buf == curwin->w_buffer)
3664 ? curwin->w_changelistidx : buf->b_changelistlen));
3665
3666 for (i = 0; i < buf->b_changelistlen; ++i)
3667 {
3668 if (buf->b_changelist[i].lnum == 0)
3669 continue;
3670 if ((d = dict_alloc()) == NULL)
3671 return;
3672 if (list_append_dict(l, d) == FAIL)
3673 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003674 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
3675 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003676 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01003677 }
3678#endif
3679}
3680/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681 * "getchar()" function
3682 */
3683 static void
3684f_getchar(typval_T *argvars, typval_T *rettv)
3685{
3686 varnumber_T n;
3687 int error = FALSE;
3688
Bram Moolenaar84d93902018-09-11 20:10:20 +02003689#ifdef MESSAGE_QUEUE
3690 // vpeekc() used to check for messages, but that caused problems, invoking
3691 // a callback where it was not expected. Some plugins use getchar(1) in a
3692 // loop to await a message, therefore make sure we check for messages here.
3693 parse_queued_messages();
3694#endif
3695
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003696 /* Position the cursor. Needed after a message that ends in a space. */
3697 windgoto(msg_row, msg_col);
3698
3699 ++no_mapping;
3700 ++allow_keys;
3701 for (;;)
3702 {
3703 if (argvars[0].v_type == VAR_UNKNOWN)
3704 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01003705 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003706 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003707 /* getchar(1): only check if char avail */
3708 n = vpeekc_any();
3709 else if (error || vpeekc_any() == NUL)
3710 /* illegal argument or getchar(0) and no char avail: return zero */
3711 n = 0;
3712 else
3713 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01003714 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003715
3716 if (n == K_IGNORE)
3717 continue;
3718 break;
3719 }
3720 --no_mapping;
3721 --allow_keys;
3722
3723 set_vim_var_nr(VV_MOUSE_WIN, 0);
3724 set_vim_var_nr(VV_MOUSE_WINID, 0);
3725 set_vim_var_nr(VV_MOUSE_LNUM, 0);
3726 set_vim_var_nr(VV_MOUSE_COL, 0);
3727
3728 rettv->vval.v_number = n;
3729 if (IS_SPECIAL(n) || mod_mask != 0)
3730 {
3731 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
3732 int i = 0;
3733
3734 /* Turn a special key into three bytes, plus modifier. */
3735 if (mod_mask != 0)
3736 {
3737 temp[i++] = K_SPECIAL;
3738 temp[i++] = KS_MODIFIER;
3739 temp[i++] = mod_mask;
3740 }
3741 if (IS_SPECIAL(n))
3742 {
3743 temp[i++] = K_SPECIAL;
3744 temp[i++] = K_SECOND(n);
3745 temp[i++] = K_THIRD(n);
3746 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003747 else if (has_mbyte)
3748 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003749 else
3750 temp[i++] = n;
3751 temp[i++] = NUL;
3752 rettv->v_type = VAR_STRING;
3753 rettv->vval.v_string = vim_strsave(temp);
3754
3755#ifdef FEAT_MOUSE
3756 if (is_mouse_key(n))
3757 {
3758 int row = mouse_row;
3759 int col = mouse_col;
3760 win_T *win;
3761 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003762 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003763 int winnr = 1;
3764
3765 if (row >= 0 && col >= 0)
3766 {
3767 /* Find the window at the mouse coordinates and compute the
3768 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003769 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02003770 if (win == NULL)
3771 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02003772 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003773# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02003774 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02003775 winnr = 0;
3776 else
3777# endif
3778 for (wp = firstwin; wp != win && wp != NULL;
3779 wp = wp->w_next)
3780 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003781 set_vim_var_nr(VV_MOUSE_WIN, winnr);
3782 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
3783 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
3784 set_vim_var_nr(VV_MOUSE_COL, col + 1);
3785 }
3786 }
3787#endif
3788 }
3789}
3790
3791/*
3792 * "getcharmod()" function
3793 */
3794 static void
3795f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
3796{
3797 rettv->vval.v_number = mod_mask;
3798}
3799
3800/*
3801 * "getcharsearch()" function
3802 */
3803 static void
3804f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
3805{
3806 if (rettv_dict_alloc(rettv) != FAIL)
3807 {
3808 dict_T *dict = rettv->vval.v_dict;
3809
Bram Moolenaare0be1672018-07-08 16:50:37 +02003810 dict_add_string(dict, "char", last_csearch());
3811 dict_add_number(dict, "forward", last_csearch_forward());
3812 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003813 }
3814}
3815
3816/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003817 * "getcmdwintype()" function
3818 */
3819 static void
3820f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
3821{
3822 rettv->v_type = VAR_STRING;
3823 rettv->vval.v_string = NULL;
3824#ifdef FEAT_CMDWIN
3825 rettv->vval.v_string = alloc(2);
3826 if (rettv->vval.v_string != NULL)
3827 {
3828 rettv->vval.v_string[0] = cmdwin_type;
3829 rettv->vval.v_string[1] = NUL;
3830 }
3831#endif
3832}
3833
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003834/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02003835 * "getenv()" function
3836 */
3837 static void
3838f_getenv(typval_T *argvars, typval_T *rettv)
3839{
3840 int mustfree = FALSE;
3841 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
3842
3843 if (p == NULL)
3844 {
3845 rettv->v_type = VAR_SPECIAL;
3846 rettv->vval.v_number = VVAL_NULL;
3847 return;
3848 }
3849 if (!mustfree)
3850 p = vim_strsave(p);
3851 rettv->vval.v_string = p;
3852 rettv->v_type = VAR_STRING;
3853}
3854
3855/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003856 * "getfontname()" function
3857 */
3858 static void
3859f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
3860{
3861 rettv->v_type = VAR_STRING;
3862 rettv->vval.v_string = NULL;
3863#ifdef FEAT_GUI
3864 if (gui.in_use)
3865 {
3866 GuiFont font;
3867 char_u *name = NULL;
3868
3869 if (argvars[0].v_type == VAR_UNKNOWN)
3870 {
3871 /* Get the "Normal" font. Either the name saved by
3872 * hl_set_font_name() or from the font ID. */
3873 font = gui.norm_font;
3874 name = hl_get_font_name();
3875 }
3876 else
3877 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003878 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003879 if (STRCMP(name, "*") == 0) /* don't use font dialog */
3880 return;
3881 font = gui_mch_get_font(name, FALSE);
3882 if (font == NOFONT)
3883 return; /* Invalid font name, return empty string. */
3884 }
3885 rettv->vval.v_string = gui_mch_get_fontname(font, name);
3886 if (argvars[0].v_type != VAR_UNKNOWN)
3887 gui_mch_free_font(font);
3888 }
3889#endif
3890}
3891
3892/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01003893 * "getjumplist()" function
3894 */
3895 static void
3896f_getjumplist(typval_T *argvars, typval_T *rettv)
3897{
3898#ifdef FEAT_JUMPLIST
3899 win_T *wp;
3900 int i;
3901 list_T *l;
3902 dict_T *d;
3903#endif
3904
3905 if (rettv_list_alloc(rettv) != OK)
3906 return;
3907
3908#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02003909 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003910 if (wp == NULL)
3911 return;
3912
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01003913 cleanup_jumplist(wp, TRUE);
3914
Bram Moolenaar4f505882018-02-10 21:06:32 +01003915 l = list_alloc();
3916 if (l == NULL)
3917 return;
3918
3919 if (list_append_list(rettv->vval.v_list, l) == FAIL)
3920 return;
3921 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
3922
3923 for (i = 0; i < wp->w_jumplistlen; ++i)
3924 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003925 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
3926 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01003927 if ((d = dict_alloc()) == NULL)
3928 return;
3929 if (list_append_dict(l, d) == FAIL)
3930 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02003931 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
3932 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003933 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02003934 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01003935 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02003936 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01003937 }
3938#endif
3939}
3940
3941/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003942 * "getline(lnum, [end])" function
3943 */
3944 static void
3945f_getline(typval_T *argvars, typval_T *rettv)
3946{
3947 linenr_T lnum;
3948 linenr_T end;
3949 int retlist;
3950
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003951 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003952 if (argvars[1].v_type == VAR_UNKNOWN)
3953 {
3954 end = 0;
3955 retlist = FALSE;
3956 }
3957 else
3958 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003959 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003960 retlist = TRUE;
3961 }
3962
3963 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
3964}
3965
3966/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003967 * "getpid()" function
3968 */
3969 static void
3970f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
3971{
3972 rettv->vval.v_number = mch_get_pid();
3973}
3974
3975 static void
3976getpos_both(
3977 typval_T *argvars,
3978 typval_T *rettv,
3979 int getcurpos)
3980{
3981 pos_T *fp;
3982 list_T *l;
3983 int fnum = -1;
3984
3985 if (rettv_list_alloc(rettv) == OK)
3986 {
3987 l = rettv->vval.v_list;
3988 if (getcurpos)
3989 fp = &curwin->w_cursor;
3990 else
3991 fp = var2fpos(&argvars[0], TRUE, &fnum);
3992 if (fnum != -1)
3993 list_append_number(l, (varnumber_T)fnum);
3994 else
3995 list_append_number(l, (varnumber_T)0);
3996 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
3997 : (varnumber_T)0);
3998 list_append_number(l, (fp != NULL)
3999 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4000 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01004001 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004002 (varnumber_T)0);
4003 if (getcurpos)
4004 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01004005 int save_set_curswant = curwin->w_set_curswant;
4006 colnr_T save_curswant = curwin->w_curswant;
4007 colnr_T save_virtcol = curwin->w_virtcol;
4008
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004009 update_curswant();
4010 list_append_number(l, curwin->w_curswant == MAXCOL ?
4011 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01004012
4013 // Do not change "curswant", as it is unexpected that a get
4014 // function has a side effect.
4015 if (save_set_curswant)
4016 {
4017 curwin->w_set_curswant = save_set_curswant;
4018 curwin->w_curswant = save_curswant;
4019 curwin->w_virtcol = save_virtcol;
4020 curwin->w_valid &= ~VALID_VIRTCOL;
4021 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004022 }
4023 }
4024 else
4025 rettv->vval.v_number = FALSE;
4026}
4027
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004028/*
4029 * "getcurpos()" function
4030 */
4031 static void
4032f_getcurpos(typval_T *argvars, typval_T *rettv)
4033{
4034 getpos_both(argvars, rettv, TRUE);
4035}
4036
4037/*
4038 * "getpos(string)" function
4039 */
4040 static void
4041f_getpos(typval_T *argvars, typval_T *rettv)
4042{
4043 getpos_both(argvars, rettv, FALSE);
4044}
4045
4046/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004047 * "getreg()" function
4048 */
4049 static void
4050f_getreg(typval_T *argvars, typval_T *rettv)
4051{
4052 char_u *strregname;
4053 int regname;
4054 int arg2 = FALSE;
4055 int return_list = FALSE;
4056 int error = FALSE;
4057
4058 if (argvars[0].v_type != VAR_UNKNOWN)
4059 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004060 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004061 error = strregname == NULL;
4062 if (argvars[1].v_type != VAR_UNKNOWN)
4063 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004064 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004065 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004066 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004067 }
4068 }
4069 else
4070 strregname = get_vim_var_str(VV_REG);
4071
4072 if (error)
4073 return;
4074
4075 regname = (strregname == NULL ? '"' : *strregname);
4076 if (regname == 0)
4077 regname = '"';
4078
4079 if (return_list)
4080 {
4081 rettv->v_type = VAR_LIST;
4082 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4083 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4084 if (rettv->vval.v_list == NULL)
4085 (void)rettv_list_alloc(rettv);
4086 else
4087 ++rettv->vval.v_list->lv_refcount;
4088 }
4089 else
4090 {
4091 rettv->v_type = VAR_STRING;
4092 rettv->vval.v_string = get_reg_contents(regname,
4093 arg2 ? GREG_EXPR_SRC : 0);
4094 }
4095}
4096
4097/*
4098 * "getregtype()" function
4099 */
4100 static void
4101f_getregtype(typval_T *argvars, typval_T *rettv)
4102{
4103 char_u *strregname;
4104 int regname;
4105 char_u buf[NUMBUFLEN + 2];
4106 long reglen = 0;
4107
4108 if (argvars[0].v_type != VAR_UNKNOWN)
4109 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004110 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004111 if (strregname == NULL) /* type error; errmsg already given */
4112 {
4113 rettv->v_type = VAR_STRING;
4114 rettv->vval.v_string = NULL;
4115 return;
4116 }
4117 }
4118 else
4119 /* Default to v:register */
4120 strregname = get_vim_var_str(VV_REG);
4121
4122 regname = (strregname == NULL ? '"' : *strregname);
4123 if (regname == 0)
4124 regname = '"';
4125
4126 buf[0] = NUL;
4127 buf[1] = NUL;
4128 switch (get_reg_type(regname, &reglen))
4129 {
4130 case MLINE: buf[0] = 'V'; break;
4131 case MCHAR: buf[0] = 'v'; break;
4132 case MBLOCK:
4133 buf[0] = Ctrl_V;
4134 sprintf((char *)buf + 1, "%ld", reglen + 1);
4135 break;
4136 }
4137 rettv->v_type = VAR_STRING;
4138 rettv->vval.v_string = vim_strsave(buf);
4139}
4140
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004141/*
4142 * Returns information (variables, options, etc.) about a tab page
4143 * as a dictionary.
4144 */
4145 static dict_T *
4146get_tabpage_info(tabpage_T *tp, int tp_idx)
4147{
4148 win_T *wp;
4149 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004150 list_T *l;
4151
4152 dict = dict_alloc();
4153 if (dict == NULL)
4154 return NULL;
4155
Bram Moolenaare0be1672018-07-08 16:50:37 +02004156 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004157
4158 l = list_alloc();
4159 if (l != NULL)
4160 {
4161 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004162 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004163 list_append_number(l, (varnumber_T)wp->w_id);
4164 dict_add_list(dict, "windows", l);
4165 }
4166
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004167 /* Make a reference to tabpage variables */
4168 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004169
4170 return dict;
4171}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004172
4173/*
4174 * "gettabinfo()" function
4175 */
4176 static void
4177f_gettabinfo(typval_T *argvars, typval_T *rettv)
4178{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004179 tabpage_T *tp, *tparg = NULL;
4180 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02004181 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004182
4183 if (rettv_list_alloc(rettv) != OK)
4184 return;
4185
4186 if (argvars[0].v_type != VAR_UNKNOWN)
4187 {
4188 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004189 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004190 if (tparg == NULL)
4191 return;
4192 }
4193
4194 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004195 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004196 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004197 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004198 if (tparg != NULL && tp != tparg)
4199 continue;
4200 d = get_tabpage_info(tp, tpnr);
4201 if (d != NULL)
4202 list_append_dict(rettv->vval.v_list, d);
4203 if (tparg != NULL)
4204 return;
4205 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004206}
4207
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004208/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01004209 * "gettagstack()" function
4210 */
4211 static void
4212f_gettagstack(typval_T *argvars, typval_T *rettv)
4213{
4214 win_T *wp = curwin; // default is current window
4215
4216 if (rettv_dict_alloc(rettv) != OK)
4217 return;
4218
4219 if (argvars[0].v_type != VAR_UNKNOWN)
4220 {
4221 wp = find_win_by_nr_or_id(&argvars[0]);
4222 if (wp == NULL)
4223 return;
4224 }
4225
4226 get_tagstack(wp, rettv->vval.v_dict);
4227}
4228
4229/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004230 * Returns information about a window as a dictionary.
4231 */
4232 static dict_T *
4233get_win_info(win_T *wp, short tpnr, short winnr)
4234{
4235 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004236
4237 dict = dict_alloc();
4238 if (dict == NULL)
4239 return NULL;
4240
Bram Moolenaare0be1672018-07-08 16:50:37 +02004241 dict_add_number(dict, "tabnr", tpnr);
4242 dict_add_number(dict, "winnr", winnr);
4243 dict_add_number(dict, "winid", wp->w_id);
4244 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02004245 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01004246 dict_add_number(dict, "topline", wp->w_topline);
4247 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02004248#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02004249 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02004250#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02004251 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02004252 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004253 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004254
Bram Moolenaar69905d12017-08-13 18:14:47 +02004255#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02004256 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02004257#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02004258#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02004259 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
4260 dict_add_number(dict, "loclist",
4261 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02004262#endif
4263
Bram Moolenaar30567352016-08-27 21:25:44 +02004264 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004265 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004266
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004267 return dict;
4268}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004269
4270/*
4271 * "getwininfo()" function
4272 */
4273 static void
4274f_getwininfo(typval_T *argvars, typval_T *rettv)
4275{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004276 tabpage_T *tp;
4277 win_T *wp = NULL, *wparg = NULL;
4278 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02004279 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004280
4281 if (rettv_list_alloc(rettv) != OK)
4282 return;
4283
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004284 if (argvars[0].v_type != VAR_UNKNOWN)
4285 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01004286 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004287 if (wparg == NULL)
4288 return;
4289 }
4290
4291 /* Collect information about either all the windows across all the tab
4292 * pages or one particular window.
4293 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004294 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004295 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004296 tabnr++;
4297 winnr = 0;
4298 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004299 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004300 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004301 if (wparg != NULL && wp != wparg)
4302 continue;
4303 d = get_win_info(wp, tabnr, winnr);
4304 if (d != NULL)
4305 list_append_dict(rettv->vval.v_list, d);
4306 if (wparg != NULL)
4307 /* found information about a specific window */
4308 return;
4309 }
4310 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004311}
4312
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004313/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004314 * "win_execute()" function
4315 */
4316 static void
4317f_win_execute(typval_T *argvars, typval_T *rettv)
4318{
4319 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02004320 tabpage_T *tp;
4321 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004322 win_T *save_curwin;
4323 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004324
Bram Moolenaar820680b2019-08-09 14:56:22 +02004325 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004326 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02004327 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004328 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004329 check_cursor();
4330 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004331 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02004332 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02004333 }
4334}
4335
4336/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004337 * "win_findbuf()" function
4338 */
4339 static void
4340f_win_findbuf(typval_T *argvars, typval_T *rettv)
4341{
4342 if (rettv_list_alloc(rettv) != FAIL)
4343 win_findbuf(argvars, rettv->vval.v_list);
4344}
4345
4346/*
4347 * "win_getid()" function
4348 */
4349 static void
4350f_win_getid(typval_T *argvars, typval_T *rettv)
4351{
4352 rettv->vval.v_number = win_getid(argvars);
4353}
4354
4355/*
4356 * "win_gotoid()" function
4357 */
4358 static void
4359f_win_gotoid(typval_T *argvars, typval_T *rettv)
4360{
4361 rettv->vval.v_number = win_gotoid(argvars);
4362}
4363
4364/*
4365 * "win_id2tabwin()" function
4366 */
4367 static void
4368f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
4369{
4370 if (rettv_list_alloc(rettv) != FAIL)
4371 win_id2tabwin(argvars, rettv->vval.v_list);
4372}
4373
4374/*
4375 * "win_id2win()" function
4376 */
4377 static void
4378f_win_id2win(typval_T *argvars, typval_T *rettv)
4379{
4380 rettv->vval.v_number = win_id2win(argvars);
4381}
4382
4383/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01004384 * "win_screenpos()" function
4385 */
4386 static void
4387f_win_screenpos(typval_T *argvars, typval_T *rettv)
4388{
4389 win_T *wp;
4390
4391 if (rettv_list_alloc(rettv) == FAIL)
4392 return;
4393
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02004394 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01004395 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
4396 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
4397}
4398
4399/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004400 * "getwinpos({timeout})" function
4401 */
4402 static void
4403f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
4404{
4405 int x = -1;
4406 int y = -1;
4407
4408 if (rettv_list_alloc(rettv) == FAIL)
4409 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004410#if defined(FEAT_GUI) \
4411 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4412 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004413 {
4414 varnumber_T timeout = 100;
4415
4416 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004417 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004418
4419 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01004420 }
4421#endif
4422 list_append_number(rettv->vval.v_list, (varnumber_T)x);
4423 list_append_number(rettv->vval.v_list, (varnumber_T)y);
4424}
4425
4426
4427/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004428 * "getwinposx()" function
4429 */
4430 static void
4431f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
4432{
4433 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004434#if defined(FEAT_GUI) \
4435 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4436 || defined(MSWIN)
4437
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004438 {
4439 int x, y;
4440
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004441 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004442 rettv->vval.v_number = x;
4443 }
4444#endif
4445}
4446
4447/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004448 * "getwinposy()" function
4449 */
4450 static void
4451f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
4452{
4453 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02004454#if defined(FEAT_GUI) \
4455 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
4456 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004457 {
4458 int x, y;
4459
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02004460 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02004461 rettv->vval.v_number = y;
4462 }
4463#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004464}
4465
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004466/* for VIM_VERSION_ defines */
4467#include "version.h"
4468
4469/*
4470 * "has()" function
4471 */
4472 static void
4473f_has(typval_T *argvars, typval_T *rettv)
4474{
4475 int i;
4476 char_u *name;
4477 int n = FALSE;
4478 static char *(has_list[]) =
4479 {
4480#ifdef AMIGA
4481 "amiga",
4482# ifdef FEAT_ARP
4483 "arp",
4484# endif
4485#endif
4486#ifdef __BEOS__
4487 "beos",
4488#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004489#if defined(BSD) && !defined(MACOS_X)
4490 "bsd",
4491#endif
4492#ifdef hpux
4493 "hpux",
4494#endif
4495#ifdef __linux__
4496 "linux",
4497#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02004498#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01004499 "mac", /* Mac OS X (and, once, Mac OS Classic) */
4500 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02004501# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01004502 "macunix", /* Mac OS X, with the darwin feature */
4503 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02004504# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004505#endif
4506#ifdef __QNX__
4507 "qnx",
4508#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004509#ifdef SUN_SYSTEM
4510 "sun",
4511#else
4512 "moon",
4513#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004514#ifdef UNIX
4515 "unix",
4516#endif
4517#ifdef VMS
4518 "vms",
4519#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004520#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004521 "win32",
4522#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01004523#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004524 "win32unix",
4525#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01004526#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004527 "win64",
4528#endif
4529#ifdef EBCDIC
4530 "ebcdic",
4531#endif
4532#ifndef CASE_INSENSITIVE_FILENAME
4533 "fname_case",
4534#endif
4535#ifdef HAVE_ACL
4536 "acl",
4537#endif
4538#ifdef FEAT_ARABIC
4539 "arabic",
4540#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004541 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004542#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01004543 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02004544#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01004545#ifdef FEAT_AUTOSERVERNAME
4546 "autoservername",
4547#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004548#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004549 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01004550# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004551 "balloon_multiline",
4552# endif
4553#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01004554#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01004555 "balloon_eval_term",
4556#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004557#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
4558 "builtin_terms",
4559# ifdef ALL_BUILTIN_TCAPS
4560 "all_builtin_terms",
4561# endif
4562#endif
4563#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01004564 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004565 || defined(FEAT_GUI_MOTIF))
4566 "browsefilter",
4567#endif
4568#ifdef FEAT_BYTEOFF
4569 "byte_offset",
4570#endif
4571#ifdef FEAT_JOB_CHANNEL
4572 "channel",
4573#endif
4574#ifdef FEAT_CINDENT
4575 "cindent",
4576#endif
4577#ifdef FEAT_CLIENTSERVER
4578 "clientserver",
4579#endif
4580#ifdef FEAT_CLIPBOARD
4581 "clipboard",
4582#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004583 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004584 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004585#ifdef FEAT_COMMENTS
4586 "comments",
4587#endif
4588#ifdef FEAT_CONCEAL
4589 "conceal",
4590#endif
4591#ifdef FEAT_CRYPT
4592 "cryptv",
4593 "crypt-blowfish",
4594 "crypt-blowfish2",
4595#endif
4596#ifdef FEAT_CSCOPE
4597 "cscope",
4598#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004599 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004600#ifdef CURSOR_SHAPE
4601 "cursorshape",
4602#endif
4603#ifdef DEBUG
4604 "debug",
4605#endif
4606#ifdef FEAT_CON_DIALOG
4607 "dialog_con",
4608#endif
4609#ifdef FEAT_GUI_DIALOG
4610 "dialog_gui",
4611#endif
4612#ifdef FEAT_DIFF
4613 "diff",
4614#endif
4615#ifdef FEAT_DIGRAPHS
4616 "digraphs",
4617#endif
4618#ifdef FEAT_DIRECTX
4619 "directx",
4620#endif
4621#ifdef FEAT_DND
4622 "dnd",
4623#endif
4624#ifdef FEAT_EMACS_TAGS
4625 "emacs_tags",
4626#endif
4627 "eval", /* always present, of course! */
4628 "ex_extra", /* graduated feature */
4629#ifdef FEAT_SEARCH_EXTRA
4630 "extra_search",
4631#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004632#ifdef FEAT_SEARCHPATH
4633 "file_in_path",
4634#endif
4635#ifdef FEAT_FILTERPIPE
4636 "filterpipe",
4637#endif
4638#ifdef FEAT_FIND_ID
4639 "find_in_path",
4640#endif
4641#ifdef FEAT_FLOAT
4642 "float",
4643#endif
4644#ifdef FEAT_FOLDING
4645 "folding",
4646#endif
4647#ifdef FEAT_FOOTER
4648 "footer",
4649#endif
4650#if !defined(USE_SYSTEM) && defined(UNIX)
4651 "fork",
4652#endif
4653#ifdef FEAT_GETTEXT
4654 "gettext",
4655#endif
4656#ifdef FEAT_GUI
4657 "gui",
4658#endif
4659#ifdef FEAT_GUI_ATHENA
4660# ifdef FEAT_GUI_NEXTAW
4661 "gui_neXtaw",
4662# else
4663 "gui_athena",
4664# endif
4665#endif
4666#ifdef FEAT_GUI_GTK
4667 "gui_gtk",
4668# ifdef USE_GTK3
4669 "gui_gtk3",
4670# else
4671 "gui_gtk2",
4672# endif
4673#endif
4674#ifdef FEAT_GUI_GNOME
4675 "gui_gnome",
4676#endif
4677#ifdef FEAT_GUI_MAC
4678 "gui_mac",
4679#endif
4680#ifdef FEAT_GUI_MOTIF
4681 "gui_motif",
4682#endif
4683#ifdef FEAT_GUI_PHOTON
4684 "gui_photon",
4685#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004686#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004687 "gui_win32",
4688#endif
4689#ifdef FEAT_HANGULIN
4690 "hangul_input",
4691#endif
4692#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
4693 "iconv",
4694#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004695 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004696#ifdef FEAT_JOB_CHANNEL
4697 "job",
4698#endif
4699#ifdef FEAT_JUMPLIST
4700 "jumplist",
4701#endif
4702#ifdef FEAT_KEYMAP
4703 "keymap",
4704#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02004705 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004706#ifdef FEAT_LANGMAP
4707 "langmap",
4708#endif
4709#ifdef FEAT_LIBCALL
4710 "libcall",
4711#endif
4712#ifdef FEAT_LINEBREAK
4713 "linebreak",
4714#endif
4715#ifdef FEAT_LISP
4716 "lispindent",
4717#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004720#ifdef FEAT_LUA
4721# ifndef DYNAMIC_LUA
4722 "lua",
4723# endif
4724#endif
4725#ifdef FEAT_MENU
4726 "menu",
4727#endif
4728#ifdef FEAT_SESSION
4729 "mksession",
4730#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004731 "modify_fname",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004732#ifdef FEAT_MOUSE
4733 "mouse",
4734#endif
4735#ifdef FEAT_MOUSESHAPE
4736 "mouseshape",
4737#endif
4738#if defined(UNIX) || defined(VMS)
4739# ifdef FEAT_MOUSE_DEC
4740 "mouse_dec",
4741# endif
4742# ifdef FEAT_MOUSE_GPM
4743 "mouse_gpm",
4744# endif
4745# ifdef FEAT_MOUSE_JSB
4746 "mouse_jsbterm",
4747# endif
4748# ifdef FEAT_MOUSE_NET
4749 "mouse_netterm",
4750# endif
4751# ifdef FEAT_MOUSE_PTERM
4752 "mouse_pterm",
4753# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01004754# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004755 "mouse_sgr",
4756# endif
4757# ifdef FEAT_SYSMOUSE
4758 "mouse_sysmouse",
4759# endif
4760# ifdef FEAT_MOUSE_URXVT
4761 "mouse_urxvt",
4762# endif
4763# ifdef FEAT_MOUSE_XTERM
4764 "mouse_xterm",
4765# endif
4766#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004767 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004768#ifdef FEAT_MBYTE_IME
4769 "multi_byte_ime",
4770#endif
4771#ifdef FEAT_MULTI_LANG
4772 "multi_lang",
4773#endif
4774#ifdef FEAT_MZSCHEME
4775#ifndef DYNAMIC_MZSCHEME
4776 "mzscheme",
4777#endif
4778#endif
4779#ifdef FEAT_NUM64
4780 "num64",
4781#endif
4782#ifdef FEAT_OLE
4783 "ole",
4784#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02004785#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004786 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02004787#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004788#ifdef FEAT_PATH_EXTRA
4789 "path_extra",
4790#endif
4791#ifdef FEAT_PERL
4792#ifndef DYNAMIC_PERL
4793 "perl",
4794#endif
4795#endif
4796#ifdef FEAT_PERSISTENT_UNDO
4797 "persistent_undo",
4798#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004799#if defined(FEAT_PYTHON)
4800 "python_compiled",
4801# if defined(DYNAMIC_PYTHON)
4802 "python_dynamic",
4803# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004804 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004805 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004806# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004807#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004808#if defined(FEAT_PYTHON3)
4809 "python3_compiled",
4810# if defined(DYNAMIC_PYTHON3)
4811 "python3_dynamic",
4812# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004813 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01004814 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01004815# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004816#endif
4817#ifdef FEAT_POSTSCRIPT
4818 "postscript",
4819#endif
4820#ifdef FEAT_PRINTER
4821 "printer",
4822#endif
4823#ifdef FEAT_PROFILE
4824 "profile",
4825#endif
4826#ifdef FEAT_RELTIME
4827 "reltime",
4828#endif
4829#ifdef FEAT_QUICKFIX
4830 "quickfix",
4831#endif
4832#ifdef FEAT_RIGHTLEFT
4833 "rightleft",
4834#endif
4835#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
4836 "ruby",
4837#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004838 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004839#ifdef FEAT_CMDL_INFO
4840 "showcmd",
4841 "cmdline_info",
4842#endif
4843#ifdef FEAT_SIGNS
4844 "signs",
4845#endif
4846#ifdef FEAT_SMARTINDENT
4847 "smartindent",
4848#endif
4849#ifdef STARTUPTIME
4850 "startuptime",
4851#endif
4852#ifdef FEAT_STL_OPT
4853 "statusline",
4854#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004855#ifdef FEAT_NETBEANS_INTG
4856 "netbeans_intg",
4857#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02004858#ifdef FEAT_SOUND
4859 "sound",
4860#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004861#ifdef FEAT_SPELL
4862 "spell",
4863#endif
4864#ifdef FEAT_SYN_HL
4865 "syntax",
4866#endif
4867#if defined(USE_SYSTEM) || !defined(UNIX)
4868 "system",
4869#endif
4870#ifdef FEAT_TAG_BINS
4871 "tag_binary",
4872#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004873#ifdef FEAT_TCL
4874# ifndef DYNAMIC_TCL
4875 "tcl",
4876# endif
4877#endif
4878#ifdef FEAT_TERMGUICOLORS
4879 "termguicolors",
4880#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01004881#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02004882 "terminal",
4883#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004884#ifdef TERMINFO
4885 "terminfo",
4886#endif
4887#ifdef FEAT_TERMRESPONSE
4888 "termresponse",
4889#endif
4890#ifdef FEAT_TEXTOBJ
4891 "textobjects",
4892#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01004893#ifdef FEAT_TEXT_PROP
4894 "textprop",
4895#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004896#ifdef HAVE_TGETENT
4897 "tgetent",
4898#endif
4899#ifdef FEAT_TIMERS
4900 "timers",
4901#endif
4902#ifdef FEAT_TITLE
4903 "title",
4904#endif
4905#ifdef FEAT_TOOLBAR
4906 "toolbar",
4907#endif
4908#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
4909 "unnamedplus",
4910#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911 "user-commands", /* was accidentally included in 5.4 */
4912 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02004913#ifdef FEAT_VARTABS
4914 "vartabs",
4915#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004916 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917#ifdef FEAT_VIMINFO
4918 "viminfo",
4919#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02004920 "vimscript-1",
4921 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02004922 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004923 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004924 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004925 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004926 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01004927#ifdef FEAT_VTP
4928 "vtp",
4929#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004930#ifdef FEAT_WILDIGN
4931 "wildignore",
4932#endif
4933#ifdef FEAT_WILDMENU
4934 "wildmenu",
4935#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004936 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004937#ifdef FEAT_WAK
4938 "winaltkeys",
4939#endif
4940#ifdef FEAT_WRITEBACKUP
4941 "writebackup",
4942#endif
4943#ifdef FEAT_XIM
4944 "xim",
4945#endif
4946#ifdef FEAT_XFONTSET
4947 "xfontset",
4948#endif
4949#ifdef FEAT_XPM_W32
4950 "xpm",
4951 "xpm_w32", /* for backward compatibility */
4952#else
4953# if defined(HAVE_XPM)
4954 "xpm",
4955# endif
4956#endif
4957#ifdef USE_XSMP
4958 "xsmp",
4959#endif
4960#ifdef USE_XSMP_INTERACT
4961 "xsmp_interact",
4962#endif
4963#ifdef FEAT_XCLIPBOARD
4964 "xterm_clipboard",
4965#endif
4966#ifdef FEAT_XTERM_SAVE
4967 "xterm_save",
4968#endif
4969#if defined(UNIX) && defined(FEAT_X11)
4970 "X11",
4971#endif
4972 NULL
4973 };
4974
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004975 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004976 for (i = 0; has_list[i] != NULL; ++i)
4977 if (STRICMP(name, has_list[i]) == 0)
4978 {
4979 n = TRUE;
4980 break;
4981 }
4982
4983 if (n == FALSE)
4984 {
4985 if (STRNICMP(name, "patch", 5) == 0)
4986 {
4987 if (name[5] == '-'
4988 && STRLEN(name) >= 11
4989 && vim_isdigit(name[6])
4990 && vim_isdigit(name[8])
4991 && vim_isdigit(name[10]))
4992 {
4993 int major = atoi((char *)name + 6);
4994 int minor = atoi((char *)name + 8);
4995
4996 /* Expect "patch-9.9.01234". */
4997 n = (major < VIM_VERSION_MAJOR
4998 || (major == VIM_VERSION_MAJOR
4999 && (minor < VIM_VERSION_MINOR
5000 || (minor == VIM_VERSION_MINOR
5001 && has_patch(atoi((char *)name + 10))))));
5002 }
5003 else
5004 n = has_patch(atoi((char *)name + 5));
5005 }
5006 else if (STRICMP(name, "vim_starting") == 0)
5007 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01005008 else if (STRICMP(name, "ttyin") == 0)
5009 n = mch_input_isatty();
5010 else if (STRICMP(name, "ttyout") == 0)
5011 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005012 else if (STRICMP(name, "multi_byte_encoding") == 0)
5013 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005014#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005015 else if (STRICMP(name, "balloon_multiline") == 0)
5016 n = multiline_balloon_available();
5017#endif
5018#ifdef DYNAMIC_TCL
5019 else if (STRICMP(name, "tcl") == 0)
5020 n = tcl_enabled(FALSE);
5021#endif
5022#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5023 else if (STRICMP(name, "iconv") == 0)
5024 n = iconv_enabled(FALSE);
5025#endif
5026#ifdef DYNAMIC_LUA
5027 else if (STRICMP(name, "lua") == 0)
5028 n = lua_enabled(FALSE);
5029#endif
5030#ifdef DYNAMIC_MZSCHEME
5031 else if (STRICMP(name, "mzscheme") == 0)
5032 n = mzscheme_enabled(FALSE);
5033#endif
5034#ifdef DYNAMIC_RUBY
5035 else if (STRICMP(name, "ruby") == 0)
5036 n = ruby_enabled(FALSE);
5037#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005038#ifdef DYNAMIC_PYTHON
5039 else if (STRICMP(name, "python") == 0)
5040 n = python_enabled(FALSE);
5041#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005042#ifdef DYNAMIC_PYTHON3
5043 else if (STRICMP(name, "python3") == 0)
5044 n = python3_enabled(FALSE);
5045#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005046#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5047 else if (STRICMP(name, "pythonx") == 0)
5048 {
5049# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
5050 if (p_pyx == 0)
5051 n = python3_enabled(FALSE) || python_enabled(FALSE);
5052 else if (p_pyx == 3)
5053 n = python3_enabled(FALSE);
5054 else if (p_pyx == 2)
5055 n = python_enabled(FALSE);
5056# elif defined(DYNAMIC_PYTHON)
5057 n = python_enabled(FALSE);
5058# elif defined(DYNAMIC_PYTHON3)
5059 n = python3_enabled(FALSE);
5060# endif
5061 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005062#endif
5063#ifdef DYNAMIC_PERL
5064 else if (STRICMP(name, "perl") == 0)
5065 n = perl_enabled(FALSE);
5066#endif
5067#ifdef FEAT_GUI
5068 else if (STRICMP(name, "gui_running") == 0)
5069 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005070# ifdef FEAT_BROWSE
5071 else if (STRICMP(name, "browse") == 0)
5072 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
5073# endif
5074#endif
5075#ifdef FEAT_SYN_HL
5076 else if (STRICMP(name, "syntax_items") == 0)
5077 n = syntax_present(curwin);
5078#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01005079#ifdef FEAT_VTP
5080 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02005081 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005082#endif
5083#ifdef FEAT_NETBEANS_INTG
5084 else if (STRICMP(name, "netbeans_enabled") == 0)
5085 n = netbeans_active();
5086#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02005087#ifdef FEAT_MOUSE_GPM
5088 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
5089 n = gpm_enabled();
5090#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005091#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02005092 else if (STRICMP(name, "terminal") == 0)
5093 n = terminal_enabled();
5094#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005095#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005096 else if (STRICMP(name, "conpty") == 0)
5097 n = use_conpty();
5098#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02005099#ifdef FEAT_CLIPBOARD
5100 else if (STRICMP(name, "clipboard_working") == 0)
5101 n = clip_star.available;
5102#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005103 }
5104
5105 rettv->vval.v_number = n;
5106}
5107
5108/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005109 * "haslocaldir()" function
5110 */
5111 static void
5112f_haslocaldir(typval_T *argvars, typval_T *rettv)
5113{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005114 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005115 win_T *wp = NULL;
5116
Bram Moolenaar00aa0692019-04-27 20:37:57 +02005117 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
5118
5119 // Check for window-local and tab-local directories
5120 if (wp != NULL && wp->w_localdir != NULL)
5121 rettv->vval.v_number = 1;
5122 else if (tp != NULL && tp->tp_localdir != NULL)
5123 rettv->vval.v_number = 2;
5124 else
5125 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005126}
5127
5128/*
5129 * "hasmapto()" function
5130 */
5131 static void
5132f_hasmapto(typval_T *argvars, typval_T *rettv)
5133{
5134 char_u *name;
5135 char_u *mode;
5136 char_u buf[NUMBUFLEN];
5137 int abbr = FALSE;
5138
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005139 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005140 if (argvars[1].v_type == VAR_UNKNOWN)
5141 mode = (char_u *)"nvo";
5142 else
5143 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005144 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005145 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005146 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005147 }
5148
5149 if (map_to_exists(name, mode, abbr))
5150 rettv->vval.v_number = TRUE;
5151 else
5152 rettv->vval.v_number = FALSE;
5153}
5154
5155/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005156 * "highlightID(name)" function
5157 */
5158 static void
5159f_hlID(typval_T *argvars, typval_T *rettv)
5160{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005161 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005162}
5163
5164/*
5165 * "highlight_exists()" function
5166 */
5167 static void
5168f_hlexists(typval_T *argvars, typval_T *rettv)
5169{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005170 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005171}
5172
5173/*
5174 * "hostname()" function
5175 */
5176 static void
5177f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
5178{
5179 char_u hostname[256];
5180
5181 mch_get_host_name(hostname, 256);
5182 rettv->v_type = VAR_STRING;
5183 rettv->vval.v_string = vim_strsave(hostname);
5184}
5185
5186/*
5187 * iconv() function
5188 */
5189 static void
5190f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
5191{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005192 char_u buf1[NUMBUFLEN];
5193 char_u buf2[NUMBUFLEN];
5194 char_u *from, *to, *str;
5195 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005196
5197 rettv->v_type = VAR_STRING;
5198 rettv->vval.v_string = NULL;
5199
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005200 str = tv_get_string(&argvars[0]);
5201 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
5202 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005203 vimconv.vc_type = CONV_NONE;
5204 convert_setup(&vimconv, from, to);
5205
5206 /* If the encodings are equal, no conversion needed. */
5207 if (vimconv.vc_type == CONV_NONE)
5208 rettv->vval.v_string = vim_strsave(str);
5209 else
5210 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
5211
5212 convert_setup(&vimconv, NULL, NULL);
5213 vim_free(from);
5214 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005215}
5216
5217/*
5218 * "indent()" function
5219 */
5220 static void
5221f_indent(typval_T *argvars, typval_T *rettv)
5222{
5223 linenr_T lnum;
5224
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005225 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005226 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5227 rettv->vval.v_number = get_indent_lnum(lnum);
5228 else
5229 rettv->vval.v_number = -1;
5230}
5231
5232/*
5233 * "index()" function
5234 */
5235 static void
5236f_index(typval_T *argvars, typval_T *rettv)
5237{
5238 list_T *l;
5239 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005240 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005241 long idx = 0;
5242 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005243 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005244
5245 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005246 if (argvars[0].v_type == VAR_BLOB)
5247 {
5248 typval_T tv;
5249 int start = 0;
5250
5251 if (argvars[2].v_type != VAR_UNKNOWN)
5252 {
5253 start = tv_get_number_chk(&argvars[2], &error);
5254 if (error)
5255 return;
5256 }
5257 b = argvars[0].vval.v_blob;
5258 if (b == NULL)
5259 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01005260 if (start < 0)
5261 {
5262 start = blob_len(b) + start;
5263 if (start < 0)
5264 start = 0;
5265 }
5266
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005267 for (idx = start; idx < blob_len(b); ++idx)
5268 {
5269 tv.v_type = VAR_NUMBER;
5270 tv.vval.v_number = blob_get(b, idx);
5271 if (tv_equal(&tv, &argvars[1], ic, FALSE))
5272 {
5273 rettv->vval.v_number = idx;
5274 return;
5275 }
5276 }
5277 return;
5278 }
5279 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005280 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01005281 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005282 return;
5283 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005284
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005285 l = argvars[0].vval.v_list;
5286 if (l != NULL)
5287 {
5288 item = l->lv_first;
5289 if (argvars[2].v_type != VAR_UNKNOWN)
5290 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005291 /* Start at specified item. Use the cached index that list_find()
5292 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005293 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005294 idx = l->lv_idx;
5295 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005296 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005297 if (error)
5298 item = NULL;
5299 }
5300
5301 for ( ; item != NULL; item = item->li_next, ++idx)
5302 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
5303 {
5304 rettv->vval.v_number = idx;
5305 break;
5306 }
5307 }
5308}
5309
5310static int inputsecret_flag = 0;
5311
5312/*
5313 * "input()" function
5314 * Also handles inputsecret() when inputsecret is set.
5315 */
5316 static void
5317f_input(typval_T *argvars, typval_T *rettv)
5318{
5319 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
5320}
5321
5322/*
5323 * "inputdialog()" function
5324 */
5325 static void
5326f_inputdialog(typval_T *argvars, typval_T *rettv)
5327{
5328#if defined(FEAT_GUI_TEXTDIALOG)
5329 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
5330 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
5331 {
5332 char_u *message;
5333 char_u buf[NUMBUFLEN];
5334 char_u *defstr = (char_u *)"";
5335
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005336 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005337 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005338 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005339 vim_strncpy(IObuff, defstr, IOSIZE - 1);
5340 else
5341 IObuff[0] = NUL;
5342 if (message != NULL && defstr != NULL
5343 && do_dialog(VIM_QUESTION, NULL, message,
5344 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
5345 rettv->vval.v_string = vim_strsave(IObuff);
5346 else
5347 {
5348 if (message != NULL && defstr != NULL
5349 && argvars[1].v_type != VAR_UNKNOWN
5350 && argvars[2].v_type != VAR_UNKNOWN)
5351 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005352 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005353 else
5354 rettv->vval.v_string = NULL;
5355 }
5356 rettv->v_type = VAR_STRING;
5357 }
5358 else
5359#endif
5360 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
5361}
5362
5363/*
5364 * "inputlist()" function
5365 */
5366 static void
5367f_inputlist(typval_T *argvars, typval_T *rettv)
5368{
5369 listitem_T *li;
5370 int selected;
5371 int mouse_used;
5372
5373#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02005374 /* While starting up, there is no place to enter text. When running tests
5375 * with --not-a-term we assume feedkeys() will be used. */
5376 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005377 return;
5378#endif
5379 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
5380 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005381 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005382 return;
5383 }
5384
5385 msg_start();
5386 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
5387 lines_left = Rows; /* avoid more prompt */
5388 msg_scroll = TRUE;
5389 msg_clr_eos();
5390
5391 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
5392 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005393 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005394 msg_putchar('\n');
5395 }
5396
5397 /* Ask for choice. */
5398 selected = prompt_for_number(&mouse_used);
5399 if (mouse_used)
5400 selected -= lines_left;
5401
5402 rettv->vval.v_number = selected;
5403}
5404
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005405static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
5406
5407/*
5408 * "inputrestore()" function
5409 */
5410 static void
5411f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
5412{
5413 if (ga_userinput.ga_len > 0)
5414 {
5415 --ga_userinput.ga_len;
5416 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
5417 + ga_userinput.ga_len);
5418 /* default return is zero == OK */
5419 }
5420 else if (p_verbose > 1)
5421 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01005422 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005423 rettv->vval.v_number = 1; /* Failed */
5424 }
5425}
5426
5427/*
5428 * "inputsave()" function
5429 */
5430 static void
5431f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
5432{
5433 /* Add an entry to the stack of typeahead storage. */
5434 if (ga_grow(&ga_userinput, 1) == OK)
5435 {
5436 save_typeahead((tasave_T *)(ga_userinput.ga_data)
5437 + ga_userinput.ga_len);
5438 ++ga_userinput.ga_len;
5439 /* default return is zero == OK */
5440 }
5441 else
5442 rettv->vval.v_number = 1; /* Failed */
5443}
5444
5445/*
5446 * "inputsecret()" function
5447 */
5448 static void
5449f_inputsecret(typval_T *argvars, typval_T *rettv)
5450{
5451 ++cmdline_star;
5452 ++inputsecret_flag;
5453 f_input(argvars, rettv);
5454 --cmdline_star;
5455 --inputsecret_flag;
5456}
5457
5458/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005459 * "invert(expr)" function
5460 */
5461 static void
5462f_invert(typval_T *argvars, typval_T *rettv)
5463{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005464 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005465}
5466
5467/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005468 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
5469 * or it refers to a List or Dictionary that is locked.
5470 */
5471 static int
5472tv_islocked(typval_T *tv)
5473{
5474 return (tv->v_lock & VAR_LOCKED)
5475 || (tv->v_type == VAR_LIST
5476 && tv->vval.v_list != NULL
5477 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
5478 || (tv->v_type == VAR_DICT
5479 && tv->vval.v_dict != NULL
5480 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
5481}
5482
5483/*
5484 * "islocked()" function
5485 */
5486 static void
5487f_islocked(typval_T *argvars, typval_T *rettv)
5488{
5489 lval_T lv;
5490 char_u *end;
5491 dictitem_T *di;
5492
5493 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005494 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01005495 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005496 if (end != NULL && lv.ll_name != NULL)
5497 {
5498 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005499 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005500 else
5501 {
5502 if (lv.ll_tv == NULL)
5503 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005504 di = find_var(lv.ll_name, NULL, TRUE);
5505 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005506 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01005507 /* Consider a variable locked when:
5508 * 1. the variable itself is locked
5509 * 2. the value of the variable is locked.
5510 * 3. the List or Dict value is locked.
5511 */
5512 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
5513 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005514 }
5515 }
5516 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005517 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005518 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005519 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005520 else if (lv.ll_list != NULL)
5521 /* List item. */
5522 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
5523 else
5524 /* Dictionary item. */
5525 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
5526 }
5527 }
5528
5529 clear_lval(&lv);
5530}
5531
5532#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
5533/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02005534 * "isinf()" function
5535 */
5536 static void
5537f_isinf(typval_T *argvars, typval_T *rettv)
5538{
5539 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
5540 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
5541}
5542
5543/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005544 * "isnan()" function
5545 */
5546 static void
5547f_isnan(typval_T *argvars, typval_T *rettv)
5548{
5549 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
5550 && isnan(argvars[0].vval.v_float);
5551}
5552#endif
5553
5554/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005555 * "last_buffer_nr()" function.
5556 */
5557 static void
5558f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
5559{
5560 int n = 0;
5561 buf_T *buf;
5562
Bram Moolenaar29323592016-07-24 22:04:11 +02005563 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005564 if (n < buf->b_fnum)
5565 n = buf->b_fnum;
5566
5567 rettv->vval.v_number = n;
5568}
5569
5570/*
5571 * "len()" function
5572 */
5573 static void
5574f_len(typval_T *argvars, typval_T *rettv)
5575{
5576 switch (argvars[0].v_type)
5577 {
5578 case VAR_STRING:
5579 case VAR_NUMBER:
5580 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005581 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005582 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01005583 case VAR_BLOB:
5584 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
5585 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005586 case VAR_LIST:
5587 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
5588 break;
5589 case VAR_DICT:
5590 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
5591 break;
5592 case VAR_UNKNOWN:
5593 case VAR_SPECIAL:
5594 case VAR_FLOAT:
5595 case VAR_FUNC:
5596 case VAR_PARTIAL:
5597 case VAR_JOB:
5598 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005599 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005600 break;
5601 }
5602}
5603
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01005605libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005606{
5607#ifdef FEAT_LIBCALL
5608 char_u *string_in;
5609 char_u **string_result;
5610 int nr_result;
5611#endif
5612
5613 rettv->v_type = type;
5614 if (type != VAR_NUMBER)
5615 rettv->vval.v_string = NULL;
5616
5617 if (check_restricted() || check_secure())
5618 return;
5619
5620#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02005621 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005622 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
5623 {
5624 string_in = NULL;
5625 if (argvars[2].v_type == VAR_STRING)
5626 string_in = argvars[2].vval.v_string;
5627 if (type == VAR_NUMBER)
5628 string_result = NULL;
5629 else
5630 string_result = &rettv->vval.v_string;
5631 if (mch_libcall(argvars[0].vval.v_string,
5632 argvars[1].vval.v_string,
5633 string_in,
5634 argvars[2].vval.v_number,
5635 string_result,
5636 &nr_result) == OK
5637 && type == VAR_NUMBER)
5638 rettv->vval.v_number = nr_result;
5639 }
5640#endif
5641}
5642
5643/*
5644 * "libcall()" function
5645 */
5646 static void
5647f_libcall(typval_T *argvars, typval_T *rettv)
5648{
5649 libcall_common(argvars, rettv, VAR_STRING);
5650}
5651
5652/*
5653 * "libcallnr()" function
5654 */
5655 static void
5656f_libcallnr(typval_T *argvars, typval_T *rettv)
5657{
5658 libcall_common(argvars, rettv, VAR_NUMBER);
5659}
5660
5661/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005662 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005663 */
5664 static void
5665f_line(typval_T *argvars, typval_T *rettv)
5666{
5667 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005668 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005669 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005670 int id;
5671 tabpage_T *tp;
5672 win_T *wp;
5673 win_T *save_curwin;
5674 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005675
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02005676 if (argvars[1].v_type != VAR_UNKNOWN)
5677 {
5678 // use window specified in the second argument
5679 id = (int)tv_get_number(&argvars[1]);
5680 wp = win_id2wp_tp(id, &tp);
5681 if (wp != NULL && tp != NULL)
5682 {
5683 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
5684 == OK)
5685 {
5686 check_cursor();
5687 fp = var2fpos(&argvars[0], TRUE, &fnum);
5688 }
5689 restore_win_noblock(save_curwin, save_curtab, TRUE);
5690 }
5691 }
5692 else
5693 // use current window
5694 fp = var2fpos(&argvars[0], TRUE, &fnum);
5695
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005696 if (fp != NULL)
5697 lnum = fp->lnum;
5698 rettv->vval.v_number = lnum;
5699}
5700
5701/*
5702 * "line2byte(lnum)" function
5703 */
5704 static void
5705f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
5706{
5707#ifndef FEAT_BYTEOFF
5708 rettv->vval.v_number = -1;
5709#else
5710 linenr_T lnum;
5711
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005712 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005713 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
5714 rettv->vval.v_number = -1;
5715 else
5716 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
5717 if (rettv->vval.v_number >= 0)
5718 ++rettv->vval.v_number;
5719#endif
5720}
5721
5722/*
5723 * "lispindent(lnum)" function
5724 */
5725 static void
5726f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
5727{
5728#ifdef FEAT_LISP
5729 pos_T pos;
5730 linenr_T lnum;
5731
5732 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005733 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005734 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
5735 {
5736 curwin->w_cursor.lnum = lnum;
5737 rettv->vval.v_number = get_lisp_indent();
5738 curwin->w_cursor = pos;
5739 }
5740 else
5741#endif
5742 rettv->vval.v_number = -1;
5743}
5744
5745/*
5746 * "localtime()" function
5747 */
5748 static void
5749f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
5750{
5751 rettv->vval.v_number = (varnumber_T)time(NULL);
5752}
5753
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005754#ifdef FEAT_FLOAT
5755/*
5756 * "log()" function
5757 */
5758 static void
5759f_log(typval_T *argvars, typval_T *rettv)
5760{
5761 float_T f = 0.0;
5762
5763 rettv->v_type = VAR_FLOAT;
5764 if (get_float_arg(argvars, &f) == OK)
5765 rettv->vval.v_float = log(f);
5766 else
5767 rettv->vval.v_float = 0.0;
5768}
5769
5770/*
5771 * "log10()" function
5772 */
5773 static void
5774f_log10(typval_T *argvars, typval_T *rettv)
5775{
5776 float_T f = 0.0;
5777
5778 rettv->v_type = VAR_FLOAT;
5779 if (get_float_arg(argvars, &f) == OK)
5780 rettv->vval.v_float = log10(f);
5781 else
5782 rettv->vval.v_float = 0.0;
5783}
5784#endif
5785
5786#ifdef FEAT_LUA
5787/*
5788 * "luaeval()" function
5789 */
5790 static void
5791f_luaeval(typval_T *argvars, typval_T *rettv)
5792{
5793 char_u *str;
5794 char_u buf[NUMBUFLEN];
5795
Bram Moolenaar8c62a082019-02-08 14:34:10 +01005796 if (check_restricted() || check_secure())
5797 return;
5798
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005799 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005800 do_luaeval(str, argvars + 1, rettv);
5801}
5802#endif
5803
5804/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005805 * "maparg()" function
5806 */
5807 static void
5808f_maparg(typval_T *argvars, typval_T *rettv)
5809{
5810 get_maparg(argvars, rettv, TRUE);
5811}
5812
5813/*
5814 * "mapcheck()" function
5815 */
5816 static void
5817f_mapcheck(typval_T *argvars, typval_T *rettv)
5818{
5819 get_maparg(argvars, rettv, FALSE);
5820}
5821
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005822typedef enum
5823{
5824 MATCH_END, /* matchend() */
5825 MATCH_MATCH, /* match() */
5826 MATCH_STR, /* matchstr() */
5827 MATCH_LIST, /* matchlist() */
5828 MATCH_POS /* matchstrpos() */
5829} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005830
5831 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005832find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005833{
5834 char_u *str = NULL;
5835 long len = 0;
5836 char_u *expr = NULL;
5837 char_u *pat;
5838 regmatch_T regmatch;
5839 char_u patbuf[NUMBUFLEN];
5840 char_u strbuf[NUMBUFLEN];
5841 char_u *save_cpo;
5842 long start = 0;
5843 long nth = 1;
5844 colnr_T startcol = 0;
5845 int match = 0;
5846 list_T *l = NULL;
5847 listitem_T *li = NULL;
5848 long idx = 0;
5849 char_u *tofree = NULL;
5850
5851 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
5852 save_cpo = p_cpo;
5853 p_cpo = (char_u *)"";
5854
5855 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005856 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005857 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005858 /* type MATCH_LIST: return empty list when there are no matches.
5859 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005860 if (rettv_list_alloc(rettv) == FAIL)
5861 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005862 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005863 && (list_append_string(rettv->vval.v_list,
5864 (char_u *)"", 0) == 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 || list_append_number(rettv->vval.v_list,
5870 (varnumber_T)-1) == FAIL))
5871 {
5872 list_free(rettv->vval.v_list);
5873 rettv->vval.v_list = NULL;
5874 goto theend;
5875 }
5876 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005877 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005878 {
5879 rettv->v_type = VAR_STRING;
5880 rettv->vval.v_string = NULL;
5881 }
5882
5883 if (argvars[0].v_type == VAR_LIST)
5884 {
5885 if ((l = argvars[0].vval.v_list) == NULL)
5886 goto theend;
5887 li = l->lv_first;
5888 }
5889 else
5890 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005891 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005892 len = (long)STRLEN(str);
5893 }
5894
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005895 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005896 if (pat == NULL)
5897 goto theend;
5898
5899 if (argvars[2].v_type != VAR_UNKNOWN)
5900 {
5901 int error = FALSE;
5902
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005903 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005904 if (error)
5905 goto theend;
5906 if (l != NULL)
5907 {
5908 li = list_find(l, start);
5909 if (li == NULL)
5910 goto theend;
5911 idx = l->lv_idx; /* use the cached index */
5912 }
5913 else
5914 {
5915 if (start < 0)
5916 start = 0;
5917 if (start > len)
5918 goto theend;
5919 /* When "count" argument is there ignore matches before "start",
5920 * otherwise skip part of the string. Differs when pattern is "^"
5921 * or "\<". */
5922 if (argvars[3].v_type != VAR_UNKNOWN)
5923 startcol = start;
5924 else
5925 {
5926 str += start;
5927 len -= start;
5928 }
5929 }
5930
5931 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005932 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005933 if (error)
5934 goto theend;
5935 }
5936
5937 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
5938 if (regmatch.regprog != NULL)
5939 {
5940 regmatch.rm_ic = p_ic;
5941
5942 for (;;)
5943 {
5944 if (l != NULL)
5945 {
5946 if (li == NULL)
5947 {
5948 match = FALSE;
5949 break;
5950 }
5951 vim_free(tofree);
5952 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
5953 if (str == NULL)
5954 break;
5955 }
5956
5957 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
5958
5959 if (match && --nth <= 0)
5960 break;
5961 if (l == NULL && !match)
5962 break;
5963
5964 /* Advance to just after the match. */
5965 if (l != NULL)
5966 {
5967 li = li->li_next;
5968 ++idx;
5969 }
5970 else
5971 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005972 startcol = (colnr_T)(regmatch.startp[0]
5973 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005974 if (startcol > (colnr_T)len
5975 || str + startcol <= regmatch.startp[0])
5976 {
5977 match = FALSE;
5978 break;
5979 }
5980 }
5981 }
5982
5983 if (match)
5984 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02005985 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005986 {
5987 listitem_T *li1 = rettv->vval.v_list->lv_first;
5988 listitem_T *li2 = li1->li_next;
5989 listitem_T *li3 = li2->li_next;
5990 listitem_T *li4 = li3->li_next;
5991
5992 vim_free(li1->li_tv.vval.v_string);
5993 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
5994 (int)(regmatch.endp[0] - regmatch.startp[0]));
5995 li3->li_tv.vval.v_number =
5996 (varnumber_T)(regmatch.startp[0] - expr);
5997 li4->li_tv.vval.v_number =
5998 (varnumber_T)(regmatch.endp[0] - expr);
5999 if (l != NULL)
6000 li2->li_tv.vval.v_number = (varnumber_T)idx;
6001 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006002 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006003 {
6004 int i;
6005
6006 /* return list with matched string and submatches */
6007 for (i = 0; i < NSUBEXP; ++i)
6008 {
6009 if (regmatch.endp[i] == NULL)
6010 {
6011 if (list_append_string(rettv->vval.v_list,
6012 (char_u *)"", 0) == FAIL)
6013 break;
6014 }
6015 else if (list_append_string(rettv->vval.v_list,
6016 regmatch.startp[i],
6017 (int)(regmatch.endp[i] - regmatch.startp[i]))
6018 == FAIL)
6019 break;
6020 }
6021 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006022 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006023 {
6024 /* return matched string */
6025 if (l != NULL)
6026 copy_tv(&li->li_tv, rettv);
6027 else
6028 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
6029 (int)(regmatch.endp[0] - regmatch.startp[0]));
6030 }
6031 else if (l != NULL)
6032 rettv->vval.v_number = idx;
6033 else
6034 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006035 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006036 rettv->vval.v_number =
6037 (varnumber_T)(regmatch.startp[0] - str);
6038 else
6039 rettv->vval.v_number =
6040 (varnumber_T)(regmatch.endp[0] - str);
6041 rettv->vval.v_number += (varnumber_T)(str - expr);
6042 }
6043 }
6044 vim_regfree(regmatch.regprog);
6045 }
6046
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006047theend:
6048 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006049 /* matchstrpos() without a list: drop the second item. */
6050 listitem_remove(rettv->vval.v_list,
6051 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006052 vim_free(tofree);
6053 p_cpo = save_cpo;
6054}
6055
6056/*
6057 * "match()" function
6058 */
6059 static void
6060f_match(typval_T *argvars, typval_T *rettv)
6061{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006062 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006063}
6064
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065/*
6066 * "matchend()" function
6067 */
6068 static void
6069f_matchend(typval_T *argvars, typval_T *rettv)
6070{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006071 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006072}
6073
6074/*
6075 * "matchlist()" function
6076 */
6077 static void
6078f_matchlist(typval_T *argvars, typval_T *rettv)
6079{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006080 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006081}
6082
6083/*
6084 * "matchstr()" function
6085 */
6086 static void
6087f_matchstr(typval_T *argvars, typval_T *rettv)
6088{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006089 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006090}
6091
6092/*
6093 * "matchstrpos()" function
6094 */
6095 static void
6096f_matchstrpos(typval_T *argvars, typval_T *rettv)
6097{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006098 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006099}
6100
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006101 static void
6102max_min(typval_T *argvars, typval_T *rettv, int domax)
6103{
6104 varnumber_T n = 0;
6105 varnumber_T i;
6106 int error = FALSE;
6107
6108 if (argvars[0].v_type == VAR_LIST)
6109 {
6110 list_T *l;
6111 listitem_T *li;
6112
6113 l = argvars[0].vval.v_list;
6114 if (l != NULL)
6115 {
6116 li = l->lv_first;
6117 if (li != NULL)
6118 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006119 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006120 for (;;)
6121 {
6122 li = li->li_next;
6123 if (li == NULL)
6124 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006125 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006126 if (domax ? i > n : i < n)
6127 n = i;
6128 }
6129 }
6130 }
6131 }
6132 else if (argvars[0].v_type == VAR_DICT)
6133 {
6134 dict_T *d;
6135 int first = TRUE;
6136 hashitem_T *hi;
6137 int todo;
6138
6139 d = argvars[0].vval.v_dict;
6140 if (d != NULL)
6141 {
6142 todo = (int)d->dv_hashtab.ht_used;
6143 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
6144 {
6145 if (!HASHITEM_EMPTY(hi))
6146 {
6147 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006148 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006149 if (first)
6150 {
6151 n = i;
6152 first = FALSE;
6153 }
6154 else if (domax ? i > n : i < n)
6155 n = i;
6156 }
6157 }
6158 }
6159 }
6160 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006161 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006162 rettv->vval.v_number = error ? 0 : n;
6163}
6164
6165/*
6166 * "max()" function
6167 */
6168 static void
6169f_max(typval_T *argvars, typval_T *rettv)
6170{
6171 max_min(argvars, rettv, TRUE);
6172}
6173
6174/*
6175 * "min()" function
6176 */
6177 static void
6178f_min(typval_T *argvars, typval_T *rettv)
6179{
6180 max_min(argvars, rettv, FALSE);
6181}
6182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006183/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006184 * "mode()" function
6185 */
6186 static void
6187f_mode(typval_T *argvars, typval_T *rettv)
6188{
Bram Moolenaar612cc382018-07-29 15:34:26 +02006189 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190
Bram Moolenaar612cc382018-07-29 15:34:26 +02006191 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006192
6193 if (time_for_testing == 93784)
6194 {
6195 /* Testing the two-character code. */
6196 buf[0] = 'x';
6197 buf[1] = '!';
6198 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02006199#ifdef FEAT_TERMINAL
6200 else if (term_use_loop())
6201 buf[0] = 't';
6202#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006203 else if (VIsual_active)
6204 {
6205 if (VIsual_select)
6206 buf[0] = VIsual_mode + 's' - 'v';
6207 else
6208 buf[0] = VIsual_mode;
6209 }
6210 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
6211 || State == CONFIRM)
6212 {
6213 buf[0] = 'r';
6214 if (State == ASKMORE)
6215 buf[1] = 'm';
6216 else if (State == CONFIRM)
6217 buf[1] = '?';
6218 }
6219 else if (State == EXTERNCMD)
6220 buf[0] = '!';
6221 else if (State & INSERT)
6222 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006223 if (State & VREPLACE_FLAG)
6224 {
6225 buf[0] = 'R';
6226 buf[1] = 'v';
6227 }
6228 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01006229 {
6230 if (State & REPLACE_FLAG)
6231 buf[0] = 'R';
6232 else
6233 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006234 if (ins_compl_active())
6235 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01006236 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01006237 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006238 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006239 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01006240 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006241 {
6242 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006243 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006244 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01006245 else if (exmode_active == EXMODE_NORMAL)
6246 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006247 }
6248 else
6249 {
6250 buf[0] = 'n';
6251 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01006252 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006253 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01006254 // to be able to detect force-linewise/blockwise/characterwise operations
6255 buf[2] = motion_force;
6256 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02006257 else if (restart_edit == 'I' || restart_edit == 'R'
6258 || restart_edit == 'V')
6259 {
6260 buf[1] = 'i';
6261 buf[2] = restart_edit;
6262 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006263 }
6264
6265 /* Clear out the minor mode when the argument is not a non-zero number or
6266 * non-empty string. */
6267 if (!non_zero_arg(&argvars[0]))
6268 buf[1] = NUL;
6269
6270 rettv->vval.v_string = vim_strsave(buf);
6271 rettv->v_type = VAR_STRING;
6272}
6273
6274#if defined(FEAT_MZSCHEME) || defined(PROTO)
6275/*
6276 * "mzeval()" function
6277 */
6278 static void
6279f_mzeval(typval_T *argvars, typval_T *rettv)
6280{
6281 char_u *str;
6282 char_u buf[NUMBUFLEN];
6283
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006284 if (check_restricted() || check_secure())
6285 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006286 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006287 do_mzeval(str, rettv);
6288}
6289
6290 void
6291mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
6292{
6293 typval_T argvars[3];
6294
6295 argvars[0].v_type = VAR_STRING;
6296 argvars[0].vval.v_string = name;
6297 copy_tv(args, &argvars[1]);
6298 argvars[2].v_type = VAR_UNKNOWN;
6299 f_call(argvars, rettv);
6300 clear_tv(&argvars[1]);
6301}
6302#endif
6303
6304/*
6305 * "nextnonblank()" function
6306 */
6307 static void
6308f_nextnonblank(typval_T *argvars, typval_T *rettv)
6309{
6310 linenr_T lnum;
6311
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006312 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313 {
6314 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
6315 {
6316 lnum = 0;
6317 break;
6318 }
6319 if (*skipwhite(ml_get(lnum)) != NUL)
6320 break;
6321 }
6322 rettv->vval.v_number = lnum;
6323}
6324
6325/*
6326 * "nr2char()" function
6327 */
6328 static void
6329f_nr2char(typval_T *argvars, typval_T *rettv)
6330{
6331 char_u buf[NUMBUFLEN];
6332
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006333 if (has_mbyte)
6334 {
6335 int utf8 = 0;
6336
6337 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006338 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006339 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01006340 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006342 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006343 }
6344 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006346 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006347 buf[1] = NUL;
6348 }
6349 rettv->v_type = VAR_STRING;
6350 rettv->vval.v_string = vim_strsave(buf);
6351}
6352
6353/*
6354 * "or(expr, expr)" function
6355 */
6356 static void
6357f_or(typval_T *argvars, typval_T *rettv)
6358{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006359 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
6360 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006361}
6362
6363/*
6364 * "pathshorten()" function
6365 */
6366 static void
6367f_pathshorten(typval_T *argvars, typval_T *rettv)
6368{
6369 char_u *p;
6370
6371 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006372 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006373 if (p == NULL)
6374 rettv->vval.v_string = NULL;
6375 else
6376 {
6377 p = vim_strsave(p);
6378 rettv->vval.v_string = p;
6379 if (p != NULL)
6380 shorten_dir(p);
6381 }
6382}
6383
6384#ifdef FEAT_PERL
6385/*
6386 * "perleval()" function
6387 */
6388 static void
6389f_perleval(typval_T *argvars, typval_T *rettv)
6390{
6391 char_u *str;
6392 char_u buf[NUMBUFLEN];
6393
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006394 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006395 do_perleval(str, rettv);
6396}
6397#endif
6398
6399#ifdef FEAT_FLOAT
6400/*
6401 * "pow()" function
6402 */
6403 static void
6404f_pow(typval_T *argvars, typval_T *rettv)
6405{
6406 float_T fx = 0.0, fy = 0.0;
6407
6408 rettv->v_type = VAR_FLOAT;
6409 if (get_float_arg(argvars, &fx) == OK
6410 && get_float_arg(&argvars[1], &fy) == OK)
6411 rettv->vval.v_float = pow(fx, fy);
6412 else
6413 rettv->vval.v_float = 0.0;
6414}
6415#endif
6416
6417/*
6418 * "prevnonblank()" function
6419 */
6420 static void
6421f_prevnonblank(typval_T *argvars, typval_T *rettv)
6422{
6423 linenr_T lnum;
6424
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006425 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006426 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
6427 lnum = 0;
6428 else
6429 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
6430 --lnum;
6431 rettv->vval.v_number = lnum;
6432}
6433
6434/* This dummy va_list is here because:
6435 * - passing a NULL pointer doesn't work when va_list isn't a pointer
6436 * - locally in the function results in a "used before set" warning
6437 * - using va_start() to initialize it gives "function with fixed args" error */
6438static va_list ap;
6439
6440/*
6441 * "printf()" function
6442 */
6443 static void
6444f_printf(typval_T *argvars, typval_T *rettv)
6445{
6446 char_u buf[NUMBUFLEN];
6447 int len;
6448 char_u *s;
6449 int saved_did_emsg = did_emsg;
6450 char *fmt;
6451
6452 rettv->v_type = VAR_STRING;
6453 rettv->vval.v_string = NULL;
6454
6455 /* Get the required length, allocate the buffer and do it for real. */
6456 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006457 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006458 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006459 if (!did_emsg)
6460 {
6461 s = alloc(len + 1);
6462 if (s != NULL)
6463 {
6464 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02006465 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
6466 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006467 }
6468 }
6469 did_emsg |= saved_did_emsg;
6470}
6471
6472/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006473 * "pum_getpos()" function
6474 */
6475 static void
6476f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6477{
6478 if (rettv_dict_alloc(rettv) != OK)
6479 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006480 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02006481}
6482
6483/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 * "pumvisible()" function
6485 */
6486 static void
6487f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6488{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489 if (pum_visible())
6490 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006491}
6492
6493#ifdef FEAT_PYTHON3
6494/*
6495 * "py3eval()" function
6496 */
6497 static void
6498f_py3eval(typval_T *argvars, typval_T *rettv)
6499{
6500 char_u *str;
6501 char_u buf[NUMBUFLEN];
6502
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006503 if (check_restricted() || check_secure())
6504 return;
6505
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006506 if (p_pyx == 0)
6507 p_pyx = 3;
6508
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006509 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006510 do_py3eval(str, rettv);
6511}
6512#endif
6513
6514#ifdef FEAT_PYTHON
6515/*
6516 * "pyeval()" function
6517 */
6518 static void
6519f_pyeval(typval_T *argvars, typval_T *rettv)
6520{
6521 char_u *str;
6522 char_u buf[NUMBUFLEN];
6523
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006524 if (check_restricted() || check_secure())
6525 return;
6526
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006527 if (p_pyx == 0)
6528 p_pyx = 2;
6529
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006530 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006531 do_pyeval(str, rettv);
6532}
6533#endif
6534
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006535#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
6536/*
6537 * "pyxeval()" function
6538 */
6539 static void
6540f_pyxeval(typval_T *argvars, typval_T *rettv)
6541{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006542 if (check_restricted() || check_secure())
6543 return;
6544
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006545# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
6546 init_pyxversion();
6547 if (p_pyx == 2)
6548 f_pyeval(argvars, rettv);
6549 else
6550 f_py3eval(argvars, rettv);
6551# elif defined(FEAT_PYTHON)
6552 f_pyeval(argvars, rettv);
6553# elif defined(FEAT_PYTHON3)
6554 f_py3eval(argvars, rettv);
6555# endif
6556}
6557#endif
6558
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006559/*
6560 * "range()" function
6561 */
6562 static void
6563f_range(typval_T *argvars, typval_T *rettv)
6564{
6565 varnumber_T start;
6566 varnumber_T end;
6567 varnumber_T stride = 1;
6568 varnumber_T i;
6569 int error = FALSE;
6570
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006571 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006572 if (argvars[1].v_type == VAR_UNKNOWN)
6573 {
6574 end = start - 1;
6575 start = 0;
6576 }
6577 else
6578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006579 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006580 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006581 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006582 }
6583
6584 if (error)
6585 return; /* type error; errmsg already given */
6586 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006587 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006589 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006590 else
6591 {
6592 if (rettv_list_alloc(rettv) == OK)
6593 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
6594 if (list_append_number(rettv->vval.v_list,
6595 (varnumber_T)i) == FAIL)
6596 break;
6597 }
6598}
6599
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02006600 static void
6601return_register(int regname, typval_T *rettv)
6602{
6603 char_u buf[2] = {0, 0};
6604
6605 buf[0] = (char_u)regname;
6606 rettv->v_type = VAR_STRING;
6607 rettv->vval.v_string = vim_strsave(buf);
6608}
6609
6610/*
6611 * "reg_executing()" function
6612 */
6613 static void
6614f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
6615{
6616 return_register(reg_executing, rettv);
6617}
6618
6619/*
6620 * "reg_recording()" function
6621 */
6622 static void
6623f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
6624{
6625 return_register(reg_recording, rettv);
6626}
6627
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006628#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006629/*
6630 * Convert a List to proftime_T.
6631 * Return FAIL when there is something wrong.
6632 */
6633 static int
6634list2proftime(typval_T *arg, proftime_T *tm)
6635{
6636 long n1, n2;
6637 int error = FALSE;
6638
6639 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
6640 || arg->vval.v_list->lv_len != 2)
6641 return FAIL;
6642 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
6643 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01006644# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006645 tm->HighPart = n1;
6646 tm->LowPart = n2;
6647# else
6648 tm->tv_sec = n1;
6649 tm->tv_usec = n2;
6650# endif
6651 return error ? FAIL : OK;
6652}
6653#endif /* FEAT_RELTIME */
6654
6655/*
6656 * "reltime()" function
6657 */
6658 static void
6659f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6660{
6661#ifdef FEAT_RELTIME
6662 proftime_T res;
6663 proftime_T start;
6664
6665 if (argvars[0].v_type == VAR_UNKNOWN)
6666 {
6667 /* No arguments: get current time. */
6668 profile_start(&res);
6669 }
6670 else if (argvars[1].v_type == VAR_UNKNOWN)
6671 {
6672 if (list2proftime(&argvars[0], &res) == FAIL)
6673 return;
6674 profile_end(&res);
6675 }
6676 else
6677 {
6678 /* Two arguments: compute the difference. */
6679 if (list2proftime(&argvars[0], &start) == FAIL
6680 || list2proftime(&argvars[1], &res) == FAIL)
6681 return;
6682 profile_sub(&res, &start);
6683 }
6684
6685 if (rettv_list_alloc(rettv) == OK)
6686 {
6687 long n1, n2;
6688
Bram Moolenaar4f974752019-02-17 17:44:42 +01006689# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006690 n1 = res.HighPart;
6691 n2 = res.LowPart;
6692# else
6693 n1 = res.tv_sec;
6694 n2 = res.tv_usec;
6695# endif
6696 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
6697 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
6698 }
6699#endif
6700}
6701
6702#ifdef FEAT_FLOAT
6703/*
6704 * "reltimefloat()" function
6705 */
6706 static void
6707f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
6708{
6709# ifdef FEAT_RELTIME
6710 proftime_T tm;
6711# endif
6712
6713 rettv->v_type = VAR_FLOAT;
6714 rettv->vval.v_float = 0;
6715# ifdef FEAT_RELTIME
6716 if (list2proftime(&argvars[0], &tm) == OK)
6717 rettv->vval.v_float = profile_float(&tm);
6718# endif
6719}
6720#endif
6721
6722/*
6723 * "reltimestr()" function
6724 */
6725 static void
6726f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
6727{
6728#ifdef FEAT_RELTIME
6729 proftime_T tm;
6730#endif
6731
6732 rettv->v_type = VAR_STRING;
6733 rettv->vval.v_string = NULL;
6734#ifdef FEAT_RELTIME
6735 if (list2proftime(&argvars[0], &tm) == OK)
6736 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
6737#endif
6738}
6739
6740#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006741 static void
6742make_connection(void)
6743{
6744 if (X_DISPLAY == NULL
6745# ifdef FEAT_GUI
6746 && !gui.in_use
6747# endif
6748 )
6749 {
6750 x_force_connect = TRUE;
6751 setup_term_clip();
6752 x_force_connect = FALSE;
6753 }
6754}
6755
6756 static int
6757check_connection(void)
6758{
6759 make_connection();
6760 if (X_DISPLAY == NULL)
6761 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006762 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006763 return FAIL;
6764 }
6765 return OK;
6766}
6767#endif
6768
6769#ifdef FEAT_CLIENTSERVER
6770 static void
6771remote_common(typval_T *argvars, typval_T *rettv, int expr)
6772{
6773 char_u *server_name;
6774 char_u *keys;
6775 char_u *r = NULL;
6776 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006777 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006778# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006779 HWND w;
6780# else
6781 Window w;
6782# endif
6783
6784 if (check_restricted() || check_secure())
6785 return;
6786
6787# ifdef FEAT_X11
6788 if (check_connection() == FAIL)
6789 return;
6790# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006791 if (argvars[2].v_type != VAR_UNKNOWN
6792 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006793 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006794
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006795 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796 if (server_name == NULL)
6797 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006798 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01006799# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006800 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006801# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006802 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
6803 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006804# endif
6805 {
6806 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006807 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006808 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006809 vim_free(r);
6810 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006811 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006812 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006813 return;
6814 }
6815
6816 rettv->vval.v_string = r;
6817
6818 if (argvars[2].v_type != VAR_UNKNOWN)
6819 {
6820 dictitem_T v;
6821 char_u str[30];
6822 char_u *idvar;
6823
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006824 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006825 if (idvar != NULL && *idvar != NUL)
6826 {
6827 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
6828 v.di_tv.v_type = VAR_STRING;
6829 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006831 vim_free(v.di_tv.vval.v_string);
6832 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006833 }
6834}
6835#endif
6836
6837/*
6838 * "remote_expr()" function
6839 */
6840 static void
6841f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
6842{
6843 rettv->v_type = VAR_STRING;
6844 rettv->vval.v_string = NULL;
6845#ifdef FEAT_CLIENTSERVER
6846 remote_common(argvars, rettv, TRUE);
6847#endif
6848}
6849
6850/*
6851 * "remote_foreground()" function
6852 */
6853 static void
6854f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6855{
6856#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01006857# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006858 /* On Win32 it's done in this application. */
6859 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006860 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006861
6862 if (server_name != NULL)
6863 serverForeground(server_name);
6864 }
6865# else
6866 /* Send a foreground() expression to the server. */
6867 argvars[1].v_type = VAR_STRING;
6868 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
6869 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02006870 rettv->v_type = VAR_STRING;
6871 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006872 remote_common(argvars, rettv, TRUE);
6873 vim_free(argvars[1].vval.v_string);
6874# endif
6875#endif
6876}
6877
6878 static void
6879f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
6880{
6881#ifdef FEAT_CLIENTSERVER
6882 dictitem_T v;
6883 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006884# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006885 long_u n = 0;
6886# endif
6887 char_u *serverid;
6888
6889 if (check_restricted() || check_secure())
6890 {
6891 rettv->vval.v_number = -1;
6892 return;
6893 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006894 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006895 if (serverid == NULL)
6896 {
6897 rettv->vval.v_number = -1;
6898 return; /* type error; errmsg already given */
6899 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01006900# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006901 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
6902 if (n == 0)
6903 rettv->vval.v_number = -1;
6904 else
6905 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006906 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006907 rettv->vval.v_number = (s != NULL);
6908 }
6909# else
6910 if (check_connection() == FAIL)
6911 return;
6912
6913 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
6914 serverStrToWin(serverid), &s);
6915# endif
6916
6917 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
6918 {
6919 char_u *retvar;
6920
6921 v.di_tv.v_type = VAR_STRING;
6922 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006923 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006924 if (retvar != NULL)
6925 set_var(retvar, &v.di_tv, FALSE);
6926 vim_free(v.di_tv.vval.v_string);
6927 }
6928#else
6929 rettv->vval.v_number = -1;
6930#endif
6931}
6932
6933 static void
6934f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
6935{
6936 char_u *r = NULL;
6937
6938#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006939 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006940
6941 if (serverid != NULL && !check_restricted() && !check_secure())
6942 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006943 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006944# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01006945 /* The server's HWND is encoded in the 'id' parameter */
6946 long_u n = 0;
6947# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006948
6949 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006950 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006951
Bram Moolenaar4f974752019-02-17 17:44:42 +01006952# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006953 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
6954 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006955 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006956 if (r == NULL)
6957# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01006958 if (check_connection() == FAIL
6959 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
6960 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006961# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006962 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006963 }
6964#endif
6965 rettv->v_type = VAR_STRING;
6966 rettv->vval.v_string = r;
6967}
6968
6969/*
6970 * "remote_send()" function
6971 */
6972 static void
6973f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
6974{
6975 rettv->v_type = VAR_STRING;
6976 rettv->vval.v_string = NULL;
6977#ifdef FEAT_CLIENTSERVER
6978 remote_common(argvars, rettv, FALSE);
6979#endif
6980}
6981
6982/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006983 * "remote_startserver()" function
6984 */
6985 static void
6986f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6987{
6988#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006989 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006990
6991 if (server == NULL)
6992 return; /* type error; errmsg already given */
6993 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006994 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01006995 else
6996 {
6997# ifdef FEAT_X11
6998 if (check_connection() == OK)
6999 serverRegisterName(X_DISPLAY, server);
7000# else
7001 serverSetName(server);
7002# endif
7003 }
7004#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007005 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01007006#endif
7007}
7008
7009/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007010 * "rename({from}, {to})" function
7011 */
7012 static void
7013f_rename(typval_T *argvars, typval_T *rettv)
7014{
7015 char_u buf[NUMBUFLEN];
7016
7017 if (check_restricted() || check_secure())
7018 rettv->vval.v_number = -1;
7019 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007020 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
7021 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007022}
7023
7024/*
7025 * "repeat()" function
7026 */
7027 static void
7028f_repeat(typval_T *argvars, typval_T *rettv)
7029{
7030 char_u *p;
7031 int n;
7032 int slen;
7033 int len;
7034 char_u *r;
7035 int i;
7036
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007037 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007038 if (argvars[0].v_type == VAR_LIST)
7039 {
7040 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
7041 while (n-- > 0)
7042 if (list_extend(rettv->vval.v_list,
7043 argvars[0].vval.v_list, NULL) == FAIL)
7044 break;
7045 }
7046 else
7047 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007048 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007049 rettv->v_type = VAR_STRING;
7050 rettv->vval.v_string = NULL;
7051
7052 slen = (int)STRLEN(p);
7053 len = slen * n;
7054 if (len <= 0)
7055 return;
7056
7057 r = alloc(len + 1);
7058 if (r != NULL)
7059 {
7060 for (i = 0; i < n; i++)
7061 mch_memmove(r + i * slen, p, (size_t)slen);
7062 r[len] = NUL;
7063 }
7064
7065 rettv->vval.v_string = r;
7066 }
7067}
7068
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069#define SP_NOMOVE 0x01 /* don't move cursor */
7070#define SP_REPEAT 0x02 /* repeat to find outer pair */
7071#define SP_RETCOUNT 0x04 /* return matchcount */
7072#define SP_SETPCMARK 0x08 /* set previous context mark */
7073#define SP_START 0x10 /* accept match at start position */
7074#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
7075#define SP_END 0x40 /* leave cursor at end of match */
7076#define SP_COLUMN 0x80 /* start at cursor column */
7077
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078/*
7079 * Get flags for a search function.
7080 * Possibly sets "p_ws".
7081 * Returns BACKWARD, FORWARD or zero (for an error).
7082 */
7083 static int
7084get_search_arg(typval_T *varp, int *flagsp)
7085{
7086 int dir = FORWARD;
7087 char_u *flags;
7088 char_u nbuf[NUMBUFLEN];
7089 int mask;
7090
7091 if (varp->v_type != VAR_UNKNOWN)
7092 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007093 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007094 if (flags == NULL)
7095 return 0; /* type error; errmsg already given */
7096 while (*flags != NUL)
7097 {
7098 switch (*flags)
7099 {
7100 case 'b': dir = BACKWARD; break;
7101 case 'w': p_ws = TRUE; break;
7102 case 'W': p_ws = FALSE; break;
7103 default: mask = 0;
7104 if (flagsp != NULL)
7105 switch (*flags)
7106 {
7107 case 'c': mask = SP_START; break;
7108 case 'e': mask = SP_END; break;
7109 case 'm': mask = SP_RETCOUNT; break;
7110 case 'n': mask = SP_NOMOVE; break;
7111 case 'p': mask = SP_SUBPAT; break;
7112 case 'r': mask = SP_REPEAT; break;
7113 case 's': mask = SP_SETPCMARK; break;
7114 case 'z': mask = SP_COLUMN; break;
7115 }
7116 if (mask == 0)
7117 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007118 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007119 dir = 0;
7120 }
7121 else
7122 *flagsp |= mask;
7123 }
7124 if (dir == 0)
7125 break;
7126 ++flags;
7127 }
7128 }
7129 return dir;
7130}
7131
7132/*
7133 * Shared by search() and searchpos() functions.
7134 */
7135 static int
7136search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
7137{
7138 int flags;
7139 char_u *pat;
7140 pos_T pos;
7141 pos_T save_cursor;
7142 int save_p_ws = p_ws;
7143 int dir;
7144 int retval = 0; /* default: FAIL */
7145 long lnum_stop = 0;
7146 proftime_T tm;
7147#ifdef FEAT_RELTIME
7148 long time_limit = 0;
7149#endif
7150 int options = SEARCH_KEEP;
7151 int subpatnum;
7152
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007153 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007154 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
7155 if (dir == 0)
7156 goto theend;
7157 flags = *flagsp;
7158 if (flags & SP_START)
7159 options |= SEARCH_START;
7160 if (flags & SP_END)
7161 options |= SEARCH_END;
7162 if (flags & SP_COLUMN)
7163 options |= SEARCH_COL;
7164
7165 /* Optional arguments: line number to stop searching and timeout. */
7166 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
7167 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007168 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007169 if (lnum_stop < 0)
7170 goto theend;
7171#ifdef FEAT_RELTIME
7172 if (argvars[3].v_type != VAR_UNKNOWN)
7173 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007174 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007175 if (time_limit < 0)
7176 goto theend;
7177 }
7178#endif
7179 }
7180
7181#ifdef FEAT_RELTIME
7182 /* Set the time limit, if there is one. */
7183 profile_setlimit(time_limit, &tm);
7184#endif
7185
7186 /*
7187 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
7188 * Check to make sure only those flags are set.
7189 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
7190 * flags cannot be set. Check for that condition also.
7191 */
7192 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
7193 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7194 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007195 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007196 goto theend;
7197 }
7198
7199 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007200 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007201 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007202 if (subpatnum != FAIL)
7203 {
7204 if (flags & SP_SUBPAT)
7205 retval = subpatnum;
7206 else
7207 retval = pos.lnum;
7208 if (flags & SP_SETPCMARK)
7209 setpcmark();
7210 curwin->w_cursor = pos;
7211 if (match_pos != NULL)
7212 {
7213 /* Store the match cursor position */
7214 match_pos->lnum = pos.lnum;
7215 match_pos->col = pos.col + 1;
7216 }
7217 /* "/$" will put the cursor after the end of the line, may need to
7218 * correct that here */
7219 check_cursor();
7220 }
7221
7222 /* If 'n' flag is used: restore cursor position. */
7223 if (flags & SP_NOMOVE)
7224 curwin->w_cursor = save_cursor;
7225 else
7226 curwin->w_set_curswant = TRUE;
7227theend:
7228 p_ws = save_p_ws;
7229
7230 return retval;
7231}
7232
7233#ifdef FEAT_FLOAT
7234
7235/*
7236 * round() is not in C90, use ceil() or floor() instead.
7237 */
7238 float_T
7239vim_round(float_T f)
7240{
7241 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
7242}
7243
7244/*
7245 * "round({float})" function
7246 */
7247 static void
7248f_round(typval_T *argvars, typval_T *rettv)
7249{
7250 float_T f = 0.0;
7251
7252 rettv->v_type = VAR_FLOAT;
7253 if (get_float_arg(argvars, &f) == OK)
7254 rettv->vval.v_float = vim_round(f);
7255 else
7256 rettv->vval.v_float = 0.0;
7257}
7258#endif
7259
Bram Moolenaare99be0e2019-03-26 22:51:09 +01007260#ifdef FEAT_RUBY
7261/*
7262 * "rubyeval()" function
7263 */
7264 static void
7265f_rubyeval(typval_T *argvars, typval_T *rettv)
7266{
7267 char_u *str;
7268 char_u buf[NUMBUFLEN];
7269
7270 str = tv_get_string_buf(&argvars[0], buf);
7271 do_rubyeval(str, rettv);
7272}
7273#endif
7274
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007275/*
7276 * "screenattr()" function
7277 */
7278 static void
7279f_screenattr(typval_T *argvars, typval_T *rettv)
7280{
7281 int row;
7282 int col;
7283 int c;
7284
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007285 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7286 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007287 if (row < 0 || row >= screen_Rows
7288 || col < 0 || col >= screen_Columns)
7289 c = -1;
7290 else
7291 c = ScreenAttrs[LineOffset[row] + col];
7292 rettv->vval.v_number = c;
7293}
7294
7295/*
7296 * "screenchar()" function
7297 */
7298 static void
7299f_screenchar(typval_T *argvars, typval_T *rettv)
7300{
7301 int row;
7302 int col;
7303 int off;
7304 int c;
7305
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007306 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7307 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007308 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007309 c = -1;
7310 else
7311 {
7312 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007313 if (enc_utf8 && ScreenLinesUC[off] != 0)
7314 c = ScreenLinesUC[off];
7315 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007316 c = ScreenLines[off];
7317 }
7318 rettv->vval.v_number = c;
7319}
7320
7321/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007322 * "screenchars()" function
7323 */
7324 static void
7325f_screenchars(typval_T *argvars, typval_T *rettv)
7326{
7327 int row;
7328 int col;
7329 int off;
7330 int c;
7331 int i;
7332
7333 if (rettv_list_alloc(rettv) == FAIL)
7334 return;
7335 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7336 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7337 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7338 return;
7339
7340 off = LineOffset[row] + col;
7341 if (enc_utf8 && ScreenLinesUC[off] != 0)
7342 c = ScreenLinesUC[off];
7343 else
7344 c = ScreenLines[off];
7345 list_append_number(rettv->vval.v_list, (varnumber_T)c);
7346
7347 if (enc_utf8)
7348
7349 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7350 list_append_number(rettv->vval.v_list,
7351 (varnumber_T)ScreenLinesC[i][off]);
7352}
7353
7354/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007355 * "screencol()" function
7356 *
7357 * First column is 1 to be consistent with virtcol().
7358 */
7359 static void
7360f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
7361{
7362 rettv->vval.v_number = screen_screencol() + 1;
7363}
7364
7365/*
7366 * "screenrow()" function
7367 */
7368 static void
7369f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
7370{
7371 rettv->vval.v_number = screen_screenrow() + 1;
7372}
7373
7374/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01007375 * "screenstring()" function
7376 */
7377 static void
7378f_screenstring(typval_T *argvars, typval_T *rettv)
7379{
7380 int row;
7381 int col;
7382 int off;
7383 int c;
7384 int i;
7385 char_u buf[MB_MAXBYTES + 1];
7386 int buflen = 0;
7387
7388 rettv->vval.v_string = NULL;
7389 rettv->v_type = VAR_STRING;
7390
7391 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
7392 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
7393 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
7394 return;
7395
7396 off = LineOffset[row] + col;
7397 if (enc_utf8 && ScreenLinesUC[off] != 0)
7398 c = ScreenLinesUC[off];
7399 else
7400 c = ScreenLines[off];
7401 buflen += mb_char2bytes(c, buf);
7402
7403 if (enc_utf8)
7404 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
7405 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
7406
7407 buf[buflen] = NUL;
7408 rettv->vval.v_string = vim_strsave(buf);
7409}
7410
7411/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412 * "search()" function
7413 */
7414 static void
7415f_search(typval_T *argvars, typval_T *rettv)
7416{
7417 int flags = 0;
7418
7419 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
7420}
7421
7422/*
7423 * "searchdecl()" function
7424 */
7425 static void
7426f_searchdecl(typval_T *argvars, typval_T *rettv)
7427{
7428 int locally = 1;
7429 int thisblock = 0;
7430 int error = FALSE;
7431 char_u *name;
7432
7433 rettv->vval.v_number = 1; /* default: FAIL */
7434
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007435 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007436 if (argvars[1].v_type != VAR_UNKNOWN)
7437 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007438 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007439 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007440 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007441 }
7442 if (!error && name != NULL)
7443 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
7444 locally, thisblock, SEARCH_KEEP) == FAIL;
7445}
7446
7447/*
7448 * Used by searchpair() and searchpairpos()
7449 */
7450 static int
7451searchpair_cmn(typval_T *argvars, pos_T *match_pos)
7452{
7453 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01007454 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007455 int save_p_ws = p_ws;
7456 int dir;
7457 int flags = 0;
7458 char_u nbuf1[NUMBUFLEN];
7459 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007460 int retval = 0; /* default: FAIL */
7461 long lnum_stop = 0;
7462 long time_limit = 0;
7463
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007464 /* Get the three pattern arguments: start, middle, end. Will result in an
7465 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007466 spat = tv_get_string_chk(&argvars[0]);
7467 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
7468 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007469 if (spat == NULL || mpat == NULL || epat == NULL)
7470 goto theend; /* type error */
7471
7472 /* Handle the optional fourth argument: flags */
7473 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
7474 if (dir == 0)
7475 goto theend;
7476
7477 /* Don't accept SP_END or SP_SUBPAT.
7478 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
7479 */
7480 if ((flags & (SP_END | SP_SUBPAT)) != 0
7481 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
7482 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007483 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007484 goto theend;
7485 }
7486
7487 /* Using 'r' implies 'W', otherwise it doesn't work. */
7488 if (flags & SP_REPEAT)
7489 p_ws = FALSE;
7490
7491 /* Optional fifth argument: skip expression */
7492 if (argvars[3].v_type == VAR_UNKNOWN
7493 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01007494 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495 else
7496 {
Bram Moolenaar48570482017-10-30 21:48:41 +01007497 skip = &argvars[4];
7498 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
7499 && skip->v_type != VAR_STRING)
7500 {
7501 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007502 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01007503 goto theend;
7504 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007505 if (argvars[5].v_type != VAR_UNKNOWN)
7506 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007507 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007508 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007509 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007510 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007511 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007512 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007513#ifdef FEAT_RELTIME
7514 if (argvars[6].v_type != VAR_UNKNOWN)
7515 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007516 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007517 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007518 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007519 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007520 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02007521 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007522 }
7523#endif
7524 }
7525 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007526
7527 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
7528 match_pos, lnum_stop, time_limit);
7529
7530theend:
7531 p_ws = save_p_ws;
7532
7533 return retval;
7534}
7535
7536/*
7537 * "searchpair()" function
7538 */
7539 static void
7540f_searchpair(typval_T *argvars, typval_T *rettv)
7541{
7542 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
7543}
7544
7545/*
7546 * "searchpairpos()" function
7547 */
7548 static void
7549f_searchpairpos(typval_T *argvars, typval_T *rettv)
7550{
7551 pos_T match_pos;
7552 int lnum = 0;
7553 int col = 0;
7554
7555 if (rettv_list_alloc(rettv) == FAIL)
7556 return;
7557
7558 if (searchpair_cmn(argvars, &match_pos) > 0)
7559 {
7560 lnum = match_pos.lnum;
7561 col = match_pos.col;
7562 }
7563
7564 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7565 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7566}
7567
7568/*
7569 * Search for a start/middle/end thing.
7570 * Used by searchpair(), see its documentation for the details.
7571 * Returns 0 or -1 for no match,
7572 */
7573 long
7574do_searchpair(
7575 char_u *spat, /* start pattern */
7576 char_u *mpat, /* middle pattern */
7577 char_u *epat, /* end pattern */
7578 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01007579 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007580 int flags, /* SP_SETPCMARK and other SP_ values */
7581 pos_T *match_pos,
7582 linenr_T lnum_stop, /* stop at this line if not zero */
7583 long time_limit UNUSED) /* stop after this many msec */
7584{
7585 char_u *save_cpo;
7586 char_u *pat, *pat2 = NULL, *pat3 = NULL;
7587 long retval = 0;
7588 pos_T pos;
7589 pos_T firstpos;
7590 pos_T foundpos;
7591 pos_T save_cursor;
7592 pos_T save_pos;
7593 int n;
7594 int r;
7595 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01007596 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007597 int err;
7598 int options = SEARCH_KEEP;
7599 proftime_T tm;
7600
7601 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7602 save_cpo = p_cpo;
7603 p_cpo = empty_option;
7604
7605#ifdef FEAT_RELTIME
7606 /* Set the time limit, if there is one. */
7607 profile_setlimit(time_limit, &tm);
7608#endif
7609
7610 /* Make two search patterns: start/end (pat2, for in nested pairs) and
7611 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02007612 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
7613 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007614 if (pat2 == NULL || pat3 == NULL)
7615 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007616 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007617 if (*mpat == NUL)
7618 STRCPY(pat3, pat2);
7619 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01007620 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007621 spat, epat, mpat);
7622 if (flags & SP_START)
7623 options |= SEARCH_START;
7624
Bram Moolenaar48570482017-10-30 21:48:41 +01007625 if (skip != NULL)
7626 {
7627 /* Empty string means to not use the skip expression. */
7628 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
7629 use_skip = skip->vval.v_string != NULL
7630 && *skip->vval.v_string != NUL;
7631 }
7632
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007633 save_cursor = curwin->w_cursor;
7634 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007635 CLEAR_POS(&firstpos);
7636 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007637 pat = pat3;
7638 for (;;)
7639 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01007640 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02007641 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007642 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007643 /* didn't find it or found the first match again: FAIL */
7644 break;
7645
7646 if (firstpos.lnum == 0)
7647 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01007648 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007649 {
7650 /* Found the same position again. Can happen with a pattern that
7651 * has "\zs" at the end and searching backwards. Advance one
7652 * character and try again. */
7653 if (dir == BACKWARD)
7654 decl(&pos);
7655 else
7656 incl(&pos);
7657 }
7658 foundpos = pos;
7659
7660 /* clear the start flag to avoid getting stuck here */
7661 options &= ~SEARCH_START;
7662
7663 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01007664 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007665 {
7666 save_pos = curwin->w_cursor;
7667 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01007668 err = FALSE;
7669 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007670 curwin->w_cursor = save_pos;
7671 if (err)
7672 {
7673 /* Evaluating {skip} caused an error, break here. */
7674 curwin->w_cursor = save_cursor;
7675 retval = -1;
7676 break;
7677 }
7678 if (r)
7679 continue;
7680 }
7681
7682 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
7683 {
7684 /* Found end when searching backwards or start when searching
7685 * forward: nested pair. */
7686 ++nest;
7687 pat = pat2; /* nested, don't search for middle */
7688 }
7689 else
7690 {
7691 /* Found end when searching forward or start when searching
7692 * backward: end of (nested) pair; or found middle in outer pair. */
7693 if (--nest == 1)
7694 pat = pat3; /* outer level, search for middle */
7695 }
7696
7697 if (nest == 0)
7698 {
7699 /* Found the match: return matchcount or line number. */
7700 if (flags & SP_RETCOUNT)
7701 ++retval;
7702 else
7703 retval = pos.lnum;
7704 if (flags & SP_SETPCMARK)
7705 setpcmark();
7706 curwin->w_cursor = pos;
7707 if (!(flags & SP_REPEAT))
7708 break;
7709 nest = 1; /* search for next unmatched */
7710 }
7711 }
7712
7713 if (match_pos != NULL)
7714 {
7715 /* Store the match cursor position */
7716 match_pos->lnum = curwin->w_cursor.lnum;
7717 match_pos->col = curwin->w_cursor.col + 1;
7718 }
7719
7720 /* If 'n' flag is used or search failed: restore cursor position. */
7721 if ((flags & SP_NOMOVE) || retval == 0)
7722 curwin->w_cursor = save_cursor;
7723
7724theend:
7725 vim_free(pat2);
7726 vim_free(pat3);
7727 if (p_cpo == empty_option)
7728 p_cpo = save_cpo;
7729 else
7730 /* Darn, evaluating the {skip} expression changed the value. */
7731 free_string_option(save_cpo);
7732
7733 return retval;
7734}
7735
7736/*
7737 * "searchpos()" function
7738 */
7739 static void
7740f_searchpos(typval_T *argvars, typval_T *rettv)
7741{
7742 pos_T match_pos;
7743 int lnum = 0;
7744 int col = 0;
7745 int n;
7746 int flags = 0;
7747
7748 if (rettv_list_alloc(rettv) == FAIL)
7749 return;
7750
7751 n = search_cmn(argvars, &match_pos, &flags);
7752 if (n > 0)
7753 {
7754 lnum = match_pos.lnum;
7755 col = match_pos.col;
7756 }
7757
7758 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
7759 list_append_number(rettv->vval.v_list, (varnumber_T)col);
7760 if (flags & SP_SUBPAT)
7761 list_append_number(rettv->vval.v_list, (varnumber_T)n);
7762}
7763
7764 static void
7765f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
7766{
7767#ifdef FEAT_CLIENTSERVER
7768 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007769 char_u *server = tv_get_string_chk(&argvars[0]);
7770 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007771
7772 rettv->vval.v_number = -1;
7773 if (server == NULL || reply == NULL)
7774 return;
7775 if (check_restricted() || check_secure())
7776 return;
7777# ifdef FEAT_X11
7778 if (check_connection() == FAIL)
7779 return;
7780# endif
7781
7782 if (serverSendReply(server, reply) < 0)
7783 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007784 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007785 return;
7786 }
7787 rettv->vval.v_number = 0;
7788#else
7789 rettv->vval.v_number = -1;
7790#endif
7791}
7792
7793 static void
7794f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
7795{
7796 char_u *r = NULL;
7797
7798#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01007799# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007800 r = serverGetVimNames();
7801# else
7802 make_connection();
7803 if (X_DISPLAY != NULL)
7804 r = serverGetVimNames(X_DISPLAY);
7805# endif
7806#endif
7807 rettv->v_type = VAR_STRING;
7808 rettv->vval.v_string = r;
7809}
7810
7811/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007812 * "setbufline()" function
7813 */
7814 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02007815f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007816{
7817 linenr_T lnum;
7818 buf_T *buf;
7819
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01007820 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007821 if (buf == NULL)
7822 rettv->vval.v_number = 1; /* FAIL */
7823 else
7824 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007825 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02007826 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02007827 }
7828}
7829
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007830 static void
7831f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
7832{
7833 dict_T *d;
7834 dictitem_T *di;
7835 char_u *csearch;
7836
7837 if (argvars[0].v_type != VAR_DICT)
7838 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007839 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007840 return;
7841 }
7842
7843 if ((d = argvars[0].vval.v_dict) != NULL)
7844 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01007845 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846 if (csearch != NULL)
7847 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007848 if (enc_utf8)
7849 {
7850 int pcc[MAX_MCO];
7851 int c = utfc_ptr2char(csearch, pcc);
7852
7853 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
7854 }
7855 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007856 set_last_csearch(PTR2CHAR(csearch),
7857 csearch, MB_PTR2LEN(csearch));
7858 }
7859
7860 di = dict_find(d, (char_u *)"forward", -1);
7861 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007862 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007863 ? FORWARD : BACKWARD);
7864
7865 di = dict_find(d, (char_u *)"until", -1);
7866 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007867 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007868 }
7869}
7870
7871/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02007872 * "setenv()" function
7873 */
7874 static void
7875f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
7876{
7877 char_u namebuf[NUMBUFLEN];
7878 char_u valbuf[NUMBUFLEN];
7879 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
7880
7881 if (argvars[1].v_type == VAR_SPECIAL
7882 && argvars[1].vval.v_number == VVAL_NULL)
7883 vim_unsetenv(name);
7884 else
7885 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
7886}
7887
7888/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007889 * "setfperm({fname}, {mode})" function
7890 */
7891 static void
7892f_setfperm(typval_T *argvars, typval_T *rettv)
7893{
7894 char_u *fname;
7895 char_u modebuf[NUMBUFLEN];
7896 char_u *mode_str;
7897 int i;
7898 int mask;
7899 int mode = 0;
7900
7901 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007902 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007903 if (fname == NULL)
7904 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007905 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007906 if (mode_str == NULL)
7907 return;
7908 if (STRLEN(mode_str) != 9)
7909 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007910 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007911 return;
7912 }
7913
7914 mask = 1;
7915 for (i = 8; i >= 0; --i)
7916 {
7917 if (mode_str[i] != '-')
7918 mode |= mask;
7919 mask = mask << 1;
7920 }
7921 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
7922}
7923
7924/*
7925 * "setline()" function
7926 */
7927 static void
7928f_setline(typval_T *argvars, typval_T *rettv)
7929{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007930 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007931
Bram Moolenaarca851592018-06-06 21:04:07 +02007932 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007933}
7934
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007935/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007936 * "setpos()" function
7937 */
7938 static void
7939f_setpos(typval_T *argvars, typval_T *rettv)
7940{
7941 pos_T pos;
7942 int fnum;
7943 char_u *name;
7944 colnr_T curswant = -1;
7945
7946 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007947 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007948 if (name != NULL)
7949 {
7950 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
7951 {
7952 if (--pos.col < 0)
7953 pos.col = 0;
7954 if (name[0] == '.' && name[1] == NUL)
7955 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007956 /* set cursor; "fnum" is ignored */
7957 curwin->w_cursor = pos;
7958 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007959 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007960 curwin->w_curswant = curswant - 1;
7961 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007962 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01007963 check_cursor();
7964 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007965 }
7966 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
7967 {
7968 /* set mark */
7969 if (setmark_pos(name[1], &pos, fnum) == OK)
7970 rettv->vval.v_number = 0;
7971 }
7972 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007973 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007974 }
7975 }
7976}
7977
7978/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007979 * "setreg()" function
7980 */
7981 static void
7982f_setreg(typval_T *argvars, typval_T *rettv)
7983{
7984 int regname;
7985 char_u *strregname;
7986 char_u *stropt;
7987 char_u *strval;
7988 int append;
7989 char_u yank_type;
7990 long block_len;
7991
7992 block_len = -1;
7993 yank_type = MAUTO;
7994 append = FALSE;
7995
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007996 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007997 rettv->vval.v_number = 1; /* FAIL is default */
7998
7999 if (strregname == NULL)
8000 return; /* type error; errmsg already given */
8001 regname = *strregname;
8002 if (regname == 0 || regname == '@')
8003 regname = '"';
8004
8005 if (argvars[2].v_type != VAR_UNKNOWN)
8006 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008007 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008008 if (stropt == NULL)
8009 return; /* type error */
8010 for (; *stropt != NUL; ++stropt)
8011 switch (*stropt)
8012 {
8013 case 'a': case 'A': /* append */
8014 append = TRUE;
8015 break;
8016 case 'v': case 'c': /* character-wise selection */
8017 yank_type = MCHAR;
8018 break;
8019 case 'V': case 'l': /* line-wise selection */
8020 yank_type = MLINE;
8021 break;
8022 case 'b': case Ctrl_V: /* block-wise selection */
8023 yank_type = MBLOCK;
8024 if (VIM_ISDIGIT(stropt[1]))
8025 {
8026 ++stropt;
8027 block_len = getdigits(&stropt) - 1;
8028 --stropt;
8029 }
8030 break;
8031 }
8032 }
8033
8034 if (argvars[1].v_type == VAR_LIST)
8035 {
8036 char_u **lstval;
8037 char_u **allocval;
8038 char_u buf[NUMBUFLEN];
8039 char_u **curval;
8040 char_u **curallocval;
8041 list_T *ll = argvars[1].vval.v_list;
8042 listitem_T *li;
8043 int len;
8044
8045 /* If the list is NULL handle like an empty list. */
8046 len = ll == NULL ? 0 : ll->lv_len;
8047
8048 /* First half: use for pointers to result lines; second half: use for
8049 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008050 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008051 if (lstval == NULL)
8052 return;
8053 curval = lstval;
8054 allocval = lstval + len + 2;
8055 curallocval = allocval;
8056
8057 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
8058 li = li->li_next)
8059 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008060 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008061 if (strval == NULL)
8062 goto free_lstval;
8063 if (strval == buf)
8064 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008065 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008066 * overwrite the string. */
8067 strval = vim_strsave(buf);
8068 if (strval == NULL)
8069 goto free_lstval;
8070 *curallocval++ = strval;
8071 }
8072 *curval++ = strval;
8073 }
8074 *curval++ = NULL;
8075
8076 write_reg_contents_lst(regname, lstval, -1,
8077 append, yank_type, block_len);
8078free_lstval:
8079 while (curallocval > allocval)
8080 vim_free(*--curallocval);
8081 vim_free(lstval);
8082 }
8083 else
8084 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008085 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 if (strval == NULL)
8087 return;
8088 write_reg_contents_ex(regname, strval, -1,
8089 append, yank_type, block_len);
8090 }
8091 rettv->vval.v_number = 0;
8092}
8093
8094/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008095 * "settagstack()" function
8096 */
8097 static void
8098f_settagstack(typval_T *argvars, typval_T *rettv)
8099{
8100 static char *e_invact2 = N_("E962: Invalid action: '%s'");
8101 win_T *wp;
8102 dict_T *d;
8103 int action = 'r';
8104
8105 rettv->vval.v_number = -1;
8106
8107 // first argument: window number or id
8108 wp = find_win_by_nr_or_id(&argvars[0]);
8109 if (wp == NULL)
8110 return;
8111
8112 // second argument: dict with items to set in the tag stack
8113 if (argvars[1].v_type != VAR_DICT)
8114 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008115 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008116 return;
8117 }
8118 d = argvars[1].vval.v_dict;
8119 if (d == NULL)
8120 return;
8121
8122 // third argument: action - 'a' for append and 'r' for replace.
8123 // default is to replace the stack.
8124 if (argvars[2].v_type == VAR_UNKNOWN)
8125 action = 'r';
8126 else if (argvars[2].v_type == VAR_STRING)
8127 {
8128 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008129 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008130 if (actstr == NULL)
8131 return;
8132 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
8133 action = *actstr;
8134 else
8135 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008136 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008137 return;
8138 }
8139 }
8140 else
8141 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008142 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01008143 return;
8144 }
8145
8146 if (set_tagstack(wp, d, action) == OK)
8147 rettv->vval.v_number = 0;
8148}
8149
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008150#ifdef FEAT_CRYPT
8151/*
8152 * "sha256({string})" function
8153 */
8154 static void
8155f_sha256(typval_T *argvars, typval_T *rettv)
8156{
8157 char_u *p;
8158
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008159 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160 rettv->vval.v_string = vim_strsave(
8161 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
8162 rettv->v_type = VAR_STRING;
8163}
8164#endif /* FEAT_CRYPT */
8165
8166/*
8167 * "shellescape({string})" function
8168 */
8169 static void
8170f_shellescape(typval_T *argvars, typval_T *rettv)
8171{
Bram Moolenaar20615522017-06-05 18:46:26 +02008172 int do_special = non_zero_arg(&argvars[1]);
8173
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008174 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008175 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 rettv->v_type = VAR_STRING;
8177}
8178
8179/*
8180 * shiftwidth() function
8181 */
8182 static void
8183f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
8184{
Bram Moolenaarf9514162018-11-22 03:08:29 +01008185 rettv->vval.v_number = 0;
8186
8187 if (argvars[0].v_type != VAR_UNKNOWN)
8188 {
8189 long col;
8190
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008191 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01008192 if (col < 0)
8193 return; // type error; errmsg already given
8194#ifdef FEAT_VARTABS
8195 rettv->vval.v_number = get_sw_value_col(curbuf, col);
8196 return;
8197#endif
8198 }
8199
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008200 rettv->vval.v_number = get_sw_value(curbuf);
8201}
8202
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008203#ifdef FEAT_FLOAT
8204/*
8205 * "sin()" function
8206 */
8207 static void
8208f_sin(typval_T *argvars, typval_T *rettv)
8209{
8210 float_T f = 0.0;
8211
8212 rettv->v_type = VAR_FLOAT;
8213 if (get_float_arg(argvars, &f) == OK)
8214 rettv->vval.v_float = sin(f);
8215 else
8216 rettv->vval.v_float = 0.0;
8217}
8218
8219/*
8220 * "sinh()" function
8221 */
8222 static void
8223f_sinh(typval_T *argvars, typval_T *rettv)
8224{
8225 float_T f = 0.0;
8226
8227 rettv->v_type = VAR_FLOAT;
8228 if (get_float_arg(argvars, &f) == OK)
8229 rettv->vval.v_float = sinh(f);
8230 else
8231 rettv->vval.v_float = 0.0;
8232}
8233#endif
8234
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008235/*
8236 * "soundfold({word})" function
8237 */
8238 static void
8239f_soundfold(typval_T *argvars, typval_T *rettv)
8240{
8241 char_u *s;
8242
8243 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008244 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008245#ifdef FEAT_SPELL
8246 rettv->vval.v_string = eval_soundfold(s);
8247#else
8248 rettv->vval.v_string = vim_strsave(s);
8249#endif
8250}
8251
8252/*
8253 * "spellbadword()" function
8254 */
8255 static void
8256f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
8257{
8258 char_u *word = (char_u *)"";
8259 hlf_T attr = HLF_COUNT;
8260 int len = 0;
8261
8262 if (rettv_list_alloc(rettv) == FAIL)
8263 return;
8264
8265#ifdef FEAT_SPELL
8266 if (argvars[0].v_type == VAR_UNKNOWN)
8267 {
8268 /* Find the start and length of the badly spelled word. */
8269 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
8270 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008271 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008272 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01008273 curwin->w_set_curswant = TRUE;
8274 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008275 }
8276 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
8277 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008278 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008279 int capcol = -1;
8280
8281 if (str != NULL)
8282 {
8283 /* Check the argument for spelling. */
8284 while (*str != NUL)
8285 {
8286 len = spell_check(curwin, str, &attr, &capcol, FALSE);
8287 if (attr != HLF_COUNT)
8288 {
8289 word = str;
8290 break;
8291 }
8292 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02008293 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02008294 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008295 }
8296 }
8297 }
8298#endif
8299
8300 list_append_string(rettv->vval.v_list, word, len);
8301 list_append_string(rettv->vval.v_list, (char_u *)(
8302 attr == HLF_SPB ? "bad" :
8303 attr == HLF_SPR ? "rare" :
8304 attr == HLF_SPL ? "local" :
8305 attr == HLF_SPC ? "caps" :
8306 ""), -1);
8307}
8308
8309/*
8310 * "spellsuggest()" function
8311 */
8312 static void
8313f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
8314{
8315#ifdef FEAT_SPELL
8316 char_u *str;
8317 int typeerr = FALSE;
8318 int maxcount;
8319 garray_T ga;
8320 int i;
8321 listitem_T *li;
8322 int need_capital = FALSE;
8323#endif
8324
8325 if (rettv_list_alloc(rettv) == FAIL)
8326 return;
8327
8328#ifdef FEAT_SPELL
8329 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
8330 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008331 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008332 if (argvars[1].v_type != VAR_UNKNOWN)
8333 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008334 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008335 if (maxcount <= 0)
8336 return;
8337 if (argvars[2].v_type != VAR_UNKNOWN)
8338 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008339 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008340 if (typeerr)
8341 return;
8342 }
8343 }
8344 else
8345 maxcount = 25;
8346
8347 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
8348
8349 for (i = 0; i < ga.ga_len; ++i)
8350 {
8351 str = ((char_u **)ga.ga_data)[i];
8352
8353 li = listitem_alloc();
8354 if (li == NULL)
8355 vim_free(str);
8356 else
8357 {
8358 li->li_tv.v_type = VAR_STRING;
8359 li->li_tv.v_lock = 0;
8360 li->li_tv.vval.v_string = str;
8361 list_append(rettv->vval.v_list, li);
8362 }
8363 }
8364 ga_clear(&ga);
8365 }
8366#endif
8367}
8368
8369 static void
8370f_split(typval_T *argvars, typval_T *rettv)
8371{
8372 char_u *str;
8373 char_u *end;
8374 char_u *pat = NULL;
8375 regmatch_T regmatch;
8376 char_u patbuf[NUMBUFLEN];
8377 char_u *save_cpo;
8378 int match;
8379 colnr_T col = 0;
8380 int keepempty = FALSE;
8381 int typeerr = FALSE;
8382
8383 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8384 save_cpo = p_cpo;
8385 p_cpo = (char_u *)"";
8386
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008387 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008388 if (argvars[1].v_type != VAR_UNKNOWN)
8389 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008390 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008391 if (pat == NULL)
8392 typeerr = TRUE;
8393 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008394 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008395 }
8396 if (pat == NULL || *pat == NUL)
8397 pat = (char_u *)"[\\x01- ]\\+";
8398
8399 if (rettv_list_alloc(rettv) == FAIL)
8400 return;
8401 if (typeerr)
8402 return;
8403
8404 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8405 if (regmatch.regprog != NULL)
8406 {
8407 regmatch.rm_ic = FALSE;
8408 while (*str != NUL || keepempty)
8409 {
8410 if (*str == NUL)
8411 match = FALSE; /* empty item at the end */
8412 else
8413 match = vim_regexec_nl(&regmatch, str, col);
8414 if (match)
8415 end = regmatch.startp[0];
8416 else
8417 end = str + STRLEN(str);
8418 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
8419 && *str != NUL && match && end < regmatch.endp[0]))
8420 {
8421 if (list_append_string(rettv->vval.v_list, str,
8422 (int)(end - str)) == FAIL)
8423 break;
8424 }
8425 if (!match)
8426 break;
Bram Moolenaar13505972019-01-24 15:04:48 +01008427 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008428 if (regmatch.endp[0] > str)
8429 col = 0;
8430 else
Bram Moolenaar13505972019-01-24 15:04:48 +01008431 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008432 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008433 str = regmatch.endp[0];
8434 }
8435
8436 vim_regfree(regmatch.regprog);
8437 }
8438
8439 p_cpo = save_cpo;
8440}
8441
8442#ifdef FEAT_FLOAT
8443/*
8444 * "sqrt()" function
8445 */
8446 static void
8447f_sqrt(typval_T *argvars, typval_T *rettv)
8448{
8449 float_T f = 0.0;
8450
8451 rettv->v_type = VAR_FLOAT;
8452 if (get_float_arg(argvars, &f) == OK)
8453 rettv->vval.v_float = sqrt(f);
8454 else
8455 rettv->vval.v_float = 0.0;
8456}
8457
8458/*
8459 * "str2float()" function
8460 */
8461 static void
8462f_str2float(typval_T *argvars, typval_T *rettv)
8463{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008464 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008465 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008466
Bram Moolenaar08243d22017-01-10 16:12:29 +01008467 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008468 p = skipwhite(p + 1);
8469 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +01008470 if (isneg)
8471 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008472 rettv->v_type = VAR_FLOAT;
8473}
8474#endif
8475
8476/*
Bram Moolenaar9d401282019-04-06 13:18:12 +02008477 * "str2list()" function
8478 */
8479 static void
8480f_str2list(typval_T *argvars, typval_T *rettv)
8481{
8482 char_u *p;
8483 int utf8 = FALSE;
8484
8485 if (rettv_list_alloc(rettv) == FAIL)
8486 return;
8487
8488 if (argvars[1].v_type != VAR_UNKNOWN)
8489 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
8490
8491 p = tv_get_string(&argvars[0]);
8492
8493 if (has_mbyte || utf8)
8494 {
8495 int (*ptr2len)(char_u *);
8496 int (*ptr2char)(char_u *);
8497
8498 if (utf8 || enc_utf8)
8499 {
8500 ptr2len = utf_ptr2len;
8501 ptr2char = utf_ptr2char;
8502 }
8503 else
8504 {
8505 ptr2len = mb_ptr2len;
8506 ptr2char = mb_ptr2char;
8507 }
8508
8509 for ( ; *p != NUL; p += (*ptr2len)(p))
8510 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
8511 }
8512 else
8513 for ( ; *p != NUL; ++p)
8514 list_append_number(rettv->vval.v_list, *p);
8515}
8516
8517/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008518 * "str2nr()" function
8519 */
8520 static void
8521f_str2nr(typval_T *argvars, typval_T *rettv)
8522{
8523 int base = 10;
8524 char_u *p;
8525 varnumber_T n;
8526 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +01008527 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008528
8529 if (argvars[1].v_type != VAR_UNKNOWN)
8530 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008531 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008532 if (base != 2 && base != 8 && base != 10 && base != 16)
8533 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008534 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008535 return;
8536 }
8537 }
8538
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008539 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +01008540 isneg = (*p == '-');
8541 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008542 p = skipwhite(p + 1);
8543 switch (base)
8544 {
8545 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
8546 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
8547 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
8548 default: what = 0;
8549 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +02008550 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
8551 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +01008552 if (isneg)
8553 rettv->vval.v_number = -n;
8554 else
8555 rettv->vval.v_number = n;
8556
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008557}
8558
8559#ifdef HAVE_STRFTIME
8560/*
8561 * "strftime({format}[, {time}])" function
8562 */
8563 static void
8564f_strftime(typval_T *argvars, typval_T *rettv)
8565{
8566 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +02008567 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008568 struct tm *curtime;
8569 time_t seconds;
8570 char_u *p;
8571
8572 rettv->v_type = VAR_STRING;
8573
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008574 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008575 if (argvars[1].v_type == VAR_UNKNOWN)
8576 seconds = time(NULL);
8577 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008578 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +02008579 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008580 /* MSVC returns NULL for an invalid value of seconds. */
8581 if (curtime == NULL)
8582 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
8583 else
8584 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008585 vimconv_T conv;
8586 char_u *enc;
8587
8588 conv.vc_type = CONV_NONE;
8589 enc = enc_locale();
8590 convert_setup(&conv, p_enc, enc);
8591 if (conv.vc_type != CONV_NONE)
8592 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008593 if (p != NULL)
8594 (void)strftime((char *)result_buf, sizeof(result_buf),
8595 (char *)p, curtime);
8596 else
8597 result_buf[0] = NUL;
8598
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008599 if (conv.vc_type != CONV_NONE)
8600 vim_free(p);
8601 convert_setup(&conv, enc, p_enc);
8602 if (conv.vc_type != CONV_NONE)
8603 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
8604 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008605 rettv->vval.v_string = vim_strsave(result_buf);
8606
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008607 /* Release conversion descriptors */
8608 convert_setup(&conv, NULL, NULL);
8609 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008610 }
8611}
8612#endif
8613
8614/*
8615 * "strgetchar()" function
8616 */
8617 static void
8618f_strgetchar(typval_T *argvars, typval_T *rettv)
8619{
8620 char_u *str;
8621 int len;
8622 int error = FALSE;
8623 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +01008624 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008625
8626 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008627 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008628 if (str == NULL)
8629 return;
8630 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008631 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008632 if (error)
8633 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008634
Bram Moolenaar13505972019-01-24 15:04:48 +01008635 while (charidx >= 0 && byteidx < len)
8636 {
8637 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008638 {
Bram Moolenaar13505972019-01-24 15:04:48 +01008639 rettv->vval.v_number = mb_ptr2char(str + byteidx);
8640 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008641 }
Bram Moolenaar13505972019-01-24 15:04:48 +01008642 --charidx;
8643 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008644 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008645}
8646
8647/*
8648 * "stridx()" function
8649 */
8650 static void
8651f_stridx(typval_T *argvars, typval_T *rettv)
8652{
8653 char_u buf[NUMBUFLEN];
8654 char_u *needle;
8655 char_u *haystack;
8656 char_u *save_haystack;
8657 char_u *pos;
8658 int start_idx;
8659
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008660 needle = tv_get_string_chk(&argvars[1]);
8661 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008662 rettv->vval.v_number = -1;
8663 if (needle == NULL || haystack == NULL)
8664 return; /* type error; errmsg already given */
8665
8666 if (argvars[2].v_type != VAR_UNKNOWN)
8667 {
8668 int error = FALSE;
8669
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008670 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008671 if (error || start_idx >= (int)STRLEN(haystack))
8672 return;
8673 if (start_idx >= 0)
8674 haystack += start_idx;
8675 }
8676
8677 pos = (char_u *)strstr((char *)haystack, (char *)needle);
8678 if (pos != NULL)
8679 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
8680}
8681
8682/*
8683 * "string()" function
8684 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +01008685 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008686f_string(typval_T *argvars, typval_T *rettv)
8687{
8688 char_u *tofree;
8689 char_u numbuf[NUMBUFLEN];
8690
8691 rettv->v_type = VAR_STRING;
8692 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
8693 get_copyID());
8694 /* Make a copy if we have a value but it's not in allocated memory. */
8695 if (rettv->vval.v_string != NULL && tofree == NULL)
8696 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
8697}
8698
8699/*
8700 * "strlen()" function
8701 */
8702 static void
8703f_strlen(typval_T *argvars, typval_T *rettv)
8704{
8705 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008706 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008707}
8708
8709/*
8710 * "strchars()" function
8711 */
8712 static void
8713f_strchars(typval_T *argvars, typval_T *rettv)
8714{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008715 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008716 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008717 varnumber_T len = 0;
8718 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008719
8720 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008721 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008722 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008723 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008724 else
8725 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008726 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
8727 while (*s != NUL)
8728 {
8729 func_mb_ptr2char_adv(&s);
8730 ++len;
8731 }
8732 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008733 }
8734}
8735
8736/*
8737 * "strdisplaywidth()" function
8738 */
8739 static void
8740f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
8741{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008742 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008743 int col = 0;
8744
8745 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008746 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008747
8748 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
8749}
8750
8751/*
8752 * "strwidth()" function
8753 */
8754 static void
8755f_strwidth(typval_T *argvars, typval_T *rettv)
8756{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008757 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008758
Bram Moolenaar13505972019-01-24 15:04:48 +01008759 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008760}
8761
8762/*
8763 * "strcharpart()" function
8764 */
8765 static void
8766f_strcharpart(typval_T *argvars, typval_T *rettv)
8767{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008768 char_u *p;
8769 int nchar;
8770 int nbyte = 0;
8771 int charlen;
8772 int len = 0;
8773 int slen;
8774 int error = FALSE;
8775
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008776 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008777 slen = (int)STRLEN(p);
8778
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008779 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008780 if (!error)
8781 {
8782 if (nchar > 0)
8783 while (nchar > 0 && nbyte < slen)
8784 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008785 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008786 --nchar;
8787 }
8788 else
8789 nbyte = nchar;
8790 if (argvars[2].v_type != VAR_UNKNOWN)
8791 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008792 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008793 while (charlen > 0 && nbyte + len < slen)
8794 {
8795 int off = nbyte + len;
8796
8797 if (off < 0)
8798 len += 1;
8799 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +02008800 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008801 --charlen;
8802 }
8803 }
8804 else
8805 len = slen - nbyte; /* default: all bytes that are available. */
8806 }
8807
8808 /*
8809 * Only return the overlap between the specified part and the actual
8810 * string.
8811 */
8812 if (nbyte < 0)
8813 {
8814 len += nbyte;
8815 nbyte = 0;
8816 }
8817 else if (nbyte > slen)
8818 nbyte = slen;
8819 if (len < 0)
8820 len = 0;
8821 else if (nbyte + len > slen)
8822 len = slen - nbyte;
8823
8824 rettv->v_type = VAR_STRING;
8825 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008826}
8827
8828/*
8829 * "strpart()" function
8830 */
8831 static void
8832f_strpart(typval_T *argvars, typval_T *rettv)
8833{
8834 char_u *p;
8835 int n;
8836 int len;
8837 int slen;
8838 int error = FALSE;
8839
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008840 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008841 slen = (int)STRLEN(p);
8842
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008843 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008844 if (error)
8845 len = 0;
8846 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008847 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008848 else
8849 len = slen - n; /* default len: all bytes that are available. */
8850
8851 /*
8852 * Only return the overlap between the specified part and the actual
8853 * string.
8854 */
8855 if (n < 0)
8856 {
8857 len += n;
8858 n = 0;
8859 }
8860 else if (n > slen)
8861 n = slen;
8862 if (len < 0)
8863 len = 0;
8864 else if (n + len > slen)
8865 len = slen - n;
8866
8867 rettv->v_type = VAR_STRING;
8868 rettv->vval.v_string = vim_strnsave(p + n, len);
8869}
8870
8871/*
8872 * "strridx()" function
8873 */
8874 static void
8875f_strridx(typval_T *argvars, typval_T *rettv)
8876{
8877 char_u buf[NUMBUFLEN];
8878 char_u *needle;
8879 char_u *haystack;
8880 char_u *rest;
8881 char_u *lastmatch = NULL;
8882 int haystack_len, end_idx;
8883
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008884 needle = tv_get_string_chk(&argvars[1]);
8885 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008886
8887 rettv->vval.v_number = -1;
8888 if (needle == NULL || haystack == NULL)
8889 return; /* type error; errmsg already given */
8890
8891 haystack_len = (int)STRLEN(haystack);
8892 if (argvars[2].v_type != VAR_UNKNOWN)
8893 {
8894 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008895 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008896 if (end_idx < 0)
8897 return; /* can never find a match */
8898 }
8899 else
8900 end_idx = haystack_len;
8901
8902 if (*needle == NUL)
8903 {
8904 /* Empty string matches past the end. */
8905 lastmatch = haystack + end_idx;
8906 }
8907 else
8908 {
8909 for (rest = haystack; *rest != '\0'; ++rest)
8910 {
8911 rest = (char_u *)strstr((char *)rest, (char *)needle);
8912 if (rest == NULL || rest > haystack + end_idx)
8913 break;
8914 lastmatch = rest;
8915 }
8916 }
8917
8918 if (lastmatch == NULL)
8919 rettv->vval.v_number = -1;
8920 else
8921 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
8922}
8923
8924/*
8925 * "strtrans()" function
8926 */
8927 static void
8928f_strtrans(typval_T *argvars, typval_T *rettv)
8929{
8930 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008931 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008932}
8933
8934/*
8935 * "submatch()" function
8936 */
8937 static void
8938f_submatch(typval_T *argvars, typval_T *rettv)
8939{
8940 int error = FALSE;
8941 int no;
8942 int retList = 0;
8943
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008944 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008945 if (error)
8946 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008947 if (no < 0 || no >= NSUBEXP)
8948 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008949 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +01008950 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +02008951 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008952 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008953 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008954 if (error)
8955 return;
8956
8957 if (retList == 0)
8958 {
8959 rettv->v_type = VAR_STRING;
8960 rettv->vval.v_string = reg_submatch(no);
8961 }
8962 else
8963 {
8964 rettv->v_type = VAR_LIST;
8965 rettv->vval.v_list = reg_submatch_list(no);
8966 }
8967}
8968
8969/*
8970 * "substitute()" function
8971 */
8972 static void
8973f_substitute(typval_T *argvars, typval_T *rettv)
8974{
8975 char_u patbuf[NUMBUFLEN];
8976 char_u subbuf[NUMBUFLEN];
8977 char_u flagsbuf[NUMBUFLEN];
8978
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008979 char_u *str = tv_get_string_chk(&argvars[0]);
8980 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008981 char_u *sub = NULL;
8982 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008983 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008984
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008985 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
8986 expr = &argvars[2];
8987 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008988 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008989
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008990 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008991 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
8992 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008993 rettv->vval.v_string = NULL;
8994 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +02008995 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008996}
8997
8998/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +02008999 * "swapinfo(swap_filename)" function
9000 */
9001 static void
9002f_swapinfo(typval_T *argvars, typval_T *rettv)
9003{
9004 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009005 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +02009006}
9007
9008/*
Bram Moolenaar110bd602018-09-16 18:46:59 +02009009 * "swapname(expr)" function
9010 */
9011 static void
9012f_swapname(typval_T *argvars, typval_T *rettv)
9013{
9014 buf_T *buf;
9015
9016 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009017 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +02009018 if (buf == NULL || buf->b_ml.ml_mfp == NULL
9019 || buf->b_ml.ml_mfp->mf_fname == NULL)
9020 rettv->vval.v_string = NULL;
9021 else
9022 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
9023}
9024
9025/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009026 * "synID(lnum, col, trans)" function
9027 */
9028 static void
9029f_synID(typval_T *argvars UNUSED, typval_T *rettv)
9030{
9031 int id = 0;
9032#ifdef FEAT_SYN_HL
9033 linenr_T lnum;
9034 colnr_T col;
9035 int trans;
9036 int transerr = FALSE;
9037
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009038 lnum = tv_get_lnum(argvars); /* -1 on type error */
9039 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
9040 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009041
9042 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9043 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
9044 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
9045#endif
9046
9047 rettv->vval.v_number = id;
9048}
9049
9050/*
9051 * "synIDattr(id, what [, mode])" function
9052 */
9053 static void
9054f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
9055{
9056 char_u *p = NULL;
9057#ifdef FEAT_SYN_HL
9058 int id;
9059 char_u *what;
9060 char_u *mode;
9061 char_u modebuf[NUMBUFLEN];
9062 int modec;
9063
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009064 id = (int)tv_get_number(&argvars[0]);
9065 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009066 if (argvars[2].v_type != VAR_UNKNOWN)
9067 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009068 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009069 modec = TOLOWER_ASC(mode[0]);
9070 if (modec != 't' && modec != 'c' && modec != 'g')
9071 modec = 0; /* replace invalid with current */
9072 }
9073 else
9074 {
9075#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
9076 if (USE_24BIT)
9077 modec = 'g';
9078 else
9079#endif
9080 if (t_colors > 1)
9081 modec = 'c';
9082 else
9083 modec = 't';
9084 }
9085
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009086 switch (TOLOWER_ASC(what[0]))
9087 {
9088 case 'b':
9089 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
9090 p = highlight_color(id, what, modec);
9091 else /* bold */
9092 p = highlight_has_attr(id, HL_BOLD, modec);
9093 break;
9094
9095 case 'f': /* fg[#] or font */
9096 p = highlight_color(id, what, modec);
9097 break;
9098
9099 case 'i':
9100 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
9101 p = highlight_has_attr(id, HL_INVERSE, modec);
9102 else /* italic */
9103 p = highlight_has_attr(id, HL_ITALIC, modec);
9104 break;
9105
9106 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +02009107 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009108 break;
9109
9110 case 'r': /* reverse */
9111 p = highlight_has_attr(id, HL_INVERSE, modec);
9112 break;
9113
9114 case 's':
9115 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
9116 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +02009117 /* strikeout */
9118 else if (TOLOWER_ASC(what[1]) == 't' &&
9119 TOLOWER_ASC(what[2]) == 'r')
9120 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009121 else /* standout */
9122 p = highlight_has_attr(id, HL_STANDOUT, modec);
9123 break;
9124
9125 case 'u':
9126 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
9127 /* underline */
9128 p = highlight_has_attr(id, HL_UNDERLINE, modec);
9129 else
9130 /* undercurl */
9131 p = highlight_has_attr(id, HL_UNDERCURL, modec);
9132 break;
9133 }
9134
9135 if (p != NULL)
9136 p = vim_strsave(p);
9137#endif
9138 rettv->v_type = VAR_STRING;
9139 rettv->vval.v_string = p;
9140}
9141
9142/*
9143 * "synIDtrans(id)" function
9144 */
9145 static void
9146f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
9147{
9148 int id;
9149
9150#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009151 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009152
9153 if (id > 0)
9154 id = syn_get_final_id(id);
9155 else
9156#endif
9157 id = 0;
9158
9159 rettv->vval.v_number = id;
9160}
9161
9162/*
9163 * "synconcealed(lnum, col)" function
9164 */
9165 static void
9166f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
9167{
9168#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
9169 linenr_T lnum;
9170 colnr_T col;
9171 int syntax_flags = 0;
9172 int cchar;
9173 int matchid = 0;
9174 char_u str[NUMBUFLEN];
9175#endif
9176
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009177 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009178
9179#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009180 lnum = tv_get_lnum(argvars); /* -1 on type error */
9181 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009182
9183 vim_memset(str, NUL, sizeof(str));
9184
9185 if (rettv_list_alloc(rettv) != FAIL)
9186 {
9187 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9188 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9189 && curwin->w_p_cole > 0)
9190 {
9191 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
9192 syntax_flags = get_syntax_info(&matchid);
9193
9194 /* get the conceal character */
9195 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
9196 {
9197 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +02009198 if (cchar == NUL && curwin->w_p_cole == 1)
9199 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009200 if (cchar != NUL)
9201 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009202 if (has_mbyte)
9203 (*mb_char2bytes)(cchar, str);
9204 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009205 str[0] = cchar;
9206 }
9207 }
9208 }
9209
9210 list_append_number(rettv->vval.v_list,
9211 (syntax_flags & HL_CONCEAL) != 0);
9212 /* -1 to auto-determine strlen */
9213 list_append_string(rettv->vval.v_list, str, -1);
9214 list_append_number(rettv->vval.v_list, matchid);
9215 }
9216#endif
9217}
9218
9219/*
9220 * "synstack(lnum, col)" function
9221 */
9222 static void
9223f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
9224{
9225#ifdef FEAT_SYN_HL
9226 linenr_T lnum;
9227 colnr_T col;
9228 int i;
9229 int id;
9230#endif
9231
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009232 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009233
9234#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009235 lnum = tv_get_lnum(argvars); /* -1 on type error */
9236 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009237
9238 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
9239 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
9240 && rettv_list_alloc(rettv) != FAIL)
9241 {
9242 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
9243 for (i = 0; ; ++i)
9244 {
9245 id = syn_get_stack_item(i);
9246 if (id < 0)
9247 break;
9248 if (list_append_number(rettv->vval.v_list, id) == FAIL)
9249 break;
9250 }
9251 }
9252#endif
9253}
9254
9255 static void
9256get_cmd_output_as_rettv(
9257 typval_T *argvars,
9258 typval_T *rettv,
9259 int retlist)
9260{
9261 char_u *res = NULL;
9262 char_u *p;
9263 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009264 int err = FALSE;
9265 FILE *fd;
9266 list_T *list = NULL;
9267 int flags = SHELL_SILENT;
9268
9269 rettv->v_type = VAR_STRING;
9270 rettv->vval.v_string = NULL;
9271 if (check_restricted() || check_secure())
9272 goto errret;
9273
9274 if (argvars[1].v_type != VAR_UNKNOWN)
9275 {
9276 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +01009277 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009278 * command.
9279 */
9280 if ((infile = vim_tempname('i', TRUE)) == NULL)
9281 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009282 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009283 goto errret;
9284 }
9285
9286 fd = mch_fopen((char *)infile, WRITEBIN);
9287 if (fd == NULL)
9288 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009289 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009290 goto errret;
9291 }
Bram Moolenaar12c44922017-01-08 13:26:03 +01009292 if (argvars[1].v_type == VAR_NUMBER)
9293 {
9294 linenr_T lnum;
9295 buf_T *buf;
9296
9297 buf = buflist_findnr(argvars[1].vval.v_number);
9298 if (buf == NULL)
9299 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009300 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +01009301 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +01009302 goto errret;
9303 }
9304
9305 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
9306 {
9307 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
9308 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
9309 {
9310 err = TRUE;
9311 break;
9312 }
9313 if (putc(NL, fd) == EOF)
9314 {
9315 err = TRUE;
9316 break;
9317 }
9318 }
9319 }
9320 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009321 {
9322 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
9323 err = TRUE;
9324 }
9325 else
9326 {
Bram Moolenaar12c44922017-01-08 13:26:03 +01009327 size_t len;
9328 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009329
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009330 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009331 if (p == NULL)
9332 {
9333 fclose(fd);
9334 goto errret; /* type error; errmsg already given */
9335 }
9336 len = STRLEN(p);
9337 if (len > 0 && fwrite(p, len, 1, fd) != 1)
9338 err = TRUE;
9339 }
9340 if (fclose(fd) != 0)
9341 err = TRUE;
9342 if (err)
9343 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009344 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009345 goto errret;
9346 }
9347 }
9348
9349 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
9350 * echoes typeahead, that messes up the display. */
9351 if (!msg_silent)
9352 flags += SHELL_COOKED;
9353
9354 if (retlist)
9355 {
9356 int len;
9357 listitem_T *li;
9358 char_u *s = NULL;
9359 char_u *start;
9360 char_u *end;
9361 int i;
9362
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009363 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009364 if (res == NULL)
9365 goto errret;
9366
9367 list = list_alloc();
9368 if (list == NULL)
9369 goto errret;
9370
9371 for (i = 0; i < len; ++i)
9372 {
9373 start = res + i;
9374 while (i < len && res[i] != NL)
9375 ++i;
9376 end = res + i;
9377
Bram Moolenaar964b3742019-05-24 18:54:09 +02009378 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009379 if (s == NULL)
9380 goto errret;
9381
9382 for (p = s; start < end; ++p, ++start)
9383 *p = *start == NUL ? NL : *start;
9384 *p = NUL;
9385
9386 li = listitem_alloc();
9387 if (li == NULL)
9388 {
9389 vim_free(s);
9390 goto errret;
9391 }
9392 li->li_tv.v_type = VAR_STRING;
9393 li->li_tv.v_lock = 0;
9394 li->li_tv.vval.v_string = s;
9395 list_append(list, li);
9396 }
9397
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009398 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009399 list = NULL;
9400 }
9401 else
9402 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009403 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +01009404#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009405 /* translate <CR><NL> into <NL> */
9406 if (res != NULL)
9407 {
9408 char_u *s, *d;
9409
9410 d = res;
9411 for (s = res; *s; ++s)
9412 {
9413 if (s[0] == CAR && s[1] == NL)
9414 ++s;
9415 *d++ = *s;
9416 }
9417 *d = NUL;
9418 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009419#endif
9420 rettv->vval.v_string = res;
9421 res = NULL;
9422 }
9423
9424errret:
9425 if (infile != NULL)
9426 {
9427 mch_remove(infile);
9428 vim_free(infile);
9429 }
9430 if (res != NULL)
9431 vim_free(res);
9432 if (list != NULL)
9433 list_free(list);
9434}
9435
9436/*
9437 * "system()" function
9438 */
9439 static void
9440f_system(typval_T *argvars, typval_T *rettv)
9441{
9442 get_cmd_output_as_rettv(argvars, rettv, FALSE);
9443}
9444
9445/*
9446 * "systemlist()" function
9447 */
9448 static void
9449f_systemlist(typval_T *argvars, typval_T *rettv)
9450{
9451 get_cmd_output_as_rettv(argvars, rettv, TRUE);
9452}
9453
9454/*
9455 * "tabpagebuflist()" function
9456 */
9457 static void
9458f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9459{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009460 tabpage_T *tp;
9461 win_T *wp = NULL;
9462
9463 if (argvars[0].v_type == VAR_UNKNOWN)
9464 wp = firstwin;
9465 else
9466 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009467 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009468 if (tp != NULL)
9469 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9470 }
9471 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
9472 {
9473 for (; wp != NULL; wp = wp->w_next)
9474 if (list_append_number(rettv->vval.v_list,
9475 wp->w_buffer->b_fnum) == FAIL)
9476 break;
9477 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009478}
9479
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009480/*
9481 * "tabpagenr()" function
9482 */
9483 static void
9484f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
9485{
9486 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487 char_u *arg;
9488
9489 if (argvars[0].v_type != VAR_UNKNOWN)
9490 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009491 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009492 nr = 0;
9493 if (arg != NULL)
9494 {
9495 if (STRCMP(arg, "$") == 0)
9496 nr = tabpage_index(NULL) - 1;
9497 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009498 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009499 }
9500 }
9501 else
9502 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009503 rettv->vval.v_number = nr;
9504}
9505
9506
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009507/*
9508 * Common code for tabpagewinnr() and winnr().
9509 */
9510 static int
9511get_winnr(tabpage_T *tp, typval_T *argvar)
9512{
9513 win_T *twin;
9514 int nr = 1;
9515 win_T *wp;
9516 char_u *arg;
9517
9518 twin = (tp == curtab) ? curwin : tp->tp_curwin;
9519 if (argvar->v_type != VAR_UNKNOWN)
9520 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +02009521 int invalid_arg = FALSE;
9522
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009523 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009524 if (arg == NULL)
9525 nr = 0; /* type error; errmsg already given */
9526 else if (STRCMP(arg, "$") == 0)
9527 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
9528 else if (STRCMP(arg, "#") == 0)
9529 {
9530 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
9531 if (twin == NULL)
9532 nr = 0;
9533 }
9534 else
9535 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +02009536 long count;
9537 char_u *endp;
9538
9539 // Extract the window count (if specified). e.g. winnr('3j')
9540 count = strtol((char *)arg, (char **)&endp, 10);
9541 if (count <= 0)
9542 count = 1; // if count is not specified, default to 1
9543 if (endp != NULL && *endp != '\0')
9544 {
9545 if (STRCMP(endp, "j") == 0)
9546 twin = win_vert_neighbor(tp, twin, FALSE, count);
9547 else if (STRCMP(endp, "k") == 0)
9548 twin = win_vert_neighbor(tp, twin, TRUE, count);
9549 else if (STRCMP(endp, "h") == 0)
9550 twin = win_horz_neighbor(tp, twin, TRUE, count);
9551 else if (STRCMP(endp, "l") == 0)
9552 twin = win_horz_neighbor(tp, twin, FALSE, count);
9553 else
9554 invalid_arg = TRUE;
9555 }
9556 else
9557 invalid_arg = TRUE;
9558 }
9559
9560 if (invalid_arg)
9561 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009562 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009563 nr = 0;
9564 }
9565 }
9566
9567 if (nr > 0)
9568 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
9569 wp != twin; wp = wp->w_next)
9570 {
9571 if (wp == NULL)
9572 {
9573 /* didn't find it in this tabpage */
9574 nr = 0;
9575 break;
9576 }
9577 ++nr;
9578 }
9579 return nr;
9580}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009581
9582/*
9583 * "tabpagewinnr()" function
9584 */
9585 static void
9586f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
9587{
9588 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009589 tabpage_T *tp;
9590
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009591 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009592 if (tp == NULL)
9593 nr = 0;
9594 else
9595 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009596 rettv->vval.v_number = nr;
9597}
9598
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009599/*
9600 * "tagfiles()" function
9601 */
9602 static void
9603f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
9604{
9605 char_u *fname;
9606 tagname_T tn;
9607 int first;
9608
9609 if (rettv_list_alloc(rettv) == FAIL)
9610 return;
9611 fname = alloc(MAXPATHL);
9612 if (fname == NULL)
9613 return;
9614
9615 for (first = TRUE; ; first = FALSE)
9616 if (get_tagfname(&tn, first, fname) == FAIL
9617 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
9618 break;
9619 tagname_free(&tn);
9620 vim_free(fname);
9621}
9622
9623/*
9624 * "taglist()" function
9625 */
9626 static void
9627f_taglist(typval_T *argvars, typval_T *rettv)
9628{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009629 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009630 char_u *tag_pattern;
9631
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009632 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009633
9634 rettv->vval.v_number = FALSE;
9635 if (*tag_pattern == NUL)
9636 return;
9637
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009638 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009639 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009640 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01009641 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009642}
9643
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009644#ifdef FEAT_FLOAT
9645/*
9646 * "tan()" function
9647 */
9648 static void
9649f_tan(typval_T *argvars, typval_T *rettv)
9650{
9651 float_T f = 0.0;
9652
9653 rettv->v_type = VAR_FLOAT;
9654 if (get_float_arg(argvars, &f) == OK)
9655 rettv->vval.v_float = tan(f);
9656 else
9657 rettv->vval.v_float = 0.0;
9658}
9659
9660/*
9661 * "tanh()" function
9662 */
9663 static void
9664f_tanh(typval_T *argvars, typval_T *rettv)
9665{
9666 float_T f = 0.0;
9667
9668 rettv->v_type = VAR_FLOAT;
9669 if (get_float_arg(argvars, &f) == OK)
9670 rettv->vval.v_float = tanh(f);
9671 else
9672 rettv->vval.v_float = 0.0;
9673}
9674#endif
9675
9676/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009677 * Get a callback from "arg". It can be a Funcref or a function name.
9678 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009679 * "cb_name" is not allocated.
9680 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009681 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009682 callback_T
9683get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009684{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009685 callback_T res;
9686
9687 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009688 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
9689 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009690 res.cb_partial = arg->vval.v_partial;
9691 ++res.cb_partial->pt_refcount;
9692 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009693 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009694 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009695 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009696 res.cb_partial = NULL;
9697 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
9698 {
9699 // Note that we don't make a copy of the string.
9700 res.cb_name = arg->vval.v_string;
9701 func_ref(res.cb_name);
9702 }
9703 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
9704 {
9705 res.cb_name = (char_u *)"";
9706 }
9707 else
9708 {
9709 emsg(_("E921: Invalid callback argument"));
9710 res.cb_name = NULL;
9711 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009712 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009713 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009714}
9715
9716/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009717 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009718 */
9719 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009720put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009721{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009722 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009723 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009724 tv->v_type = VAR_PARTIAL;
9725 tv->vval.v_partial = cb->cb_partial;
9726 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009727 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009728 else
9729 {
9730 tv->v_type = VAR_FUNC;
9731 tv->vval.v_string = vim_strsave(cb->cb_name);
9732 func_ref(cb->cb_name);
9733 }
9734}
9735
9736/*
9737 * Make a copy of "src" into "dest", allocating the function name if needed,
9738 * without incrementing the refcount.
9739 */
9740 void
9741set_callback(callback_T *dest, callback_T *src)
9742{
9743 if (src->cb_partial == NULL)
9744 {
9745 // just a function name, make a copy
9746 dest->cb_name = vim_strsave(src->cb_name);
9747 dest->cb_free_name = TRUE;
9748 }
9749 else
9750 {
9751 // cb_name is a pointer into cb_partial
9752 dest->cb_name = src->cb_name;
9753 dest->cb_free_name = FALSE;
9754 }
9755 dest->cb_partial = src->cb_partial;
9756}
9757
9758/*
9759 * Unref/free "callback" returned by get_callback() or set_callback().
9760 */
9761 void
9762free_callback(callback_T *callback)
9763{
9764 if (callback->cb_partial != NULL)
9765 {
9766 partial_unref(callback->cb_partial);
9767 callback->cb_partial = NULL;
9768 }
9769 else if (callback->cb_name != NULL)
9770 func_unref(callback->cb_name);
9771 if (callback->cb_free_name)
9772 {
9773 vim_free(callback->cb_name);
9774 callback->cb_free_name = FALSE;
9775 }
9776 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009777}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009778
9779#ifdef FEAT_TIMERS
9780/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02009781 * "timer_info([timer])" function
9782 */
9783 static void
9784f_timer_info(typval_T *argvars, typval_T *rettv)
9785{
9786 timer_T *timer = NULL;
9787
9788 if (rettv_list_alloc(rettv) != OK)
9789 return;
9790 if (argvars[0].v_type != VAR_UNKNOWN)
9791 {
9792 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009793 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02009794 else
9795 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009796 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +02009797 if (timer != NULL)
9798 add_timer_info(rettv, timer);
9799 }
9800 }
9801 else
9802 add_timer_info_all(rettv);
9803}
9804
9805/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009806 * "timer_pause(timer, paused)" function
9807 */
9808 static void
9809f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
9810{
9811 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009812 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009813
9814 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009815 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009816 else
9817 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009818 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009819 if (timer != NULL)
9820 timer->tr_paused = paused;
9821 }
9822}
9823
9824/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009825 * "timer_start(time, callback [, options])" function
9826 */
9827 static void
9828f_timer_start(typval_T *argvars, typval_T *rettv)
9829{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009830 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +02009831 timer_T *timer;
9832 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009833 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +02009834 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009835
Bram Moolenaar75537a92016-09-05 22:45:28 +02009836 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009837 if (check_secure())
9838 return;
9839 if (argvars[2].v_type != VAR_UNKNOWN)
9840 {
9841 if (argvars[2].v_type != VAR_DICT
9842 || (dict = argvars[2].vval.v_dict) == NULL)
9843 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009844 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009845 return;
9846 }
9847 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01009848 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009849 }
9850
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009851 callback = get_callback(&argvars[1]);
9852 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +02009853 return;
9854
9855 timer = create_timer(msec, repeat);
9856 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009857 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009858 else
9859 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +02009860 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +02009861 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009862 }
9863}
9864
9865/*
9866 * "timer_stop(timer)" function
9867 */
9868 static void
9869f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
9870{
9871 timer_T *timer;
9872
9873 if (argvars[0].v_type != VAR_NUMBER)
9874 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009875 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009876 return;
9877 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009878 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009879 if (timer != NULL)
9880 stop_timer(timer);
9881}
Bram Moolenaarb73598e2016-08-07 18:22:53 +02009882
9883/*
9884 * "timer_stopall()" function
9885 */
9886 static void
9887f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9888{
9889 stop_all_timers();
9890}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009891#endif
9892
9893/*
9894 * "tolower(string)" function
9895 */
9896 static void
9897f_tolower(typval_T *argvars, typval_T *rettv)
9898{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009899 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009900 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009901}
9902
9903/*
9904 * "toupper(string)" function
9905 */
9906 static void
9907f_toupper(typval_T *argvars, typval_T *rettv)
9908{
9909 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009910 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009911}
9912
9913/*
9914 * "tr(string, fromstr, tostr)" function
9915 */
9916 static void
9917f_tr(typval_T *argvars, typval_T *rettv)
9918{
9919 char_u *in_str;
9920 char_u *fromstr;
9921 char_u *tostr;
9922 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009923 int inlen;
9924 int fromlen;
9925 int tolen;
9926 int idx;
9927 char_u *cpstr;
9928 int cplen;
9929 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009930 char_u buf[NUMBUFLEN];
9931 char_u buf2[NUMBUFLEN];
9932 garray_T ga;
9933
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009934 in_str = tv_get_string(&argvars[0]);
9935 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
9936 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009937
9938 /* Default return value: empty string. */
9939 rettv->v_type = VAR_STRING;
9940 rettv->vval.v_string = NULL;
9941 if (fromstr == NULL || tostr == NULL)
9942 return; /* type error; errmsg already given */
9943 ga_init2(&ga, (int)sizeof(char), 80);
9944
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009945 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009946 /* not multi-byte: fromstr and tostr must be the same length */
9947 if (STRLEN(fromstr) != STRLEN(tostr))
9948 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009949error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009950 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009951 ga_clear(&ga);
9952 return;
9953 }
9954
9955 /* fromstr and tostr have to contain the same number of chars */
9956 while (*in_str != NUL)
9957 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009958 if (has_mbyte)
9959 {
9960 inlen = (*mb_ptr2len)(in_str);
9961 cpstr = in_str;
9962 cplen = inlen;
9963 idx = 0;
9964 for (p = fromstr; *p != NUL; p += fromlen)
9965 {
9966 fromlen = (*mb_ptr2len)(p);
9967 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
9968 {
9969 for (p = tostr; *p != NUL; p += tolen)
9970 {
9971 tolen = (*mb_ptr2len)(p);
9972 if (idx-- == 0)
9973 {
9974 cplen = tolen;
9975 cpstr = p;
9976 break;
9977 }
9978 }
9979 if (*p == NUL) /* tostr is shorter than fromstr */
9980 goto error;
9981 break;
9982 }
9983 ++idx;
9984 }
9985
9986 if (first && cpstr == in_str)
9987 {
9988 /* Check that fromstr and tostr have the same number of
9989 * (multi-byte) characters. Done only once when a character
9990 * of in_str doesn't appear in fromstr. */
9991 first = FALSE;
9992 for (p = tostr; *p != NUL; p += tolen)
9993 {
9994 tolen = (*mb_ptr2len)(p);
9995 --idx;
9996 }
9997 if (idx != 0)
9998 goto error;
9999 }
10000
10001 (void)ga_grow(&ga, cplen);
10002 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
10003 ga.ga_len += cplen;
10004
10005 in_str += inlen;
10006 }
10007 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010008 {
10009 /* When not using multi-byte chars we can do it faster. */
10010 p = vim_strchr(fromstr, *in_str);
10011 if (p != NULL)
10012 ga_append(&ga, tostr[p - fromstr]);
10013 else
10014 ga_append(&ga, *in_str);
10015 ++in_str;
10016 }
10017 }
10018
10019 /* add a terminating NUL */
10020 (void)ga_grow(&ga, 1);
10021 ga_append(&ga, NUL);
10022
10023 rettv->vval.v_string = ga.ga_data;
10024}
10025
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010026/*
10027 * "trim({expr})" function
10028 */
10029 static void
10030f_trim(typval_T *argvars, typval_T *rettv)
10031{
10032 char_u buf1[NUMBUFLEN];
10033 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010034 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010035 char_u *mask = NULL;
10036 char_u *tail;
10037 char_u *prev;
10038 char_u *p;
10039 int c1;
10040
10041 rettv->v_type = VAR_STRING;
10042 if (head == NULL)
10043 {
10044 rettv->vval.v_string = NULL;
10045 return;
10046 }
10047
10048 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010049 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010010050
10051 while (*head != NUL)
10052 {
10053 c1 = PTR2CHAR(head);
10054 if (mask == NULL)
10055 {
10056 if (c1 > ' ' && c1 != 0xa0)
10057 break;
10058 }
10059 else
10060 {
10061 for (p = mask; *p != NUL; MB_PTR_ADV(p))
10062 if (c1 == PTR2CHAR(p))
10063 break;
10064 if (*p == NUL)
10065 break;
10066 }
10067 MB_PTR_ADV(head);
10068 }
10069
10070 for (tail = head + STRLEN(head); tail > head; tail = prev)
10071 {
10072 prev = tail;
10073 MB_PTR_BACK(head, prev);
10074 c1 = PTR2CHAR(prev);
10075 if (mask == NULL)
10076 {
10077 if (c1 > ' ' && c1 != 0xa0)
10078 break;
10079 }
10080 else
10081 {
10082 for (p = mask; *p != NUL; MB_PTR_ADV(p))
10083 if (c1 == PTR2CHAR(p))
10084 break;
10085 if (*p == NUL)
10086 break;
10087 }
10088 }
10089 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
10090}
10091
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010092#ifdef FEAT_FLOAT
10093/*
10094 * "trunc({float})" function
10095 */
10096 static void
10097f_trunc(typval_T *argvars, typval_T *rettv)
10098{
10099 float_T f = 0.0;
10100
10101 rettv->v_type = VAR_FLOAT;
10102 if (get_float_arg(argvars, &f) == OK)
10103 /* trunc() is not in C90, use floor() or ceil() instead. */
10104 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
10105 else
10106 rettv->vval.v_float = 0.0;
10107}
10108#endif
10109
10110/*
10111 * "type(expr)" function
10112 */
10113 static void
10114f_type(typval_T *argvars, typval_T *rettv)
10115{
10116 int n = -1;
10117
10118 switch (argvars[0].v_type)
10119 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020010120 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
10121 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010122 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020010123 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
10124 case VAR_LIST: n = VAR_TYPE_LIST; break;
10125 case VAR_DICT: n = VAR_TYPE_DICT; break;
10126 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010127 case VAR_SPECIAL:
10128 if (argvars[0].vval.v_number == VVAL_FALSE
10129 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020010130 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010131 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020010132 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010133 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020010134 case VAR_JOB: n = VAR_TYPE_JOB; break;
10135 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010136 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010137 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010010138 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010139 n = -1;
10140 break;
10141 }
10142 rettv->vval.v_number = n;
10143}
10144
10145/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010146 * "virtcol(string)" function
10147 */
10148 static void
10149f_virtcol(typval_T *argvars, typval_T *rettv)
10150{
10151 colnr_T vcol = 0;
10152 pos_T *fp;
10153 int fnum = curbuf->b_fnum;
10154
10155 fp = var2fpos(&argvars[0], FALSE, &fnum);
10156 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
10157 && fnum == curbuf->b_fnum)
10158 {
10159 getvvcol(curwin, fp, NULL, NULL, &vcol);
10160 ++vcol;
10161 }
10162
10163 rettv->vval.v_number = vcol;
10164}
10165
10166/*
10167 * "visualmode()" function
10168 */
10169 static void
10170f_visualmode(typval_T *argvars, typval_T *rettv)
10171{
10172 char_u str[2];
10173
10174 rettv->v_type = VAR_STRING;
10175 str[0] = curbuf->b_visual_mode_eval;
10176 str[1] = NUL;
10177 rettv->vval.v_string = vim_strsave(str);
10178
10179 /* A non-zero number or non-empty string argument: reset mode. */
10180 if (non_zero_arg(&argvars[0]))
10181 curbuf->b_visual_mode_eval = NUL;
10182}
10183
10184/*
10185 * "wildmenumode()" function
10186 */
10187 static void
10188f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
10189{
10190#ifdef FEAT_WILDMENU
10191 if (wild_menu_showing)
10192 rettv->vval.v_number = 1;
10193#endif
10194}
10195
10196/*
10197 * "winbufnr(nr)" function
10198 */
10199 static void
10200f_winbufnr(typval_T *argvars, typval_T *rettv)
10201{
10202 win_T *wp;
10203
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010204 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010205 if (wp == NULL)
10206 rettv->vval.v_number = -1;
10207 else
10208 rettv->vval.v_number = wp->w_buffer->b_fnum;
10209}
10210
10211/*
10212 * "wincol()" function
10213 */
10214 static void
10215f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
10216{
10217 validate_cursor();
10218 rettv->vval.v_number = curwin->w_wcol + 1;
10219}
10220
10221/*
10222 * "winheight(nr)" function
10223 */
10224 static void
10225f_winheight(typval_T *argvars, typval_T *rettv)
10226{
10227 win_T *wp;
10228
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010229 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010230 if (wp == NULL)
10231 rettv->vval.v_number = -1;
10232 else
10233 rettv->vval.v_number = wp->w_height;
10234}
10235
10236/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020010237 * "winlayout()" function
10238 */
10239 static void
10240f_winlayout(typval_T *argvars, typval_T *rettv)
10241{
10242 tabpage_T *tp;
10243
10244 if (rettv_list_alloc(rettv) != OK)
10245 return;
10246
10247 if (argvars[0].v_type == VAR_UNKNOWN)
10248 tp = curtab;
10249 else
10250 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010251 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020010252 if (tp == NULL)
10253 return;
10254 }
10255
10256 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
10257}
10258
10259/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010260 * "winline()" function
10261 */
10262 static void
10263f_winline(typval_T *argvars UNUSED, typval_T *rettv)
10264{
10265 validate_cursor();
10266 rettv->vval.v_number = curwin->w_wrow + 1;
10267}
10268
10269/*
10270 * "winnr()" function
10271 */
10272 static void
10273f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
10274{
10275 int nr = 1;
10276
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010277 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010278 rettv->vval.v_number = nr;
10279}
10280
10281/*
10282 * "winrestcmd()" function
10283 */
10284 static void
10285f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
10286{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010287 win_T *wp;
10288 int winnr = 1;
10289 garray_T ga;
10290 char_u buf[50];
10291
10292 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020010293 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010294 {
10295 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
10296 ga_concat(&ga, buf);
10297 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
10298 ga_concat(&ga, buf);
10299 ++winnr;
10300 }
10301 ga_append(&ga, NUL);
10302
10303 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010304 rettv->v_type = VAR_STRING;
10305}
10306
10307/*
10308 * "winrestview()" function
10309 */
10310 static void
10311f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
10312{
10313 dict_T *dict;
10314
10315 if (argvars[0].v_type != VAR_DICT
10316 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010317 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010318 else
10319 {
10320 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010321 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010322 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010323 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010324 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010325 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010326 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
10327 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010010328 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010329 curwin->w_set_curswant = FALSE;
10330 }
10331
10332 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010333 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010334#ifdef FEAT_DIFF
10335 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010336 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010337#endif
10338 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010339 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010340 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010010341 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010342
10343 check_cursor();
10344 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020010345 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010346 changed_window_setting();
10347
10348 if (curwin->w_topline <= 0)
10349 curwin->w_topline = 1;
10350 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
10351 curwin->w_topline = curbuf->b_ml.ml_line_count;
10352#ifdef FEAT_DIFF
10353 check_topfill(curwin, TRUE);
10354#endif
10355 }
10356}
10357
10358/*
10359 * "winsaveview()" function
10360 */
10361 static void
10362f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
10363{
10364 dict_T *dict;
10365
10366 if (rettv_dict_alloc(rettv) == FAIL)
10367 return;
10368 dict = rettv->vval.v_dict;
10369
Bram Moolenaare0be1672018-07-08 16:50:37 +020010370 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
10371 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020010372 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010373 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020010374 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010375
Bram Moolenaare0be1672018-07-08 16:50:37 +020010376 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010377#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020010378 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010379#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020010380 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
10381 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010382}
10383
10384/*
10385 * "winwidth(nr)" function
10386 */
10387 static void
10388f_winwidth(typval_T *argvars, typval_T *rettv)
10389{
10390 win_T *wp;
10391
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010392 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010393 if (wp == NULL)
10394 rettv->vval.v_number = -1;
10395 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010396 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010397}
10398
10399/*
10400 * "wordcount()" function
10401 */
10402 static void
10403f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
10404{
10405 if (rettv_dict_alloc(rettv) == FAIL)
10406 return;
10407 cursor_pos_info(rettv->vval.v_dict);
10408}
10409
10410/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010411 * "xor(expr, expr)" function
10412 */
10413 static void
10414f_xor(typval_T *argvars, typval_T *rettv)
10415{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010416 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
10417 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010418}
10419
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010420#endif /* FEAT_EVAL */