blob: eac37ed27ecc20748cf4e057bbcc845e7170d415 [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 Moolenaarbf821bc2019-01-23 21:15:02 +010027static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028
29#ifdef FEAT_FLOAT
30static void f_abs(typval_T *argvars, typval_T *rettv);
31static void f_acos(typval_T *argvars, typval_T *rettv);
32#endif
33static void f_add(typval_T *argvars, typval_T *rettv);
34static void f_and(typval_T *argvars, typval_T *rettv);
35static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020036static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020037#ifdef FEAT_FLOAT
38static void f_asin(typval_T *argvars, typval_T *rettv);
39static void f_atan(typval_T *argvars, typval_T *rettv);
40static void f_atan2(typval_T *argvars, typval_T *rettv);
41#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010042#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020043static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010044static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010045# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010046static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010047# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010048#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020049static void f_browse(typval_T *argvars, typval_T *rettv);
50static void f_browsedir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020051static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020052static void f_bufexists(typval_T *argvars, typval_T *rettv);
53static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020054static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_bufloaded(typval_T *argvars, typval_T *rettv);
56static void f_bufname(typval_T *argvars, typval_T *rettv);
57static void f_bufnr(typval_T *argvars, typval_T *rettv);
58static void f_bufwinid(typval_T *argvars, typval_T *rettv);
59static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
60static void f_byte2line(typval_T *argvars, typval_T *rettv);
61static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
62static void f_byteidx(typval_T *argvars, typval_T *rettv);
63static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
64static void f_call(typval_T *argvars, typval_T *rettv);
65#ifdef FEAT_FLOAT
66static void f_ceil(typval_T *argvars, typval_T *rettv);
67#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020068static void f_changenr(typval_T *argvars, typval_T *rettv);
69static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar1063f3d2019-05-07 22:06:52 +020070static void f_chdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020071static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_confirm(typval_T *argvars, typval_T *rettv);
74static void f_copy(typval_T *argvars, typval_T *rettv);
75#ifdef FEAT_FLOAT
76static void f_cos(typval_T *argvars, typval_T *rettv);
77static void f_cosh(typval_T *argvars, typval_T *rettv);
78#endif
79static void f_count(typval_T *argvars, typval_T *rettv);
80static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
81static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010082#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020083static void f_debugbreak(typval_T *argvars, typval_T *rettv);
84#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020085static void f_deepcopy(typval_T *argvars, typval_T *rettv);
86static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020087static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020088static void f_did_filetype(typval_T *argvars, typval_T *rettv);
89static void f_diff_filler(typval_T *argvars, typval_T *rettv);
90static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
91static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020092static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020093static void f_escape(typval_T *argvars, typval_T *rettv);
94static void f_eval(typval_T *argvars, typval_T *rettv);
95static void f_eventhandler(typval_T *argvars, typval_T *rettv);
96static void f_executable(typval_T *argvars, typval_T *rettv);
97static void f_execute(typval_T *argvars, typval_T *rettv);
98static void f_exepath(typval_T *argvars, typval_T *rettv);
99static void f_exists(typval_T *argvars, typval_T *rettv);
100#ifdef FEAT_FLOAT
101static void f_exp(typval_T *argvars, typval_T *rettv);
102#endif
103static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +0200104static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200105static void f_extend(typval_T *argvars, typval_T *rettv);
106static void f_feedkeys(typval_T *argvars, typval_T *rettv);
107static void f_filereadable(typval_T *argvars, typval_T *rettv);
108static void f_filewritable(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200109static void f_finddir(typval_T *argvars, typval_T *rettv);
110static void f_findfile(typval_T *argvars, typval_T *rettv);
111#ifdef FEAT_FLOAT
112static void f_float2nr(typval_T *argvars, typval_T *rettv);
113static void f_floor(typval_T *argvars, typval_T *rettv);
114static void f_fmod(typval_T *argvars, typval_T *rettv);
115#endif
116static void f_fnameescape(typval_T *argvars, typval_T *rettv);
117static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200119static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200120static void f_function(typval_T *argvars, typval_T *rettv);
121static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
122static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200123static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200124static void f_getbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100125static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200126static void f_getchar(typval_T *argvars, typval_T *rettv);
127static void f_getcharmod(typval_T *argvars, typval_T *rettv);
128static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
129static void f_getcmdline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200130static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
131static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
132static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
133static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200134static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200135static void f_getfontname(typval_T *argvars, typval_T *rettv);
136static void f_getfperm(typval_T *argvars, typval_T *rettv);
137static void f_getfsize(typval_T *argvars, typval_T *rettv);
138static void f_getftime(typval_T *argvars, typval_T *rettv);
139static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100140static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200141static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200142static void f_getpid(typval_T *argvars, typval_T *rettv);
143static void f_getcurpos(typval_T *argvars, typval_T *rettv);
144static void f_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200145static void f_getreg(typval_T *argvars, typval_T *rettv);
146static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200147static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100148static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200149static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100150static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200151static void f_getwinposx(typval_T *argvars, typval_T *rettv);
152static void f_getwinposy(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200153static void f_glob(typval_T *argvars, typval_T *rettv);
154static void f_globpath(typval_T *argvars, typval_T *rettv);
155static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
156static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200157static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
158static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200159static void f_hlID(typval_T *argvars, typval_T *rettv);
160static void f_hlexists(typval_T *argvars, typval_T *rettv);
161static void f_hostname(typval_T *argvars, typval_T *rettv);
162static void f_iconv(typval_T *argvars, typval_T *rettv);
163static void f_indent(typval_T *argvars, typval_T *rettv);
164static void f_index(typval_T *argvars, typval_T *rettv);
165static void f_input(typval_T *argvars, typval_T *rettv);
166static void f_inputdialog(typval_T *argvars, typval_T *rettv);
167static void f_inputlist(typval_T *argvars, typval_T *rettv);
168static void f_inputrestore(typval_T *argvars, typval_T *rettv);
169static void f_inputsave(typval_T *argvars, typval_T *rettv);
170static void f_inputsecret(typval_T *argvars, typval_T *rettv);
171static void f_insert(typval_T *argvars, typval_T *rettv);
172static void f_invert(typval_T *argvars, typval_T *rettv);
173static void f_isdirectory(typval_T *argvars, typval_T *rettv);
174static void f_islocked(typval_T *argvars, typval_T *rettv);
175#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200176static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_isnan(typval_T *argvars, typval_T *rettv);
178#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200179static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
180static void f_len(typval_T *argvars, typval_T *rettv);
181static void f_libcall(typval_T *argvars, typval_T *rettv);
182static void f_libcallnr(typval_T *argvars, typval_T *rettv);
183static void f_line(typval_T *argvars, typval_T *rettv);
184static void f_line2byte(typval_T *argvars, typval_T *rettv);
185static void f_lispindent(typval_T *argvars, typval_T *rettv);
186static void f_localtime(typval_T *argvars, typval_T *rettv);
187#ifdef FEAT_FLOAT
188static void f_log(typval_T *argvars, typval_T *rettv);
189static void f_log10(typval_T *argvars, typval_T *rettv);
190#endif
191#ifdef FEAT_LUA
192static void f_luaeval(typval_T *argvars, typval_T *rettv);
193#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_maparg(typval_T *argvars, typval_T *rettv);
195static void f_mapcheck(typval_T *argvars, typval_T *rettv);
196static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200197static void f_matchend(typval_T *argvars, typval_T *rettv);
198static void f_matchlist(typval_T *argvars, typval_T *rettv);
199static void f_matchstr(typval_T *argvars, typval_T *rettv);
200static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
201static void f_max(typval_T *argvars, typval_T *rettv);
202static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200203static void f_mkdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204static void f_mode(typval_T *argvars, typval_T *rettv);
205#ifdef FEAT_MZSCHEME
206static void f_mzeval(typval_T *argvars, typval_T *rettv);
207#endif
208static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
209static void f_nr2char(typval_T *argvars, typval_T *rettv);
210static void f_or(typval_T *argvars, typval_T *rettv);
211static void f_pathshorten(typval_T *argvars, typval_T *rettv);
212#ifdef FEAT_PERL
213static void f_perleval(typval_T *argvars, typval_T *rettv);
214#endif
215#ifdef FEAT_FLOAT
216static void f_pow(typval_T *argvars, typval_T *rettv);
217#endif
218static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
219static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200220static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200221static void f_pumvisible(typval_T *argvars, typval_T *rettv);
222#ifdef FEAT_PYTHON3
223static void f_py3eval(typval_T *argvars, typval_T *rettv);
224#endif
225#ifdef FEAT_PYTHON
226static void f_pyeval(typval_T *argvars, typval_T *rettv);
227#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100228#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
229static void f_pyxeval(typval_T *argvars, typval_T *rettv);
230#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200231static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200232static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200233static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200234static void f_reg_executing(typval_T *argvars, typval_T *rettv);
235static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200236static void f_reltime(typval_T *argvars, typval_T *rettv);
237#ifdef FEAT_FLOAT
238static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
239#endif
240static void f_reltimestr(typval_T *argvars, typval_T *rettv);
241static void f_remote_expr(typval_T *argvars, typval_T *rettv);
242static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
243static void f_remote_peek(typval_T *argvars, typval_T *rettv);
244static void f_remote_read(typval_T *argvars, typval_T *rettv);
245static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100246static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200247static void f_remove(typval_T *argvars, typval_T *rettv);
248static void f_rename(typval_T *argvars, typval_T *rettv);
249static void f_repeat(typval_T *argvars, typval_T *rettv);
250static void f_resolve(typval_T *argvars, typval_T *rettv);
251static void f_reverse(typval_T *argvars, typval_T *rettv);
252#ifdef FEAT_FLOAT
253static void f_round(typval_T *argvars, typval_T *rettv);
254#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100255#ifdef FEAT_RUBY
256static void f_rubyeval(typval_T *argvars, typval_T *rettv);
257#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200258static void f_screenattr(typval_T *argvars, typval_T *rettv);
259static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100260static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_screencol(typval_T *argvars, typval_T *rettv);
262static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100263static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200264static void f_search(typval_T *argvars, typval_T *rettv);
265static void f_searchdecl(typval_T *argvars, typval_T *rettv);
266static void f_searchpair(typval_T *argvars, typval_T *rettv);
267static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
268static void f_searchpos(typval_T *argvars, typval_T *rettv);
269static void f_server2client(typval_T *argvars, typval_T *rettv);
270static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200271static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200272static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
273static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200274static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200275static void f_setfperm(typval_T *argvars, typval_T *rettv);
276static void f_setline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200277static void f_setpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200278static void f_setreg(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100279static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200280#ifdef FEAT_CRYPT
281static void f_sha256(typval_T *argvars, typval_T *rettv);
282#endif /* FEAT_CRYPT */
283static void f_shellescape(typval_T *argvars, typval_T *rettv);
284static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
285static void f_simplify(typval_T *argvars, typval_T *rettv);
286#ifdef FEAT_FLOAT
287static void f_sin(typval_T *argvars, typval_T *rettv);
288static void f_sinh(typval_T *argvars, typval_T *rettv);
289#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200290static void f_soundfold(typval_T *argvars, typval_T *rettv);
291static void f_spellbadword(typval_T *argvars, typval_T *rettv);
292static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
293static void f_split(typval_T *argvars, typval_T *rettv);
294#ifdef FEAT_FLOAT
295static void f_sqrt(typval_T *argvars, typval_T *rettv);
296static void f_str2float(typval_T *argvars, typval_T *rettv);
297#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200298static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200299static void f_str2nr(typval_T *argvars, typval_T *rettv);
300static void f_strchars(typval_T *argvars, typval_T *rettv);
301#ifdef HAVE_STRFTIME
302static void f_strftime(typval_T *argvars, typval_T *rettv);
303#endif
304static void f_strgetchar(typval_T *argvars, typval_T *rettv);
305static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200306static void f_strlen(typval_T *argvars, typval_T *rettv);
307static void f_strcharpart(typval_T *argvars, typval_T *rettv);
308static void f_strpart(typval_T *argvars, typval_T *rettv);
309static void f_strridx(typval_T *argvars, typval_T *rettv);
310static void f_strtrans(typval_T *argvars, typval_T *rettv);
311static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
312static void f_strwidth(typval_T *argvars, typval_T *rettv);
313static void f_submatch(typval_T *argvars, typval_T *rettv);
314static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200315static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200316static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200317static void f_synID(typval_T *argvars, typval_T *rettv);
318static void f_synIDattr(typval_T *argvars, typval_T *rettv);
319static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
320static void f_synstack(typval_T *argvars, typval_T *rettv);
321static void f_synconcealed(typval_T *argvars, typval_T *rettv);
322static void f_system(typval_T *argvars, typval_T *rettv);
323static void f_systemlist(typval_T *argvars, typval_T *rettv);
324static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
325static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
326static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
327static void f_taglist(typval_T *argvars, typval_T *rettv);
328static void f_tagfiles(typval_T *argvars, typval_T *rettv);
329static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200330#ifdef FEAT_FLOAT
331static void f_tan(typval_T *argvars, typval_T *rettv);
332static void f_tanh(typval_T *argvars, typval_T *rettv);
333#endif
334#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200335static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200336static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200337static void f_timer_start(typval_T *argvars, typval_T *rettv);
338static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200339static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200340#endif
341static void f_tolower(typval_T *argvars, typval_T *rettv);
342static void f_toupper(typval_T *argvars, typval_T *rettv);
343static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100344static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200345#ifdef FEAT_FLOAT
346static void f_trunc(typval_T *argvars, typval_T *rettv);
347#endif
348static void f_type(typval_T *argvars, typval_T *rettv);
349static void f_undofile(typval_T *argvars, typval_T *rettv);
350static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200351static void f_virtcol(typval_T *argvars, typval_T *rettv);
352static void f_visualmode(typval_T *argvars, typval_T *rettv);
353static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200354static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200355static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
356static void f_win_getid(typval_T *argvars, typval_T *rettv);
357static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
358static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
359static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100360static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200361static void f_winbufnr(typval_T *argvars, typval_T *rettv);
362static void f_wincol(typval_T *argvars, typval_T *rettv);
363static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200364static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200365static void f_winline(typval_T *argvars, typval_T *rettv);
366static void f_winnr(typval_T *argvars, typval_T *rettv);
367static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
368static void f_winrestview(typval_T *argvars, typval_T *rettv);
369static void f_winsaveview(typval_T *argvars, typval_T *rettv);
370static void f_winwidth(typval_T *argvars, typval_T *rettv);
371static void f_writefile(typval_T *argvars, typval_T *rettv);
372static void f_wordcount(typval_T *argvars, typval_T *rettv);
373static void f_xor(typval_T *argvars, typval_T *rettv);
374
375/*
376 * Array with names and number of arguments of all internal functions
377 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
378 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200379typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200380{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200381 char *f_name; // function name
382 char f_min_argc; // minimal number of arguments
383 char f_max_argc; // maximal number of arguments
384 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200385 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200386 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200387} funcentry_T;
388
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200389// values for f_argtype; zero means it cannot be used as a method
390#define FEARG_1 1 // base is the first argument
391#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200392#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200393#define FEARG_LAST 9 // base is the last argument
394
Bram Moolenaarac92e252019-08-03 21:58:38 +0200395static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200396{
397#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200398 {"abs", 1, 1, FEARG_1, f_abs},
399 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200400#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200401 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200402 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200403 {"append", 2, 2, FEARG_LAST, f_append},
404 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
405 {"argc", 0, 1, 0, f_argc},
406 {"argidx", 0, 0, 0, f_argidx},
407 {"arglistid", 0, 2, 0, f_arglistid},
408 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200410 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200411#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200412 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200413 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200414 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200415 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200416 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
417 {"assert_false", 1, 2, FEARG_1, f_assert_false},
418 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
419 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200420 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200421 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200422 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200423 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200424#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200425 {"atan", 1, 1, FEARG_1, f_atan},
426 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200427#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100428#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200429 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200430 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100431# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200432 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100433# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100434#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200435 {"browse", 4, 4, 0, f_browse},
436 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200437 {"bufadd", 1, 1, FEARG_1, f_bufadd},
438 {"bufexists", 1, 1, FEARG_1, f_bufexists},
439 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaara8eee212019-08-24 22:14:58 +0200440 {"buffer_name", 0, 1, FEARG_1, f_bufname}, // obsolete
441 {"buffer_number", 0, 1, FEARG_1, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200442 {"buflisted", 1, 1, FEARG_1, f_buflisted},
443 {"bufload", 1, 1, FEARG_1, f_bufload},
444 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
Bram Moolenaara8eee212019-08-24 22:14:58 +0200445 {"bufname", 0, 1, FEARG_1, f_bufname},
446 {"bufnr", 0, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200447 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
448 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200449 {"byte2line", 1, 1, FEARG_1, f_byte2line},
450 {"byteidx", 2, 2, FEARG_1, f_byteidx},
451 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
452 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200453#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200454 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200455#endif
456#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200457 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
458 {"ch_close", 1, 1, FEARG_1, f_ch_close},
459 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
460 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
461 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
462 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
463 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
464 {"ch_info", 1, 1, FEARG_1, f_ch_info},
465 {"ch_log", 1, 2, FEARG_1, f_ch_log},
466 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
467 {"ch_open", 1, 2, FEARG_1, f_ch_open},
468 {"ch_read", 1, 2, FEARG_1, f_ch_read},
469 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
470 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
471 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
472 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
473 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
474 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200475#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200476 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200477 {"char2nr", 1, 2, FEARG_1, f_char2nr},
478 {"chdir", 1, 1, FEARG_1, f_chdir},
479 {"cindent", 1, 1, FEARG_1, f_cindent},
480 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
481 {"col", 1, 1, FEARG_1, f_col},
482 {"complete", 2, 2, FEARG_2, f_complete},
483 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200484 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200485 {"complete_info", 0, 1, FEARG_1, f_complete_info},
486 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200487 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200488#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200489 {"cos", 1, 1, FEARG_1, f_cos},
490 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200491#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200492 {"count", 2, 4, FEARG_1, f_count},
493 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200494 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100495#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200496 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200497#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200498 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
499 {"delete", 1, 2, FEARG_1, f_delete},
500 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200501 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200502 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
503 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"empty", 1, 1, FEARG_1, f_empty},
505 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200506 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200507 {"eval", 1, 1, FEARG_1, f_eval},
508 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200509 {"executable", 1, 1, FEARG_1, f_executable},
510 {"execute", 1, 2, FEARG_1, f_execute},
511 {"exepath", 1, 1, FEARG_1, f_exepath},
512 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200513#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200514 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200515#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200516 {"expand", 1, 3, FEARG_1, f_expand},
517 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200518 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200519 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
520 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
521 {"filereadable", 1, 1, FEARG_1, f_filereadable},
522 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200523 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200524 {"finddir", 1, 3, FEARG_1, f_finddir},
525 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200526#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200527 {"float2nr", 1, 1, FEARG_1, f_float2nr},
528 {"floor", 1, 1, FEARG_1, f_floor},
529 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200530#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200531 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
532 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
533 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
534 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
535 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200536 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200537 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200538 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200539 {"funcref", 1, 3, FEARG_1, f_funcref},
540 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200541 {"garbagecollect", 0, 1, 0, f_garbagecollect},
542 {"get", 2, 3, FEARG_1, f_get},
543 {"getbufinfo", 0, 1, 0, f_getbufinfo},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200544 {"getbufline", 2, 3, FEARG_1, f_getbufline},
545 {"getbufvar", 2, 3, FEARG_1, f_getbufvar},
546 {"getchangelist", 0, 1, FEARG_1, f_getchangelist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200547 {"getchar", 0, 1, 0, f_getchar},
548 {"getcharmod", 0, 0, 0, f_getcharmod},
549 {"getcharsearch", 0, 0, 0, f_getcharsearch},
550 {"getcmdline", 0, 0, 0, f_getcmdline},
551 {"getcmdpos", 0, 0, 0, f_getcmdpos},
552 {"getcmdtype", 0, 0, 0, f_getcmdtype},
553 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200554 {"getcompletion", 2, 3, FEARG_1, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200555 {"getcurpos", 0, 0, 0, f_getcurpos},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200556 {"getcwd", 0, 2, FEARG_1, f_getcwd},
557 {"getenv", 1, 1, FEARG_1, f_getenv},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200558 {"getfontname", 0, 1, 0, f_getfontname},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200559 {"getfperm", 1, 1, FEARG_1, f_getfperm},
560 {"getfsize", 1, 1, FEARG_1, f_getfsize},
561 {"getftime", 1, 1, FEARG_1, f_getftime},
562 {"getftype", 1, 1, FEARG_1, f_getftype},
563 {"getjumplist", 0, 2, FEARG_1, f_getjumplist},
564 {"getline", 1, 2, FEARG_1, f_getline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200565 {"getloclist", 1, 2, 0, f_getloclist},
566 {"getmatches", 0, 1, 0, f_getmatches},
567 {"getpid", 0, 0, 0, f_getpid},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200568 {"getpos", 1, 1, FEARG_1, f_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200569 {"getqflist", 0, 1, 0, f_getqflist},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200570 {"getreg", 0, 3, FEARG_1, f_getreg},
571 {"getregtype", 0, 1, FEARG_1, f_getregtype},
572 {"gettabinfo", 0, 1, FEARG_1, f_gettabinfo},
573 {"gettabvar", 2, 3, FEARG_1, f_gettabvar},
574 {"gettabwinvar", 3, 4, FEARG_1, f_gettabwinvar},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200575 {"gettagstack", 0, 1, FEARG_1, f_gettagstack},
576 {"getwininfo", 0, 1, FEARG_1, f_getwininfo},
577 {"getwinpos", 0, 1, FEARG_1, f_getwinpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200578 {"getwinposx", 0, 0, 0, f_getwinposx},
579 {"getwinposy", 0, 0, 0, f_getwinposy},
Bram Moolenaar5d69fdb2019-08-31 19:13:58 +0200580 {"getwinvar", 2, 3, FEARG_1, f_getwinvar},
581 {"glob", 1, 4, FEARG_1, f_glob},
582 {"glob2regpat", 1, 1, FEARG_1, f_glob2regpat},
583 {"globpath", 2, 5, FEARG_2, f_globpath},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200584 {"has", 1, 1, 0, f_has},
585 {"has_key", 2, 2, FEARG_1, f_has_key},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200586 {"haslocaldir", 0, 2, FEARG_1, f_haslocaldir},
587 {"hasmapto", 1, 3, FEARG_1, f_hasmapto},
588 {"highlightID", 1, 1, FEARG_1, f_hlID}, // obsolete
589 {"highlight_exists",1, 1, FEARG_1, f_hlexists}, // obsolete
590 {"histadd", 2, 2, FEARG_2, f_histadd},
591 {"histdel", 1, 2, FEARG_1, f_histdel},
592 {"histget", 1, 2, FEARG_1, f_histget},
593 {"histnr", 1, 1, FEARG_1, f_histnr},
594 {"hlID", 1, 1, FEARG_1, f_hlID},
595 {"hlexists", 1, 1, FEARG_1, f_hlexists},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200596 {"hostname", 0, 0, 0, f_hostname},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200597 {"iconv", 3, 3, FEARG_1, f_iconv},
598 {"indent", 1, 1, FEARG_1, f_indent},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200599 {"index", 2, 4, FEARG_1, f_index},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200600 {"input", 1, 3, FEARG_1, f_input},
601 {"inputdialog", 1, 3, FEARG_1, f_inputdialog},
602 {"inputlist", 1, 1, FEARG_1, f_inputlist},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200603 {"inputrestore", 0, 0, 0, f_inputrestore},
604 {"inputsave", 0, 0, 0, f_inputsave},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200605 {"inputsecret", 1, 2, FEARG_1, f_inputsecret},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200606 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200607 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200608 {"isdirectory", 1, 1, FEARG_1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200609#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200610 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200611#endif
Bram Moolenaarf9f24ce2019-08-31 21:17:39 +0200612 {"islocked", 1, 1, FEARG_1, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200613#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200614 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200615#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200616 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200617#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200618 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
619 {"job_info", 0, 1, FEARG_1, f_job_info},
620 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
621 {"job_start", 1, 2, FEARG_1, f_job_start},
622 {"job_status", 1, 1, FEARG_1, f_job_status},
623 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200624#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200625 {"join", 1, 2, FEARG_1, f_join},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200626 {"js_decode", 1, 1, FEARG_1, f_js_decode},
627 {"js_encode", 1, 1, FEARG_1, f_js_encode},
628 {"json_decode", 1, 1, FEARG_1, f_json_decode},
629 {"json_encode", 1, 1, FEARG_1, f_json_encode},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200630 {"keys", 1, 1, FEARG_1, f_keys},
631 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
632 {"len", 1, 1, FEARG_1, f_len},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200633 {"libcall", 3, 3, FEARG_3, f_libcall},
634 {"libcallnr", 3, 3, FEARG_3, f_libcallnr},
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +0200635 {"line", 1, 2, FEARG_1, f_line},
Bram Moolenaar02b31112019-08-31 22:16:38 +0200636 {"line2byte", 1, 1, FEARG_1, f_line2byte},
637 {"lispindent", 1, 1, FEARG_1, f_lispindent},
638 {"list2str", 1, 2, FEARG_1, f_list2str},
639 {"listener_add", 1, 2, FEARG_2, f_listener_add},
640 {"listener_flush", 0, 1, FEARG_1, f_listener_flush},
641 {"listener_remove", 1, 1, FEARG_1, f_listener_remove},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200642 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200643#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200644 {"log", 1, 1, FEARG_1, f_log},
645 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200646#endif
647#ifdef FEAT_LUA
Bram Moolenaar02b31112019-08-31 22:16:38 +0200648 {"luaeval", 1, 2, FEARG_1, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200649#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200650 {"map", 2, 2, FEARG_1, f_map},
Bram Moolenaara1449832019-09-01 20:16:52 +0200651 {"maparg", 1, 4, FEARG_1, f_maparg},
652 {"mapcheck", 1, 3, FEARG_1, f_mapcheck},
653 {"match", 2, 4, FEARG_1, f_match},
654 {"matchadd", 2, 5, FEARG_1, f_matchadd},
655 {"matchaddpos", 2, 5, FEARG_1, f_matchaddpos},
656 {"matcharg", 1, 1, FEARG_1, f_matcharg},
657 {"matchdelete", 1, 2, FEARG_1, f_matchdelete},
658 {"matchend", 2, 4, FEARG_1, f_matchend},
659 {"matchlist", 2, 4, FEARG_1, f_matchlist},
660 {"matchstr", 2, 4, FEARG_1, f_matchstr},
661 {"matchstrpos", 2, 4, FEARG_1, f_matchstrpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200662 {"max", 1, 1, FEARG_1, f_max},
663 {"min", 1, 1, FEARG_1, f_min},
Bram Moolenaara1449832019-09-01 20:16:52 +0200664 {"mkdir", 1, 3, FEARG_1, f_mkdir},
665 {"mode", 0, 1, FEARG_1, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666#ifdef FEAT_MZSCHEME
Bram Moolenaara1449832019-09-01 20:16:52 +0200667 {"mzeval", 1, 1, FEARG_1, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200668#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200669 {"nextnonblank", 1, 1, 0, f_nextnonblank},
670 {"nr2char", 1, 2, 0, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200671 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200672 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200673#ifdef FEAT_PERL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200674 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200675#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200676#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200677 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
678 {"popup_beval", 2, 2, 0, f_popup_beval},
679 {"popup_clear", 0, 0, 0, f_popup_clear},
680 {"popup_close", 1, 2, 0, f_popup_close},
681 {"popup_create", 2, 2, 0, f_popup_create},
682 {"popup_dialog", 2, 2, 0, f_popup_dialog},
683 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
684 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200685 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
686 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200687 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
688 {"popup_getpos", 1, 1, 0, f_popup_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200689 {"popup_hide", 1, 1, 0, f_popup_hide},
690 {"popup_locate", 2, 2, 0, f_popup_locate},
691 {"popup_menu", 2, 2, 0, f_popup_menu},
692 {"popup_move", 2, 2, 0, f_popup_move},
693 {"popup_notification", 2, 2, 0, f_popup_notification},
694 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
695 {"popup_settext", 2, 2, 0, f_popup_settext},
696 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200697#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200698#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200699 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200700#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200701 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200702 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200703#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200704 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
705 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
706 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200707#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100708#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200709 {"prop_add", 3, 3, 0, f_prop_add},
710 {"prop_clear", 1, 3, 0, f_prop_clear},
711 {"prop_list", 1, 2, 0, f_prop_list},
712 {"prop_remove", 1, 3, 0, f_prop_remove},
713 {"prop_type_add", 2, 2, 0, f_prop_type_add},
714 {"prop_type_change", 2, 2, 0, f_prop_type_change},
715 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
716 {"prop_type_get", 1, 2, 0, f_prop_type_get},
717 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100718#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200719 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200720 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200721#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200722 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200723#endif
724#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200725 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200726#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100727#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200728 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100729#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200730 {"range", 1, 3, 0, f_range},
731 {"readdir", 1, 2, 0, f_readdir},
732 {"readfile", 1, 3, 0, f_readfile},
733 {"reg_executing", 0, 0, 0, f_reg_executing},
734 {"reg_recording", 0, 0, 0, f_reg_recording},
735 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200736#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200737 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200738#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200739 {"reltimestr", 1, 1, 0, f_reltimestr},
740 {"remote_expr", 2, 4, 0, f_remote_expr},
741 {"remote_foreground", 1, 1, 0, f_remote_foreground},
742 {"remote_peek", 1, 2, 0, f_remote_peek},
743 {"remote_read", 1, 2, 0, f_remote_read},
744 {"remote_send", 2, 3, 0, f_remote_send},
745 {"remote_startserver", 1, 1, 0, f_remote_startserver},
746 {"remove", 2, 3, FEARG_1, f_remove},
747 {"rename", 2, 2, 0, f_rename},
748 {"repeat", 2, 2, FEARG_1, f_repeat},
749 {"resolve", 1, 1, 0, f_resolve},
750 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200751#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200752 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200753#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100754#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200755 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100756#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200757 {"screenattr", 2, 2, 0, f_screenattr},
758 {"screenchar", 2, 2, 0, f_screenchar},
759 {"screenchars", 2, 2, 0, f_screenchars},
760 {"screencol", 0, 0, 0, f_screencol},
761 {"screenpos", 3, 3, 0, f_screenpos},
762 {"screenrow", 0, 0, 0, f_screenrow},
763 {"screenstring", 2, 2, 0, f_screenstring},
764 {"search", 1, 4, 0, f_search},
765 {"searchdecl", 1, 3, 0, f_searchdecl},
766 {"searchpair", 3, 7, 0, f_searchpair},
767 {"searchpairpos", 3, 7, 0, f_searchpairpos},
768 {"searchpos", 1, 4, 0, f_searchpos},
769 {"server2client", 2, 2, 0, f_server2client},
770 {"serverlist", 0, 0, 0, f_serverlist},
771 {"setbufline", 3, 3, 0, f_setbufline},
772 {"setbufvar", 3, 3, 0, f_setbufvar},
773 {"setcharsearch", 1, 1, 0, f_setcharsearch},
774 {"setcmdpos", 1, 1, 0, f_setcmdpos},
775 {"setenv", 2, 2, 0, f_setenv},
Bram Moolenaar4c313b12019-08-24 22:58:31 +0200776 {"setfperm", 2, 2, FEARG_1, f_setfperm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200777 {"setline", 2, 2, 0, f_setline},
778 {"setloclist", 2, 4, 0, f_setloclist},
779 {"setmatches", 1, 2, 0, f_setmatches},
780 {"setpos", 2, 2, 0, f_setpos},
781 {"setqflist", 1, 3, 0, f_setqflist},
782 {"setreg", 2, 3, 0, f_setreg},
783 {"settabvar", 3, 3, 0, f_settabvar},
784 {"settabwinvar", 4, 4, 0, f_settabwinvar},
785 {"settagstack", 2, 3, 0, f_settagstack},
786 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200787#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200788 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200789#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200790 {"shellescape", 1, 2, 0, f_shellescape},
791 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100792#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200793 {"sign_define", 1, 2, 0, f_sign_define},
794 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
795 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
796 {"sign_jump", 3, 3, 0, f_sign_jump},
797 {"sign_place", 4, 5, 0, f_sign_place},
798 {"sign_placelist", 1, 1, 0, f_sign_placelist},
799 {"sign_undefine", 0, 1, 0, f_sign_undefine},
800 {"sign_unplace", 1, 2, 0, f_sign_unplace},
801 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100802#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200803 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200804#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200805 {"sin", 1, 1, FEARG_1, f_sin},
806 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200808 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200809#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200810 {"sound_clear", 0, 0, 0, f_sound_clear},
811 {"sound_playevent", 1, 2, 0, f_sound_playevent},
812 {"sound_playfile", 1, 2, 0, f_sound_playfile},
813 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200814#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200815 {"soundfold", 1, 1, 0, f_soundfold},
816 {"spellbadword", 0, 1, 0, f_spellbadword},
817 {"spellsuggest", 1, 3, 0, f_spellsuggest},
818 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200819#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200820 {"sqrt", 1, 1, FEARG_1, f_sqrt},
821 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200822#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200823 {"str2list", 1, 2, FEARG_1, f_str2list},
824 {"str2nr", 1, 2, 0, f_str2nr},
825 {"strcharpart", 2, 3, 0, f_strcharpart},
826 {"strchars", 1, 2, 0, f_strchars},
827 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200828#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200829 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200830#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200831 {"strgetchar", 2, 2, 0, f_strgetchar},
832 {"stridx", 2, 3, 0, f_stridx},
833 {"string", 1, 1, FEARG_1, f_string},
834 {"strlen", 1, 1, FEARG_1, f_strlen},
835 {"strpart", 2, 3, 0, f_strpart},
836 {"strridx", 2, 3, 0, f_strridx},
837 {"strtrans", 1, 1, FEARG_1, f_strtrans},
838 {"strwidth", 1, 1, FEARG_1, f_strwidth},
839 {"submatch", 1, 2, 0, f_submatch},
840 {"substitute", 4, 4, FEARG_1, f_substitute},
841 {"swapinfo", 1, 1, 0, f_swapinfo},
842 {"swapname", 1, 1, 0, f_swapname},
843 {"synID", 3, 3, 0, f_synID},
844 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
845 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
846 {"synconcealed", 2, 2, 0, f_synconcealed},
847 {"synstack", 2, 2, 0, f_synstack},
848 {"system", 1, 2, FEARG_1, f_system},
849 {"systemlist", 1, 2, FEARG_1, f_systemlist},
850 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
851 {"tabpagenr", 0, 1, 0, f_tabpagenr},
852 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
853 {"tagfiles", 0, 0, 0, f_tagfiles},
854 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200855#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200856 {"tan", 1, 1, FEARG_1, f_tan},
857 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200858#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200859 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200860#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200861 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
862 {"term_dumpload", 1, 2, 0, f_term_dumpload},
863 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
864 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200865# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200866 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200867# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200868 {"term_getattr", 2, 2, 0, f_term_getattr},
869 {"term_getcursor", 1, 1, 0, f_term_getcursor},
870 {"term_getjob", 1, 1, 0, f_term_getjob},
871 {"term_getline", 2, 2, 0, f_term_getline},
872 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
873 {"term_getsize", 1, 1, 0, f_term_getsize},
874 {"term_getstatus", 1, 1, 0, f_term_getstatus},
875 {"term_gettitle", 1, 1, 0, f_term_gettitle},
876 {"term_gettty", 1, 2, 0, f_term_gettty},
877 {"term_list", 0, 0, 0, f_term_list},
878 {"term_scrape", 2, 2, 0, f_term_scrape},
879 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200880# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200881 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200882# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200883 {"term_setkill", 2, 2, 0, f_term_setkill},
884 {"term_setrestore", 2, 2, 0, f_term_setrestore},
885 {"term_setsize", 3, 3, 0, f_term_setsize},
886 {"term_start", 1, 2, 0, f_term_start},
887 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200888#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200889 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
890 {"test_autochdir", 0, 0, 0, f_test_autochdir},
891 {"test_feedinput", 1, 1, 0, f_test_feedinput},
892 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
893 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
894 {"test_getvalue", 1, 1, 0, f_test_getvalue},
895 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
896 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200897#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200898 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200899#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200900 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200901#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200902 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200903#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200904 {"test_null_list", 0, 0, 0, f_test_null_list},
905 {"test_null_partial", 0, 0, 0, f_test_null_partial},
906 {"test_null_string", 0, 0, 0, f_test_null_string},
907 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
908 {"test_override", 2, 2, 0, f_test_override},
909 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200910#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200911 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200912#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200913#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200914 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200915#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200916 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200918 {"timer_info", 0, 1, 0, f_timer_info},
919 {"timer_pause", 2, 2, 0, f_timer_pause},
920 {"timer_start", 2, 3, 0, f_timer_start},
921 {"timer_stop", 1, 1, 0, f_timer_stop},
922 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200924 {"tolower", 1, 1, 0, f_tolower},
925 {"toupper", 1, 1, 0, f_toupper},
926 {"tr", 3, 3, 0, f_tr},
927 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200928#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200929 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200930#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200931 {"type", 1, 1, FEARG_1, f_type},
932 {"undofile", 1, 1, 0, f_undofile},
933 {"undotree", 0, 0, 0, f_undotree},
934 {"uniq", 1, 3, FEARG_1, f_uniq},
935 {"values", 1, 1, FEARG_1, f_values},
936 {"virtcol", 1, 1, 0, f_virtcol},
937 {"visualmode", 0, 1, 0, f_visualmode},
938 {"wildmenumode", 0, 0, 0, f_wildmenumode},
939 {"win_execute", 2, 3, 0, f_win_execute},
940 {"win_findbuf", 1, 1, 0, f_win_findbuf},
941 {"win_getid", 0, 2, 0, f_win_getid},
942 {"win_gotoid", 1, 1, 0, f_win_gotoid},
943 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
944 {"win_id2win", 1, 1, 0, f_win_id2win},
945 {"win_screenpos", 1, 1, 0, f_win_screenpos},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200946 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200947 {"wincol", 0, 0, 0, f_wincol},
948 {"winheight", 1, 1, 0, f_winheight},
949 {"winlayout", 0, 1, 0, f_winlayout},
950 {"winline", 0, 0, 0, f_winline},
951 {"winnr", 0, 1, 0, f_winnr},
952 {"winrestcmd", 0, 0, 0, f_winrestcmd},
953 {"winrestview", 1, 1, 0, f_winrestview},
954 {"winsaveview", 0, 0, 0, f_winsaveview},
955 {"winwidth", 1, 1, 0, f_winwidth},
956 {"wordcount", 0, 0, 0, f_wordcount},
957 {"writefile", 2, 3, 0, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200958 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200959};
960
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200961/*
962 * Function given to ExpandGeneric() to obtain the list of internal
963 * or user defined function names.
964 */
965 char_u *
966get_function_name(expand_T *xp, int idx)
967{
968 static int intidx = -1;
969 char_u *name;
970
971 if (idx == 0)
972 intidx = -1;
973 if (intidx < 0)
974 {
975 name = get_user_func_name(xp, idx);
976 if (name != NULL)
977 return name;
978 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200979 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200980 {
Bram Moolenaarac92e252019-08-03 21:58:38 +0200981 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200982 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +0200983 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200984 STRCAT(IObuff, ")");
985 return IObuff;
986 }
987
988 return NULL;
989}
990
991/*
992 * Function given to ExpandGeneric() to obtain the list of internal or
993 * user defined variable or function names.
994 */
995 char_u *
996get_expr_name(expand_T *xp, int idx)
997{
998 static int intidx = -1;
999 char_u *name;
1000
1001 if (idx == 0)
1002 intidx = -1;
1003 if (intidx < 0)
1004 {
1005 name = get_function_name(xp, idx);
1006 if (name != NULL)
1007 return name;
1008 }
1009 return get_user_var_name(xp, ++intidx);
1010}
1011
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001012/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001013 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001014 * Return index, or -1 if not found
1015 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001016 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001017find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001018{
1019 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001020 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001021 int cmp;
1022 int x;
1023
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001024 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001025
1026 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001027 while (first <= last)
1028 {
1029 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001030 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001031 if (cmp < 0)
1032 last = x - 1;
1033 else if (cmp > 0)
1034 first = x + 1;
1035 else
1036 return x;
1037 }
1038 return -1;
1039}
1040
1041 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001042has_internal_func(char_u *name)
1043{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001044 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001045}
1046
1047 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001048call_internal_func(
1049 char_u *name,
1050 int argcount,
1051 typval_T *argvars,
1052 typval_T *rettv)
1053{
1054 int i;
1055
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001056 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001057 if (i < 0)
1058 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001059 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001060 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001061 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001062 return ERROR_TOOMANY;
1063 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001064 global_functions[i].f_func(argvars, rettv);
1065 return ERROR_NONE;
1066}
1067
1068/*
1069 * Invoke a method for base->method().
1070 */
1071 int
1072call_internal_method(
1073 char_u *name,
1074 int argcount,
1075 typval_T *argvars,
1076 typval_T *rettv,
1077 typval_T *basetv)
1078{
1079 int i;
1080 int fi;
1081 typval_T argv[MAX_FUNC_ARGS + 1];
1082
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001083 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001084 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001085 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001086 if (global_functions[fi].f_argtype == 0)
1087 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001088 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001089 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001090 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001091 return ERROR_TOOMANY;
1092
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001093 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001094 {
1095 // base value goes last
1096 for (i = 0; i < argcount; ++i)
1097 argv[i] = argvars[i];
1098 argv[argcount] = *basetv;
1099 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001100 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001101 {
1102 // base value goes second
1103 argv[0] = argvars[0];
1104 argv[1] = *basetv;
1105 for (i = 1; i < argcount; ++i)
1106 argv[i + 1] = argvars[i];
1107 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001108 else if (global_functions[fi].f_argtype == FEARG_3)
1109 {
1110 // base value goes third
1111 argv[0] = argvars[0];
1112 argv[1] = argvars[1];
1113 argv[2] = *basetv;
1114 for (i = 2; i < argcount; ++i)
1115 argv[i + 1] = argvars[i];
1116 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001117 else
1118 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001119 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001120 argv[0] = *basetv;
1121 for (i = 0; i < argcount; ++i)
1122 argv[i + 1] = argvars[i];
1123 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001124 argv[argcount + 1].v_type = VAR_UNKNOWN;
1125
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001126 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001127 return ERROR_NONE;
1128}
1129
1130/*
1131 * Return TRUE for a non-zero Number and a non-empty String.
1132 */
1133 static int
1134non_zero_arg(typval_T *argvars)
1135{
1136 return ((argvars[0].v_type == VAR_NUMBER
1137 && argvars[0].vval.v_number != 0)
1138 || (argvars[0].v_type == VAR_SPECIAL
1139 && argvars[0].vval.v_number == VVAL_TRUE)
1140 || (argvars[0].v_type == VAR_STRING
1141 && argvars[0].vval.v_string != NULL
1142 && *argvars[0].vval.v_string != NUL));
1143}
1144
1145/*
1146 * Get the lnum from the first argument.
1147 * Also accepts ".", "$", etc., but that only works for the current buffer.
1148 * Returns -1 on error.
1149 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001150 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001151tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001152{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001153 linenr_T lnum;
1154
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001155 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001156 if (lnum == 0) // no valid number, try using arg like line()
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001157 {
Bram Moolenaar1f3165b2019-09-04 13:21:26 +02001158 int fnum;
1159 pos_T *fp = var2fpos(&argvars[0], TRUE, &fnum);
1160
1161 if (fp != NULL)
1162 lnum = fp->lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001163 }
1164 return lnum;
1165}
1166
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001167/*
1168 * Get the lnum from the first argument.
1169 * Also accepts "$", then "buf" is used.
1170 * Returns 0 on error.
1171 */
1172 static linenr_T
1173tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1174{
1175 if (argvars[0].v_type == VAR_STRING
1176 && argvars[0].vval.v_string != NULL
1177 && argvars[0].vval.v_string[0] == '$'
1178 && buf != NULL)
1179 return buf->b_ml.ml_line_count;
1180 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1181}
1182
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001183#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001184/*
1185 * Get the float value of "argvars[0]" into "f".
1186 * Returns FAIL when the argument is not a Number or Float.
1187 */
1188 static int
1189get_float_arg(typval_T *argvars, float_T *f)
1190{
1191 if (argvars[0].v_type == VAR_FLOAT)
1192 {
1193 *f = argvars[0].vval.v_float;
1194 return OK;
1195 }
1196 if (argvars[0].v_type == VAR_NUMBER)
1197 {
1198 *f = (float_T)argvars[0].vval.v_number;
1199 return OK;
1200 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001201 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001202 return FAIL;
1203}
1204
1205/*
1206 * "abs(expr)" function
1207 */
1208 static void
1209f_abs(typval_T *argvars, typval_T *rettv)
1210{
1211 if (argvars[0].v_type == VAR_FLOAT)
1212 {
1213 rettv->v_type = VAR_FLOAT;
1214 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1215 }
1216 else
1217 {
1218 varnumber_T n;
1219 int error = FALSE;
1220
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001221 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001222 if (error)
1223 rettv->vval.v_number = -1;
1224 else if (n > 0)
1225 rettv->vval.v_number = n;
1226 else
1227 rettv->vval.v_number = -n;
1228 }
1229}
1230
1231/*
1232 * "acos()" function
1233 */
1234 static void
1235f_acos(typval_T *argvars, typval_T *rettv)
1236{
1237 float_T f = 0.0;
1238
1239 rettv->v_type = VAR_FLOAT;
1240 if (get_float_arg(argvars, &f) == OK)
1241 rettv->vval.v_float = acos(f);
1242 else
1243 rettv->vval.v_float = 0.0;
1244}
1245#endif
1246
1247/*
1248 * "add(list, item)" function
1249 */
1250 static void
1251f_add(typval_T *argvars, typval_T *rettv)
1252{
1253 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001254 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001255
1256 rettv->vval.v_number = 1; /* Default: Failed */
1257 if (argvars[0].v_type == VAR_LIST)
1258 {
1259 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001260 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001261 (char_u *)N_("add() argument"), TRUE)
1262 && list_append_tv(l, &argvars[1]) == OK)
1263 copy_tv(&argvars[0], rettv);
1264 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001265 else if (argvars[0].v_type == VAR_BLOB)
1266 {
1267 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001268 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001269 (char_u *)N_("add() argument"), TRUE))
1270 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001271 int error = FALSE;
1272 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1273
1274 if (!error)
1275 {
1276 ga_append(&b->bv_ga, (int)n);
1277 copy_tv(&argvars[0], rettv);
1278 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001279 }
1280 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001281 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001282 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001283}
1284
1285/*
1286 * "and(expr, expr)" function
1287 */
1288 static void
1289f_and(typval_T *argvars, typval_T *rettv)
1290{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001291 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1292 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001293}
1294
1295/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001296 * If there is a window for "curbuf", make it the current window.
1297 */
1298 static void
1299find_win_for_curbuf(void)
1300{
1301 wininfo_T *wip;
1302
1303 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1304 {
1305 if (wip->wi_win != NULL)
1306 {
1307 curwin = wip->wi_win;
1308 break;
1309 }
1310 }
1311}
1312
1313/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001314 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001315 */
1316 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001317set_buffer_lines(
1318 buf_T *buf,
1319 linenr_T lnum_arg,
1320 int append,
1321 typval_T *lines,
1322 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001323{
Bram Moolenaarca851592018-06-06 21:04:07 +02001324 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1325 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001326 list_T *l = NULL;
1327 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001328 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001329 linenr_T append_lnum;
1330 buf_T *curbuf_save = NULL;
1331 win_T *curwin_save = NULL;
1332 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001333
Bram Moolenaarca851592018-06-06 21:04:07 +02001334 /* When using the current buffer ml_mfp will be set if needed. Useful when
1335 * setline() is used on startup. For other buffers the buffer must be
1336 * loaded. */
1337 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001338 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001339 rettv->vval.v_number = 1; /* FAIL */
1340 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001341 }
1342
Bram Moolenaarca851592018-06-06 21:04:07 +02001343 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001344 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001345 curbuf_save = curbuf;
1346 curwin_save = curwin;
1347 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001348 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001349 }
1350
1351 if (append)
1352 // appendbufline() uses the line number below which we insert
1353 append_lnum = lnum - 1;
1354 else
1355 // setbufline() uses the line number above which we insert, we only
1356 // append if it's below the last line
1357 append_lnum = curbuf->b_ml.ml_line_count;
1358
1359 if (lines->v_type == VAR_LIST)
1360 {
1361 l = lines->vval.v_list;
1362 li = l->lv_first;
1363 }
1364 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001365 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001366
1367 /* default result is zero == OK */
1368 for (;;)
1369 {
1370 if (l != NULL)
1371 {
1372 /* list argument, get next string */
1373 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001374 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001375 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001376 li = li->li_next;
1377 }
1378
Bram Moolenaarca851592018-06-06 21:04:07 +02001379 rettv->vval.v_number = 1; /* FAIL */
1380 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1381 break;
1382
1383 /* When coming here from Insert mode, sync undo, so that this can be
1384 * undone separately from what was previously inserted. */
1385 if (u_sync_once == 2)
1386 {
1387 u_sync_once = 1; /* notify that u_sync() was called */
1388 u_sync(TRUE);
1389 }
1390
1391 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1392 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001393 // Existing line, replace it.
1394 // Removes any existing text properties.
1395 if (u_savesub(lnum) == OK && ml_replace_len(
1396 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001397 {
1398 changed_bytes(lnum, 0);
1399 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1400 check_cursor_col();
1401 rettv->vval.v_number = 0; /* OK */
1402 }
1403 }
1404 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1405 {
1406 /* append the line */
1407 ++added;
1408 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1409 rettv->vval.v_number = 0; /* OK */
1410 }
1411
1412 if (l == NULL) /* only one string argument */
1413 break;
1414 ++lnum;
1415 }
1416
1417 if (added > 0)
1418 {
1419 win_T *wp;
1420 tabpage_T *tp;
1421
1422 appended_lines_mark(append_lnum, added);
Bram Moolenaard2007022019-08-27 21:56:06 +02001423
1424 // Only adjust the cursor for buffers other than the current, unless it
1425 // is the current window. For curbuf and other windows it has been
1426 // done in mark_adjust_internal().
Bram Moolenaarca851592018-06-06 21:04:07 +02001427 FOR_ALL_TAB_WINDOWS(tp, wp)
Bram Moolenaard2007022019-08-27 21:56:06 +02001428 if (wp->w_buffer == buf
1429 && (wp->w_buffer != curbuf || wp == curwin)
1430 && wp->w_cursor.lnum > append_lnum)
Bram Moolenaarca851592018-06-06 21:04:07 +02001431 wp->w_cursor.lnum += added;
1432 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001433 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001434 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001435
1436 if (!is_curbuf)
1437 {
1438 curbuf = curbuf_save;
1439 curwin = curwin_save;
1440 }
1441}
1442
1443/*
1444 * "append(lnum, string/list)" function
1445 */
1446 static void
1447f_append(typval_T *argvars, typval_T *rettv)
1448{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001449 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001450
1451 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1452}
1453
1454/*
1455 * "appendbufline(buf, lnum, string/list)" function
1456 */
1457 static void
1458f_appendbufline(typval_T *argvars, typval_T *rettv)
1459{
1460 linenr_T lnum;
1461 buf_T *buf;
1462
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001463 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001464 if (buf == NULL)
1465 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001466 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001467 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001468 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001469 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1470 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001471}
1472
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001473#ifdef FEAT_FLOAT
1474/*
1475 * "asin()" function
1476 */
1477 static void
1478f_asin(typval_T *argvars, typval_T *rettv)
1479{
1480 float_T f = 0.0;
1481
1482 rettv->v_type = VAR_FLOAT;
1483 if (get_float_arg(argvars, &f) == OK)
1484 rettv->vval.v_float = asin(f);
1485 else
1486 rettv->vval.v_float = 0.0;
1487}
1488
1489/*
1490 * "atan()" function
1491 */
1492 static void
1493f_atan(typval_T *argvars, typval_T *rettv)
1494{
1495 float_T f = 0.0;
1496
1497 rettv->v_type = VAR_FLOAT;
1498 if (get_float_arg(argvars, &f) == OK)
1499 rettv->vval.v_float = atan(f);
1500 else
1501 rettv->vval.v_float = 0.0;
1502}
1503
1504/*
1505 * "atan2()" function
1506 */
1507 static void
1508f_atan2(typval_T *argvars, typval_T *rettv)
1509{
1510 float_T fx = 0.0, fy = 0.0;
1511
1512 rettv->v_type = VAR_FLOAT;
1513 if (get_float_arg(argvars, &fx) == OK
1514 && get_float_arg(&argvars[1], &fy) == OK)
1515 rettv->vval.v_float = atan2(fx, fy);
1516 else
1517 rettv->vval.v_float = 0.0;
1518}
1519#endif
1520
1521/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001522 * "balloon_show()" function
1523 */
1524#ifdef FEAT_BEVAL
1525 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001526f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1527{
1528 rettv->v_type = VAR_STRING;
1529 if (balloonEval != NULL)
1530 {
1531 if (balloonEval->msg == NULL)
1532 rettv->vval.v_string = NULL;
1533 else
1534 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1535 }
1536}
1537
1538 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001539f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1540{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001541 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001542 {
1543 if (argvars[0].v_type == VAR_LIST
1544# ifdef FEAT_GUI
1545 && !gui.in_use
1546# endif
1547 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001548 {
1549 list_T *l = argvars[0].vval.v_list;
1550
1551 // empty list removes the balloon
1552 post_balloon(balloonEval, NULL,
1553 l == NULL || l->lv_len == 0 ? NULL : l);
1554 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001555 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001556 {
1557 char_u *mesg = tv_get_string_chk(&argvars[0]);
1558
1559 if (mesg != NULL)
1560 // empty string removes the balloon
1561 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1562 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001563 }
1564}
1565
Bram Moolenaar669a8282017-11-19 20:13:05 +01001566# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001567 static void
1568f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1569{
1570 if (rettv_list_alloc(rettv) == OK)
1571 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001572 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001573
1574 if (msg != NULL)
1575 {
1576 pumitem_T *array;
1577 int size = split_message(msg, &array);
1578 int i;
1579
1580 /* Skip the first and last item, they are always empty. */
1581 for (i = 1; i < size - 1; ++i)
1582 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001583 while (size > 0)
1584 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001585 vim_free(array);
1586 }
1587 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001588}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001589# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001590#endif
1591
1592/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001593 * "browse(save, title, initdir, default)" function
1594 */
1595 static void
1596f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1597{
1598#ifdef FEAT_BROWSE
1599 int save;
1600 char_u *title;
1601 char_u *initdir;
1602 char_u *defname;
1603 char_u buf[NUMBUFLEN];
1604 char_u buf2[NUMBUFLEN];
1605 int error = FALSE;
1606
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001607 save = (int)tv_get_number_chk(&argvars[0], &error);
1608 title = tv_get_string_chk(&argvars[1]);
1609 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1610 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001611
1612 if (error || title == NULL || initdir == NULL || defname == NULL)
1613 rettv->vval.v_string = NULL;
1614 else
1615 rettv->vval.v_string =
1616 do_browse(save ? BROWSE_SAVE : 0,
1617 title, defname, NULL, initdir, NULL, curbuf);
1618#else
1619 rettv->vval.v_string = NULL;
1620#endif
1621 rettv->v_type = VAR_STRING;
1622}
1623
1624/*
1625 * "browsedir(title, initdir)" function
1626 */
1627 static void
1628f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1629{
1630#ifdef FEAT_BROWSE
1631 char_u *title;
1632 char_u *initdir;
1633 char_u buf[NUMBUFLEN];
1634
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001635 title = tv_get_string_chk(&argvars[0]);
1636 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001637
1638 if (title == NULL || initdir == NULL)
1639 rettv->vval.v_string = NULL;
1640 else
1641 rettv->vval.v_string = do_browse(BROWSE_DIR,
1642 title, NULL, NULL, initdir, NULL, curbuf);
1643#else
1644 rettv->vval.v_string = NULL;
1645#endif
1646 rettv->v_type = VAR_STRING;
1647}
1648
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649/*
1650 * Find a buffer by number or exact name.
1651 */
1652 static buf_T *
1653find_buffer(typval_T *avar)
1654{
1655 buf_T *buf = NULL;
1656
1657 if (avar->v_type == VAR_NUMBER)
1658 buf = buflist_findnr((int)avar->vval.v_number);
1659 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1660 {
1661 buf = buflist_findname_exp(avar->vval.v_string);
1662 if (buf == NULL)
1663 {
1664 /* No full path name match, try a match with a URL or a "nofile"
1665 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001666 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667 if (buf->b_fname != NULL
1668 && (path_with_url(buf->b_fname)
1669#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001670 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001671#endif
1672 )
1673 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1674 break;
1675 }
1676 }
1677 return buf;
1678}
1679
1680/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001681 * "bufadd(expr)" function
1682 */
1683 static void
1684f_bufadd(typval_T *argvars, typval_T *rettv)
1685{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001686 char_u *name = tv_get_string(&argvars[0]);
1687
1688 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001689}
1690
1691/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001692 * "bufexists(expr)" function
1693 */
1694 static void
1695f_bufexists(typval_T *argvars, typval_T *rettv)
1696{
1697 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1698}
1699
1700/*
1701 * "buflisted(expr)" function
1702 */
1703 static void
1704f_buflisted(typval_T *argvars, typval_T *rettv)
1705{
1706 buf_T *buf;
1707
1708 buf = find_buffer(&argvars[0]);
1709 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1710}
1711
1712/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001713 * "bufload(expr)" function
1714 */
1715 static void
1716f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1717{
1718 buf_T *buf = get_buf_arg(&argvars[0]);
1719
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001720 if (buf != NULL)
1721 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001722}
1723
1724/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001725 * "bufloaded(expr)" function
1726 */
1727 static void
1728f_bufloaded(typval_T *argvars, typval_T *rettv)
1729{
1730 buf_T *buf;
1731
1732 buf = find_buffer(&argvars[0]);
1733 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1734}
1735
1736 buf_T *
1737buflist_find_by_name(char_u *name, int curtab_only)
1738{
1739 int save_magic;
1740 char_u *save_cpo;
1741 buf_T *buf;
1742
1743 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1744 save_magic = p_magic;
1745 p_magic = TRUE;
1746 save_cpo = p_cpo;
1747 p_cpo = (char_u *)"";
1748
1749 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1750 TRUE, FALSE, curtab_only));
1751
1752 p_magic = save_magic;
1753 p_cpo = save_cpo;
1754 return buf;
1755}
1756
1757/*
1758 * Get buffer by number or pattern.
1759 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001760 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001761tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001762{
1763 char_u *name = tv->vval.v_string;
1764 buf_T *buf;
1765
1766 if (tv->v_type == VAR_NUMBER)
1767 return buflist_findnr((int)tv->vval.v_number);
1768 if (tv->v_type != VAR_STRING)
1769 return NULL;
1770 if (name == NULL || *name == NUL)
1771 return curbuf;
1772 if (name[0] == '$' && name[1] == NUL)
1773 return lastbuf;
1774
1775 buf = buflist_find_by_name(name, curtab_only);
1776
1777 /* If not found, try expanding the name, like done for bufexists(). */
1778 if (buf == NULL)
1779 buf = find_buffer(tv);
1780
1781 return buf;
1782}
1783
1784/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001785 * Get the buffer from "arg" and give an error and return NULL if it is not
1786 * valid.
1787 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001788 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001789get_buf_arg(typval_T *arg)
1790{
1791 buf_T *buf;
1792
1793 ++emsg_off;
1794 buf = tv_get_buf(arg, FALSE);
1795 --emsg_off;
1796 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001797 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001798 return buf;
1799}
1800
1801/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001802 * "bufname(expr)" function
1803 */
1804 static void
1805f_bufname(typval_T *argvars, typval_T *rettv)
1806{
1807 buf_T *buf;
1808
Bram Moolenaara8eee212019-08-24 22:14:58 +02001809 if (argvars[0].v_type == VAR_UNKNOWN)
1810 buf = curbuf;
1811 else
1812 {
1813 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1814 ++emsg_off;
1815 buf = tv_get_buf(&argvars[0], FALSE);
1816 --emsg_off;
1817 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001818 rettv->v_type = VAR_STRING;
1819 if (buf != NULL && buf->b_fname != NULL)
1820 rettv->vval.v_string = vim_strsave(buf->b_fname);
1821 else
1822 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001823}
1824
1825/*
1826 * "bufnr(expr)" function
1827 */
1828 static void
1829f_bufnr(typval_T *argvars, typval_T *rettv)
1830{
1831 buf_T *buf;
1832 int error = FALSE;
1833 char_u *name;
1834
Bram Moolenaara8eee212019-08-24 22:14:58 +02001835 if (argvars[0].v_type == VAR_UNKNOWN)
1836 buf = curbuf;
1837 else
1838 {
1839 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
1840 ++emsg_off;
1841 buf = tv_get_buf(&argvars[0], FALSE);
1842 --emsg_off;
1843 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001844
Bram Moolenaara8eee212019-08-24 22:14:58 +02001845 // If the buffer isn't found and the second argument is not zero create a
1846 // new buffer.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001847 if (buf == NULL
1848 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001849 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001850 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001851 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001852 && !error)
1853 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1854
1855 if (buf != NULL)
1856 rettv->vval.v_number = buf->b_fnum;
1857 else
1858 rettv->vval.v_number = -1;
1859}
1860
1861 static void
1862buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1863{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001864 win_T *wp;
1865 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001866 buf_T *buf;
1867
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001868 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001869 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001870 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001871 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001872 {
1873 ++winnr;
1874 if (wp->w_buffer == buf)
1875 break;
1876 }
1877 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001878 --emsg_off;
1879}
1880
1881/*
1882 * "bufwinid(nr)" function
1883 */
1884 static void
1885f_bufwinid(typval_T *argvars, typval_T *rettv)
1886{
1887 buf_win_common(argvars, rettv, FALSE);
1888}
1889
1890/*
1891 * "bufwinnr(nr)" function
1892 */
1893 static void
1894f_bufwinnr(typval_T *argvars, typval_T *rettv)
1895{
1896 buf_win_common(argvars, rettv, TRUE);
1897}
1898
1899/*
1900 * "byte2line(byte)" function
1901 */
1902 static void
1903f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1904{
1905#ifndef FEAT_BYTEOFF
1906 rettv->vval.v_number = -1;
1907#else
1908 long boff = 0;
1909
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001910 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001911 if (boff < 0)
1912 rettv->vval.v_number = -1;
1913 else
1914 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1915 (linenr_T)0, &boff);
1916#endif
1917}
1918
1919 static void
1920byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1921{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001922 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001923 char_u *str;
1924 varnumber_T idx;
1925
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001926 str = tv_get_string_chk(&argvars[0]);
1927 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001928 rettv->vval.v_number = -1;
1929 if (str == NULL || idx < 0)
1930 return;
1931
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001932 t = str;
1933 for ( ; idx > 0; idx--)
1934 {
1935 if (*t == NUL) /* EOL reached */
1936 return;
1937 if (enc_utf8 && comp)
1938 t += utf_ptr2len(t);
1939 else
1940 t += (*mb_ptr2len)(t);
1941 }
1942 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001943}
1944
1945/*
1946 * "byteidx()" function
1947 */
1948 static void
1949f_byteidx(typval_T *argvars, typval_T *rettv)
1950{
1951 byteidx(argvars, rettv, FALSE);
1952}
1953
1954/*
1955 * "byteidxcomp()" function
1956 */
1957 static void
1958f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1959{
1960 byteidx(argvars, rettv, TRUE);
1961}
1962
1963/*
1964 * "call(func, arglist [, dict])" function
1965 */
1966 static void
1967f_call(typval_T *argvars, typval_T *rettv)
1968{
1969 char_u *func;
1970 partial_T *partial = NULL;
1971 dict_T *selfdict = NULL;
1972
1973 if (argvars[1].v_type != VAR_LIST)
1974 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001975 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001976 return;
1977 }
1978 if (argvars[1].vval.v_list == NULL)
1979 return;
1980
1981 if (argvars[0].v_type == VAR_FUNC)
1982 func = argvars[0].vval.v_string;
1983 else if (argvars[0].v_type == VAR_PARTIAL)
1984 {
1985 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001986 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987 }
1988 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001989 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001990 if (*func == NUL)
1991 return; /* type error or empty name */
1992
1993 if (argvars[2].v_type != VAR_UNKNOWN)
1994 {
1995 if (argvars[2].v_type != VAR_DICT)
1996 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001997 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001998 return;
1999 }
2000 selfdict = argvars[2].vval.v_dict;
2001 }
2002
2003 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2004}
2005
2006#ifdef FEAT_FLOAT
2007/*
2008 * "ceil({float})" function
2009 */
2010 static void
2011f_ceil(typval_T *argvars, typval_T *rettv)
2012{
2013 float_T f = 0.0;
2014
2015 rettv->v_type = VAR_FLOAT;
2016 if (get_float_arg(argvars, &f) == OK)
2017 rettv->vval.v_float = ceil(f);
2018 else
2019 rettv->vval.v_float = 0.0;
2020}
2021#endif
2022
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002023/*
2024 * "changenr()" function
2025 */
2026 static void
2027f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2028{
2029 rettv->vval.v_number = curbuf->b_u_seq_cur;
2030}
2031
2032/*
2033 * "char2nr(string)" function
2034 */
2035 static void
2036f_char2nr(typval_T *argvars, typval_T *rettv)
2037{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002038 if (has_mbyte)
2039 {
2040 int utf8 = 0;
2041
2042 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002043 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002044
2045 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002046 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002047 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002048 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049 }
2050 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002051 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002052}
2053
2054/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002055 * "chdir(dir)" function
2056 */
2057 static void
2058f_chdir(typval_T *argvars, typval_T *rettv)
2059{
2060 char_u *cwd;
2061 cdscope_T scope = CDSCOPE_GLOBAL;
2062
2063 rettv->v_type = VAR_STRING;
2064 rettv->vval.v_string = NULL;
2065
2066 if (argvars[0].v_type != VAR_STRING)
2067 return;
2068
2069 // Return the current directory
2070 cwd = alloc(MAXPATHL);
2071 if (cwd != NULL)
2072 {
2073 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2074 {
2075#ifdef BACKSLASH_IN_FILENAME
2076 slash_adjust(cwd);
2077#endif
2078 rettv->vval.v_string = vim_strsave(cwd);
2079 }
2080 vim_free(cwd);
2081 }
2082
2083 if (curwin->w_localdir != NULL)
2084 scope = CDSCOPE_WINDOW;
2085 else if (curtab->tp_localdir != NULL)
2086 scope = CDSCOPE_TABPAGE;
2087
2088 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2089 // Directory change failed
2090 VIM_CLEAR(rettv->vval.v_string);
2091}
2092
2093/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002094 * "cindent(lnum)" function
2095 */
2096 static void
2097f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2098{
2099#ifdef FEAT_CINDENT
2100 pos_T pos;
2101 linenr_T lnum;
2102
2103 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002104 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002105 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2106 {
2107 curwin->w_cursor.lnum = lnum;
2108 rettv->vval.v_number = get_c_indent();
2109 curwin->w_cursor = pos;
2110 }
2111 else
2112#endif
2113 rettv->vval.v_number = -1;
2114}
2115
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002116 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002117get_optional_window(typval_T *argvars, int idx)
2118{
2119 win_T *win = curwin;
2120
2121 if (argvars[idx].v_type != VAR_UNKNOWN)
2122 {
2123 win = find_win_by_nr_or_id(&argvars[idx]);
2124 if (win == NULL)
2125 {
2126 emsg(_(e_invalwindow));
2127 return NULL;
2128 }
2129 }
2130 return win;
2131}
2132
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002133/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002134 * "col(string)" function
2135 */
2136 static void
2137f_col(typval_T *argvars, typval_T *rettv)
2138{
2139 colnr_T col = 0;
2140 pos_T *fp;
2141 int fnum = curbuf->b_fnum;
2142
2143 fp = var2fpos(&argvars[0], FALSE, &fnum);
2144 if (fp != NULL && fnum == curbuf->b_fnum)
2145 {
2146 if (fp->col == MAXCOL)
2147 {
2148 /* '> can be MAXCOL, get the length of the line then */
2149 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2150 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2151 else
2152 col = MAXCOL;
2153 }
2154 else
2155 {
2156 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002157 /* col(".") when the cursor is on the NUL at the end of the line
2158 * because of "coladd" can be seen as an extra column. */
2159 if (virtual_active() && fp == &curwin->w_cursor)
2160 {
2161 char_u *p = ml_get_cursor();
2162
2163 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2164 curwin->w_virtcol - curwin->w_cursor.coladd))
2165 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002166 int l;
2167
2168 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2169 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002170 }
2171 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002172 }
2173 }
2174 rettv->vval.v_number = col;
2175}
2176
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002177/*
2178 * "confirm(message, buttons[, default [, type]])" function
2179 */
2180 static void
2181f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2182{
2183#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2184 char_u *message;
2185 char_u *buttons = NULL;
2186 char_u buf[NUMBUFLEN];
2187 char_u buf2[NUMBUFLEN];
2188 int def = 1;
2189 int type = VIM_GENERIC;
2190 char_u *typestr;
2191 int error = FALSE;
2192
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002193 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002194 if (message == NULL)
2195 error = TRUE;
2196 if (argvars[1].v_type != VAR_UNKNOWN)
2197 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002198 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002199 if (buttons == NULL)
2200 error = TRUE;
2201 if (argvars[2].v_type != VAR_UNKNOWN)
2202 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002203 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002204 if (argvars[3].v_type != VAR_UNKNOWN)
2205 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002206 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207 if (typestr == NULL)
2208 error = TRUE;
2209 else
2210 {
2211 switch (TOUPPER_ASC(*typestr))
2212 {
2213 case 'E': type = VIM_ERROR; break;
2214 case 'Q': type = VIM_QUESTION; break;
2215 case 'I': type = VIM_INFO; break;
2216 case 'W': type = VIM_WARNING; break;
2217 case 'G': type = VIM_GENERIC; break;
2218 }
2219 }
2220 }
2221 }
2222 }
2223
2224 if (buttons == NULL || *buttons == NUL)
2225 buttons = (char_u *)_("&Ok");
2226
2227 if (!error)
2228 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2229 def, NULL, FALSE);
2230#endif
2231}
2232
2233/*
2234 * "copy()" function
2235 */
2236 static void
2237f_copy(typval_T *argvars, typval_T *rettv)
2238{
2239 item_copy(&argvars[0], rettv, FALSE, 0);
2240}
2241
2242#ifdef FEAT_FLOAT
2243/*
2244 * "cos()" function
2245 */
2246 static void
2247f_cos(typval_T *argvars, typval_T *rettv)
2248{
2249 float_T f = 0.0;
2250
2251 rettv->v_type = VAR_FLOAT;
2252 if (get_float_arg(argvars, &f) == OK)
2253 rettv->vval.v_float = cos(f);
2254 else
2255 rettv->vval.v_float = 0.0;
2256}
2257
2258/*
2259 * "cosh()" function
2260 */
2261 static void
2262f_cosh(typval_T *argvars, typval_T *rettv)
2263{
2264 float_T f = 0.0;
2265
2266 rettv->v_type = VAR_FLOAT;
2267 if (get_float_arg(argvars, &f) == OK)
2268 rettv->vval.v_float = cosh(f);
2269 else
2270 rettv->vval.v_float = 0.0;
2271}
2272#endif
2273
2274/*
2275 * "count()" function
2276 */
2277 static void
2278f_count(typval_T *argvars, typval_T *rettv)
2279{
2280 long n = 0;
2281 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002282 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002283
Bram Moolenaar9966b212017-07-28 16:46:57 +02002284 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002285 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002286
2287 if (argvars[0].v_type == VAR_STRING)
2288 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002289 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002290 char_u *p = argvars[0].vval.v_string;
2291 char_u *next;
2292
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002293 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002294 {
2295 if (ic)
2296 {
2297 size_t len = STRLEN(expr);
2298
2299 while (*p != NUL)
2300 {
2301 if (MB_STRNICMP(p, expr, len) == 0)
2302 {
2303 ++n;
2304 p += len;
2305 }
2306 else
2307 MB_PTR_ADV(p);
2308 }
2309 }
2310 else
2311 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2312 != NULL)
2313 {
2314 ++n;
2315 p = next + STRLEN(expr);
2316 }
2317 }
2318
2319 }
2320 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002321 {
2322 listitem_T *li;
2323 list_T *l;
2324 long idx;
2325
2326 if ((l = argvars[0].vval.v_list) != NULL)
2327 {
2328 li = l->lv_first;
2329 if (argvars[2].v_type != VAR_UNKNOWN)
2330 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002331 if (argvars[3].v_type != VAR_UNKNOWN)
2332 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002333 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002334 if (!error)
2335 {
2336 li = list_find(l, idx);
2337 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002338 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002339 }
2340 }
2341 if (error)
2342 li = NULL;
2343 }
2344
2345 for ( ; li != NULL; li = li->li_next)
2346 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2347 ++n;
2348 }
2349 }
2350 else if (argvars[0].v_type == VAR_DICT)
2351 {
2352 int todo;
2353 dict_T *d;
2354 hashitem_T *hi;
2355
2356 if ((d = argvars[0].vval.v_dict) != NULL)
2357 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002358 if (argvars[2].v_type != VAR_UNKNOWN)
2359 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002360 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002361 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002362 }
2363
2364 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2365 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2366 {
2367 if (!HASHITEM_EMPTY(hi))
2368 {
2369 --todo;
2370 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2371 ++n;
2372 }
2373 }
2374 }
2375 }
2376 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002377 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002378 rettv->vval.v_number = n;
2379}
2380
2381/*
2382 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2383 *
2384 * Checks the existence of a cscope connection.
2385 */
2386 static void
2387f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2388{
2389#ifdef FEAT_CSCOPE
2390 int num = 0;
2391 char_u *dbpath = NULL;
2392 char_u *prepend = NULL;
2393 char_u buf[NUMBUFLEN];
2394
2395 if (argvars[0].v_type != VAR_UNKNOWN
2396 && argvars[1].v_type != VAR_UNKNOWN)
2397 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002398 num = (int)tv_get_number(&argvars[0]);
2399 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002400 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002401 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002402 }
2403
2404 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2405#endif
2406}
2407
2408/*
2409 * "cursor(lnum, col)" function, or
2410 * "cursor(list)"
2411 *
2412 * Moves the cursor to the specified line and column.
2413 * Returns 0 when the position could be set, -1 otherwise.
2414 */
2415 static void
2416f_cursor(typval_T *argvars, typval_T *rettv)
2417{
2418 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002419 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002420 int set_curswant = TRUE;
2421
2422 rettv->vval.v_number = -1;
2423 if (argvars[1].v_type == VAR_UNKNOWN)
2424 {
2425 pos_T pos;
2426 colnr_T curswant = -1;
2427
2428 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2429 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002430 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002431 return;
2432 }
2433 line = pos.lnum;
2434 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002435 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002436 if (curswant >= 0)
2437 {
2438 curwin->w_curswant = curswant - 1;
2439 set_curswant = FALSE;
2440 }
2441 }
2442 else
2443 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002444 line = tv_get_lnum(argvars);
2445 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002446 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002447 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002448 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002449 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 return; /* type error; errmsg already given */
2451 if (line > 0)
2452 curwin->w_cursor.lnum = line;
2453 if (col > 0)
2454 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002455 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002456
2457 /* Make sure the cursor is in a valid position. */
2458 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459 /* Correct cursor for multi-byte character. */
2460 if (has_mbyte)
2461 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002462
2463 curwin->w_set_curswant = set_curswant;
2464 rettv->vval.v_number = 0;
2465}
2466
Bram Moolenaar4f974752019-02-17 17:44:42 +01002467#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002468/*
2469 * "debugbreak()" function
2470 */
2471 static void
2472f_debugbreak(typval_T *argvars, typval_T *rettv)
2473{
2474 int pid;
2475
2476 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002477 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002478 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002479 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002480 else
2481 {
2482 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2483
2484 if (hProcess != NULL)
2485 {
2486 DebugBreakProcess(hProcess);
2487 CloseHandle(hProcess);
2488 rettv->vval.v_number = OK;
2489 }
2490 }
2491}
2492#endif
2493
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002494/*
2495 * "deepcopy()" function
2496 */
2497 static void
2498f_deepcopy(typval_T *argvars, typval_T *rettv)
2499{
2500 int noref = 0;
2501 int copyID;
2502
2503 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002504 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002505 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002506 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002507 else
2508 {
2509 copyID = get_copyID();
2510 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2511 }
2512}
2513
2514/*
2515 * "delete()" function
2516 */
2517 static void
2518f_delete(typval_T *argvars, typval_T *rettv)
2519{
2520 char_u nbuf[NUMBUFLEN];
2521 char_u *name;
2522 char_u *flags;
2523
2524 rettv->vval.v_number = -1;
2525 if (check_restricted() || check_secure())
2526 return;
2527
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002528 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002529 if (name == NULL || *name == NUL)
2530 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002531 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002532 return;
2533 }
2534
2535 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002536 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002537 else
2538 flags = (char_u *)"";
2539
2540 if (*flags == NUL)
2541 /* delete a file */
2542 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2543 else if (STRCMP(flags, "d") == 0)
2544 /* delete an empty directory */
2545 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2546 else if (STRCMP(flags, "rf") == 0)
2547 /* delete a directory recursively */
2548 rettv->vval.v_number = delete_recursive(name);
2549 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002550 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002551}
2552
2553/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002554 * "deletebufline()" function
2555 */
2556 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002557f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002558{
2559 buf_T *buf;
2560 linenr_T first, last;
2561 linenr_T lnum;
2562 long count;
2563 int is_curbuf;
2564 buf_T *curbuf_save = NULL;
2565 win_T *curwin_save = NULL;
2566 tabpage_T *tp;
2567 win_T *wp;
2568
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002569 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002570 if (buf == NULL)
2571 {
2572 rettv->vval.v_number = 1; /* FAIL */
2573 return;
2574 }
2575 is_curbuf = buf == curbuf;
2576
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002577 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002578 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002579 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002580 else
2581 last = first;
2582
2583 if (buf->b_ml.ml_mfp == NULL || first < 1
2584 || first > buf->b_ml.ml_line_count || last < first)
2585 {
2586 rettv->vval.v_number = 1; /* FAIL */
2587 return;
2588 }
2589
2590 if (!is_curbuf)
2591 {
2592 curbuf_save = curbuf;
2593 curwin_save = curwin;
2594 curbuf = buf;
2595 find_win_for_curbuf();
2596 }
2597 if (last > curbuf->b_ml.ml_line_count)
2598 last = curbuf->b_ml.ml_line_count;
2599 count = last - first + 1;
2600
2601 // When coming here from Insert mode, sync undo, so that this can be
2602 // undone separately from what was previously inserted.
2603 if (u_sync_once == 2)
2604 {
2605 u_sync_once = 1; // notify that u_sync() was called
2606 u_sync(TRUE);
2607 }
2608
2609 if (u_save(first - 1, last + 1) == FAIL)
2610 {
2611 rettv->vval.v_number = 1; /* FAIL */
2612 return;
2613 }
2614
2615 for (lnum = first; lnum <= last; ++lnum)
2616 ml_delete(first, TRUE);
2617
2618 FOR_ALL_TAB_WINDOWS(tp, wp)
2619 if (wp->w_buffer == buf)
2620 {
2621 if (wp->w_cursor.lnum > last)
2622 wp->w_cursor.lnum -= count;
2623 else if (wp->w_cursor.lnum> first)
2624 wp->w_cursor.lnum = first;
2625 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2626 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2627 }
2628 check_cursor_col();
2629 deleted_lines_mark(first, count);
2630
2631 if (!is_curbuf)
2632 {
2633 curbuf = curbuf_save;
2634 curwin = curwin_save;
2635 }
2636}
2637
2638/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002639 * "did_filetype()" function
2640 */
2641 static void
2642f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2643{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002644 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002645}
2646
2647/*
2648 * "diff_filler()" function
2649 */
2650 static void
2651f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2652{
2653#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002654 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002655#endif
2656}
2657
2658/*
2659 * "diff_hlID()" function
2660 */
2661 static void
2662f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2663{
2664#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002665 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002666 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002667 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002668 static int fnum = 0;
2669 static int change_start = 0;
2670 static int change_end = 0;
2671 static hlf_T hlID = (hlf_T)0;
2672 int filler_lines;
2673 int col;
2674
2675 if (lnum < 0) /* ignore type error in {lnum} arg */
2676 lnum = 0;
2677 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002678 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002679 || fnum != curbuf->b_fnum)
2680 {
2681 /* New line, buffer, change: need to get the values. */
2682 filler_lines = diff_check(curwin, lnum);
2683 if (filler_lines < 0)
2684 {
2685 if (filler_lines == -1)
2686 {
2687 change_start = MAXCOL;
2688 change_end = -1;
2689 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2690 hlID = HLF_ADD; /* added line */
2691 else
2692 hlID = HLF_CHD; /* changed line */
2693 }
2694 else
2695 hlID = HLF_ADD; /* added line */
2696 }
2697 else
2698 hlID = (hlf_T)0;
2699 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002700 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002701 fnum = curbuf->b_fnum;
2702 }
2703
2704 if (hlID == HLF_CHD || hlID == HLF_TXD)
2705 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002706 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002707 if (col >= change_start && col <= change_end)
2708 hlID = HLF_TXD; /* changed text */
2709 else
2710 hlID = HLF_CHD; /* changed line */
2711 }
2712 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2713#endif
2714}
2715
2716/*
2717 * "empty({expr})" function
2718 */
2719 static void
2720f_empty(typval_T *argvars, typval_T *rettv)
2721{
2722 int n = FALSE;
2723
2724 switch (argvars[0].v_type)
2725 {
2726 case VAR_STRING:
2727 case VAR_FUNC:
2728 n = argvars[0].vval.v_string == NULL
2729 || *argvars[0].vval.v_string == NUL;
2730 break;
2731 case VAR_PARTIAL:
2732 n = FALSE;
2733 break;
2734 case VAR_NUMBER:
2735 n = argvars[0].vval.v_number == 0;
2736 break;
2737 case VAR_FLOAT:
2738#ifdef FEAT_FLOAT
2739 n = argvars[0].vval.v_float == 0.0;
2740 break;
2741#endif
2742 case VAR_LIST:
2743 n = argvars[0].vval.v_list == NULL
2744 || argvars[0].vval.v_list->lv_first == NULL;
2745 break;
2746 case VAR_DICT:
2747 n = argvars[0].vval.v_dict == NULL
2748 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2749 break;
2750 case VAR_SPECIAL:
2751 n = argvars[0].vval.v_number != VVAL_TRUE;
2752 break;
2753
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002754 case VAR_BLOB:
2755 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002756 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2757 break;
2758
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002759 case VAR_JOB:
2760#ifdef FEAT_JOB_CHANNEL
2761 n = argvars[0].vval.v_job == NULL
2762 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2763 break;
2764#endif
2765 case VAR_CHANNEL:
2766#ifdef FEAT_JOB_CHANNEL
2767 n = argvars[0].vval.v_channel == NULL
2768 || !channel_is_open(argvars[0].vval.v_channel);
2769 break;
2770#endif
2771 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002772 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002773 n = TRUE;
2774 break;
2775 }
2776
2777 rettv->vval.v_number = n;
2778}
2779
2780/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002781 * "environ()" function
2782 */
2783 static void
2784f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2785{
2786#if !defined(AMIGA)
2787 int i = 0;
2788 char_u *entry, *value;
2789# ifdef MSWIN
2790 extern wchar_t **_wenviron;
2791# else
2792 extern char **environ;
2793# endif
2794
2795 if (rettv_dict_alloc(rettv) != OK)
2796 return;
2797
2798# ifdef MSWIN
2799 if (*_wenviron == NULL)
2800 return;
2801# else
2802 if (*environ == NULL)
2803 return;
2804# endif
2805
2806 for (i = 0; ; ++i)
2807 {
2808# ifdef MSWIN
2809 short_u *p;
2810
2811 if ((p = (short_u *)_wenviron[i]) == NULL)
2812 return;
2813 entry = utf16_to_enc(p, NULL);
2814# else
2815 if ((entry = (char_u *)environ[i]) == NULL)
2816 return;
2817 entry = vim_strsave(entry);
2818# endif
2819 if (entry == NULL) // out of memory
2820 return;
2821 if ((value = vim_strchr(entry, '=')) == NULL)
2822 {
2823 vim_free(entry);
2824 continue;
2825 }
2826 *value++ = NUL;
2827 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2828 vim_free(entry);
2829 }
2830#endif
2831}
2832
2833/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002834 * "escape({string}, {chars})" function
2835 */
2836 static void
2837f_escape(typval_T *argvars, typval_T *rettv)
2838{
2839 char_u buf[NUMBUFLEN];
2840
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002841 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2842 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002843 rettv->v_type = VAR_STRING;
2844}
2845
2846/*
2847 * "eval()" function
2848 */
2849 static void
2850f_eval(typval_T *argvars, typval_T *rettv)
2851{
2852 char_u *s, *p;
2853
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002854 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002855 if (s != NULL)
2856 s = skipwhite(s);
2857
2858 p = s;
2859 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2860 {
2861 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002862 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002863 need_clr_eos = FALSE;
2864 rettv->v_type = VAR_NUMBER;
2865 rettv->vval.v_number = 0;
2866 }
2867 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002868 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002869}
2870
2871/*
2872 * "eventhandler()" function
2873 */
2874 static void
2875f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2876{
2877 rettv->vval.v_number = vgetc_busy;
2878}
2879
2880/*
2881 * "executable()" function
2882 */
2883 static void
2884f_executable(typval_T *argvars, typval_T *rettv)
2885{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002886 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002887
2888 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02002889 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002890}
2891
2892static garray_T redir_execute_ga;
2893
2894/*
2895 * Append "value[value_len]" to the execute() output.
2896 */
2897 void
2898execute_redir_str(char_u *value, int value_len)
2899{
2900 int len;
2901
2902 if (value_len == -1)
2903 len = (int)STRLEN(value); /* Append the entire string */
2904 else
2905 len = value_len; /* Append only "value_len" characters */
2906 if (ga_grow(&redir_execute_ga, len) == OK)
2907 {
2908 mch_memmove((char *)redir_execute_ga.ga_data
2909 + redir_execute_ga.ga_len, value, len);
2910 redir_execute_ga.ga_len += len;
2911 }
2912}
2913
2914/*
2915 * Get next line from a list.
2916 * Called by do_cmdline() to get the next line.
2917 * Returns allocated string, or NULL for end of function.
2918 */
2919
2920 static char_u *
2921get_list_line(
2922 int c UNUSED,
2923 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002924 int indent UNUSED,
2925 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002926{
2927 listitem_T **p = (listitem_T **)cookie;
2928 listitem_T *item = *p;
2929 char_u buf[NUMBUFLEN];
2930 char_u *s;
2931
2932 if (item == NULL)
2933 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002934 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002935 *p = item->li_next;
2936 return s == NULL ? NULL : vim_strsave(s);
2937}
2938
2939/*
2940 * "execute()" function
2941 */
2942 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002943execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002944{
2945 char_u *cmd = NULL;
2946 list_T *list = NULL;
2947 int save_msg_silent = msg_silent;
2948 int save_emsg_silent = emsg_silent;
2949 int save_emsg_noredir = emsg_noredir;
2950 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002951 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002952 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002953 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002954 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002955
2956 rettv->vval.v_string = NULL;
2957 rettv->v_type = VAR_STRING;
2958
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002959 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002960 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002961 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002962 if (list == NULL || list->lv_first == NULL)
2963 /* empty list, no commands, empty output */
2964 return;
2965 ++list->lv_refcount;
2966 }
2967 else
2968 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002969 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002970 if (cmd == NULL)
2971 return;
2972 }
2973
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002974 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002975 {
2976 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002977 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002978
2979 if (s == NULL)
2980 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002981 if (*s == NUL)
2982 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002983 if (STRNCMP(s, "silent", 6) == 0)
2984 ++msg_silent;
2985 if (STRCMP(s, "silent!") == 0)
2986 {
2987 emsg_silent = TRUE;
2988 emsg_noredir = TRUE;
2989 }
2990 }
2991 else
2992 ++msg_silent;
2993
2994 if (redir_execute)
2995 save_ga = redir_execute_ga;
2996 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
2997 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01002998 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002999 if (!echo_output)
3000 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003001
3002 if (cmd != NULL)
3003 do_cmdline_cmd(cmd);
3004 else
3005 {
3006 listitem_T *item = list->lv_first;
3007
3008 do_cmdline(NULL, get_list_line, (void *)&item,
3009 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3010 --list->lv_refcount;
3011 }
3012
Bram Moolenaard297f352017-01-29 20:31:21 +01003013 /* Need to append a NUL to the result. */
3014 if (ga_grow(&redir_execute_ga, 1) == OK)
3015 {
3016 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3017 rettv->vval.v_string = redir_execute_ga.ga_data;
3018 }
3019 else
3020 {
3021 ga_clear(&redir_execute_ga);
3022 rettv->vval.v_string = NULL;
3023 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003024 msg_silent = save_msg_silent;
3025 emsg_silent = save_emsg_silent;
3026 emsg_noredir = save_emsg_noredir;
3027
3028 redir_execute = save_redir_execute;
3029 if (redir_execute)
3030 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003031 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003032
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003033 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003034 if (echo_output)
3035 // When not working silently: put it in column zero. A following
3036 // "echon" will overwrite the message, unavoidably.
3037 msg_col = 0;
3038 else
3039 // When working silently: Put it back where it was, since nothing
3040 // should have been written.
3041 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003042}
3043
3044/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003045 * "execute()" function
3046 */
3047 static void
3048f_execute(typval_T *argvars, typval_T *rettv)
3049{
3050 execute_common(argvars, rettv, 0);
3051}
3052
3053/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003054 * "exepath()" function
3055 */
3056 static void
3057f_exepath(typval_T *argvars, typval_T *rettv)
3058{
3059 char_u *p = NULL;
3060
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003061 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003062 rettv->v_type = VAR_STRING;
3063 rettv->vval.v_string = p;
3064}
3065
3066/*
3067 * "exists()" function
3068 */
3069 static void
3070f_exists(typval_T *argvars, typval_T *rettv)
3071{
3072 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003073 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003074
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003075 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003076 if (*p == '$') /* environment variable */
3077 {
3078 /* first try "normal" environment variables (fast) */
3079 if (mch_getenv(p + 1) != NULL)
3080 n = TRUE;
3081 else
3082 {
3083 /* try expanding things like $VIM and ${HOME} */
3084 p = expand_env_save(p);
3085 if (p != NULL && *p != '$')
3086 n = TRUE;
3087 vim_free(p);
3088 }
3089 }
3090 else if (*p == '&' || *p == '+') /* option */
3091 {
3092 n = (get_option_tv(&p, NULL, TRUE) == OK);
3093 if (*skipwhite(p) != NUL)
3094 n = FALSE; /* trailing garbage */
3095 }
3096 else if (*p == '*') /* internal or user defined function */
3097 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003098 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003099 }
3100 else if (*p == ':')
3101 {
3102 n = cmd_exists(p + 1);
3103 }
3104 else if (*p == '#')
3105 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003106 if (p[1] == '#')
3107 n = autocmd_supported(p + 2);
3108 else
3109 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003110 }
3111 else /* internal variable */
3112 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003113 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003114 }
3115
3116 rettv->vval.v_number = n;
3117}
3118
3119#ifdef FEAT_FLOAT
3120/*
3121 * "exp()" function
3122 */
3123 static void
3124f_exp(typval_T *argvars, typval_T *rettv)
3125{
3126 float_T f = 0.0;
3127
3128 rettv->v_type = VAR_FLOAT;
3129 if (get_float_arg(argvars, &f) == OK)
3130 rettv->vval.v_float = exp(f);
3131 else
3132 rettv->vval.v_float = 0.0;
3133}
3134#endif
3135
3136/*
3137 * "expand()" function
3138 */
3139 static void
3140f_expand(typval_T *argvars, typval_T *rettv)
3141{
3142 char_u *s;
3143 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003144 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003145 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3146 expand_T xpc;
3147 int error = FALSE;
3148 char_u *result;
3149
3150 rettv->v_type = VAR_STRING;
3151 if (argvars[1].v_type != VAR_UNKNOWN
3152 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003153 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003154 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003155 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003156
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003157 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003158 if (*s == '%' || *s == '#' || *s == '<')
3159 {
3160 ++emsg_off;
3161 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3162 --emsg_off;
3163 if (rettv->v_type == VAR_LIST)
3164 {
3165 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3166 list_append_string(rettv->vval.v_list, result, -1);
3167 else
3168 vim_free(result);
3169 }
3170 else
3171 rettv->vval.v_string = result;
3172 }
3173 else
3174 {
3175 /* When the optional second argument is non-zero, don't remove matches
3176 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3177 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003178 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003179 options |= WILD_KEEP_ALL;
3180 if (!error)
3181 {
3182 ExpandInit(&xpc);
3183 xpc.xp_context = EXPAND_FILES;
3184 if (p_wic)
3185 options += WILD_ICASE;
3186 if (rettv->v_type == VAR_STRING)
3187 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3188 options, WILD_ALL);
3189 else if (rettv_list_alloc(rettv) != FAIL)
3190 {
3191 int i;
3192
3193 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3194 for (i = 0; i < xpc.xp_numfiles; i++)
3195 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3196 ExpandCleanup(&xpc);
3197 }
3198 }
3199 else
3200 rettv->vval.v_string = NULL;
3201 }
3202}
3203
3204/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003205 * "expandcmd()" function
3206 * Expand all the special characters in a command string.
3207 */
3208 static void
3209f_expandcmd(typval_T *argvars, typval_T *rettv)
3210{
3211 exarg_T eap;
3212 char_u *cmdstr;
3213 char *errormsg = NULL;
3214
3215 rettv->v_type = VAR_STRING;
3216 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3217
3218 memset(&eap, 0, sizeof(eap));
3219 eap.cmd = cmdstr;
3220 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003221 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003222 eap.usefilter = FALSE;
3223 eap.nextcmd = NULL;
3224 eap.cmdidx = CMD_USER;
3225
3226 expand_filename(&eap, &cmdstr, &errormsg);
3227 if (errormsg != NULL && *errormsg != NUL)
3228 emsg(errormsg);
3229
3230 rettv->vval.v_string = cmdstr;
3231}
3232
3233/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003234 * "extend(list, list [, idx])" function
3235 * "extend(dict, dict [, action])" function
3236 */
3237 static void
3238f_extend(typval_T *argvars, typval_T *rettv)
3239{
3240 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3241
3242 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3243 {
3244 list_T *l1, *l2;
3245 listitem_T *item;
3246 long before;
3247 int error = FALSE;
3248
3249 l1 = argvars[0].vval.v_list;
3250 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003251 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003252 && l2 != NULL)
3253 {
3254 if (argvars[2].v_type != VAR_UNKNOWN)
3255 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003256 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003257 if (error)
3258 return; /* type error; errmsg already given */
3259
3260 if (before == l1->lv_len)
3261 item = NULL;
3262 else
3263 {
3264 item = list_find(l1, before);
3265 if (item == NULL)
3266 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003267 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003268 return;
3269 }
3270 }
3271 }
3272 else
3273 item = NULL;
3274 list_extend(l1, l2, item);
3275
3276 copy_tv(&argvars[0], rettv);
3277 }
3278 }
3279 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3280 {
3281 dict_T *d1, *d2;
3282 char_u *action;
3283 int i;
3284
3285 d1 = argvars[0].vval.v_dict;
3286 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003287 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003288 && d2 != NULL)
3289 {
3290 /* Check the third argument. */
3291 if (argvars[2].v_type != VAR_UNKNOWN)
3292 {
3293 static char *(av[]) = {"keep", "force", "error"};
3294
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003295 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003296 if (action == NULL)
3297 return; /* type error; errmsg already given */
3298 for (i = 0; i < 3; ++i)
3299 if (STRCMP(action, av[i]) == 0)
3300 break;
3301 if (i == 3)
3302 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003303 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003304 return;
3305 }
3306 }
3307 else
3308 action = (char_u *)"force";
3309
3310 dict_extend(d1, d2, action);
3311
3312 copy_tv(&argvars[0], rettv);
3313 }
3314 }
3315 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003316 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003317}
3318
3319/*
3320 * "feedkeys()" function
3321 */
3322 static void
3323f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3324{
3325 int remap = TRUE;
3326 int insert = FALSE;
3327 char_u *keys, *flags;
3328 char_u nbuf[NUMBUFLEN];
3329 int typed = FALSE;
3330 int execute = FALSE;
3331 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003332 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003333 char_u *keys_esc;
3334
3335 /* This is not allowed in the sandbox. If the commands would still be
3336 * executed in the sandbox it would be OK, but it probably happens later,
3337 * when "sandbox" is no longer set. */
3338 if (check_secure())
3339 return;
3340
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003341 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003342
3343 if (argvars[1].v_type != VAR_UNKNOWN)
3344 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003345 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003346 for ( ; *flags != NUL; ++flags)
3347 {
3348 switch (*flags)
3349 {
3350 case 'n': remap = FALSE; break;
3351 case 'm': remap = TRUE; break;
3352 case 't': typed = TRUE; break;
3353 case 'i': insert = TRUE; break;
3354 case 'x': execute = TRUE; break;
3355 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003356 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003357 }
3358 }
3359 }
3360
3361 if (*keys != NUL || execute)
3362 {
3363 /* Need to escape K_SPECIAL and CSI before putting the string in the
3364 * typeahead buffer. */
3365 keys_esc = vim_strsave_escape_csi(keys);
3366 if (keys_esc != NULL)
3367 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003368 if (lowlevel)
3369 {
3370#ifdef USE_INPUT_BUF
3371 add_to_input_buf(keys, (int)STRLEN(keys));
3372#else
3373 emsg(_("E980: lowlevel input not supported"));
3374#endif
3375 }
3376 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003377 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003378 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003379 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003380 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003381#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003382 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003383#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003384 )
3385 typebuf_was_filled = TRUE;
3386 }
3387 vim_free(keys_esc);
3388
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003389 if (execute)
3390 {
3391 int save_msg_scroll = msg_scroll;
3392
3393 /* Avoid a 1 second delay when the keys start Insert mode. */
3394 msg_scroll = FALSE;
3395
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003396 if (!dangerous)
3397 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003398 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003399 if (!dangerous)
3400 --ex_normal_busy;
3401
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003402 msg_scroll |= save_msg_scroll;
3403 }
3404 }
3405 }
3406}
3407
3408/*
3409 * "filereadable()" function
3410 */
3411 static void
3412f_filereadable(typval_T *argvars, typval_T *rettv)
3413{
3414 int fd;
3415 char_u *p;
3416 int n;
3417
3418#ifndef O_NONBLOCK
3419# define O_NONBLOCK 0
3420#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003421 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003422 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3423 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3424 {
3425 n = TRUE;
3426 close(fd);
3427 }
3428 else
3429 n = FALSE;
3430
3431 rettv->vval.v_number = n;
3432}
3433
3434/*
3435 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3436 * rights to write into.
3437 */
3438 static void
3439f_filewritable(typval_T *argvars, typval_T *rettv)
3440{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003441 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003442}
3443
3444 static void
3445findfilendir(
3446 typval_T *argvars UNUSED,
3447 typval_T *rettv,
3448 int find_what UNUSED)
3449{
3450#ifdef FEAT_SEARCHPATH
3451 char_u *fname;
3452 char_u *fresult = NULL;
3453 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3454 char_u *p;
3455 char_u pathbuf[NUMBUFLEN];
3456 int count = 1;
3457 int first = TRUE;
3458 int error = FALSE;
3459#endif
3460
3461 rettv->vval.v_string = NULL;
3462 rettv->v_type = VAR_STRING;
3463
3464#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003465 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003466
3467 if (argvars[1].v_type != VAR_UNKNOWN)
3468 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003469 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470 if (p == NULL)
3471 error = TRUE;
3472 else
3473 {
3474 if (*p != NUL)
3475 path = p;
3476
3477 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003478 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003479 }
3480 }
3481
3482 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3483 error = TRUE;
3484
3485 if (*fname != NUL && !error)
3486 {
3487 do
3488 {
3489 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3490 vim_free(fresult);
3491 fresult = find_file_in_path_option(first ? fname : NULL,
3492 first ? (int)STRLEN(fname) : 0,
3493 0, first, path,
3494 find_what,
3495 curbuf->b_ffname,
3496 find_what == FINDFILE_DIR
3497 ? (char_u *)"" : curbuf->b_p_sua);
3498 first = FALSE;
3499
3500 if (fresult != NULL && rettv->v_type == VAR_LIST)
3501 list_append_string(rettv->vval.v_list, fresult, -1);
3502
3503 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3504 }
3505
3506 if (rettv->v_type == VAR_STRING)
3507 rettv->vval.v_string = fresult;
3508#endif
3509}
3510
3511/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003512 * "finddir({fname}[, {path}[, {count}]])" function
3513 */
3514 static void
3515f_finddir(typval_T *argvars, typval_T *rettv)
3516{
3517 findfilendir(argvars, rettv, FINDFILE_DIR);
3518}
3519
3520/*
3521 * "findfile({fname}[, {path}[, {count}]])" function
3522 */
3523 static void
3524f_findfile(typval_T *argvars, typval_T *rettv)
3525{
3526 findfilendir(argvars, rettv, FINDFILE_FILE);
3527}
3528
3529#ifdef FEAT_FLOAT
3530/*
3531 * "float2nr({float})" function
3532 */
3533 static void
3534f_float2nr(typval_T *argvars, typval_T *rettv)
3535{
3536 float_T f = 0.0;
3537
3538 if (get_float_arg(argvars, &f) == OK)
3539 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003540 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003541 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003542 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003543 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003544 else
3545 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003546 }
3547}
3548
3549/*
3550 * "floor({float})" function
3551 */
3552 static void
3553f_floor(typval_T *argvars, typval_T *rettv)
3554{
3555 float_T f = 0.0;
3556
3557 rettv->v_type = VAR_FLOAT;
3558 if (get_float_arg(argvars, &f) == OK)
3559 rettv->vval.v_float = floor(f);
3560 else
3561 rettv->vval.v_float = 0.0;
3562}
3563
3564/*
3565 * "fmod()" function
3566 */
3567 static void
3568f_fmod(typval_T *argvars, typval_T *rettv)
3569{
3570 float_T fx = 0.0, fy = 0.0;
3571
3572 rettv->v_type = VAR_FLOAT;
3573 if (get_float_arg(argvars, &fx) == OK
3574 && get_float_arg(&argvars[1], &fy) == OK)
3575 rettv->vval.v_float = fmod(fx, fy);
3576 else
3577 rettv->vval.v_float = 0.0;
3578}
3579#endif
3580
3581/*
3582 * "fnameescape({string})" function
3583 */
3584 static void
3585f_fnameescape(typval_T *argvars, typval_T *rettv)
3586{
3587 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003588 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003589 rettv->v_type = VAR_STRING;
3590}
3591
3592/*
3593 * "fnamemodify({fname}, {mods})" function
3594 */
3595 static void
3596f_fnamemodify(typval_T *argvars, typval_T *rettv)
3597{
3598 char_u *fname;
3599 char_u *mods;
3600 int usedlen = 0;
3601 int len;
3602 char_u *fbuf = NULL;
3603 char_u buf[NUMBUFLEN];
3604
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003605 fname = tv_get_string_chk(&argvars[0]);
3606 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003607 if (fname == NULL || mods == NULL)
3608 fname = NULL;
3609 else
3610 {
3611 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003612 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003613 }
3614
3615 rettv->v_type = VAR_STRING;
3616 if (fname == NULL)
3617 rettv->vval.v_string = NULL;
3618 else
3619 rettv->vval.v_string = vim_strnsave(fname, len);
3620 vim_free(fbuf);
3621}
3622
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003623/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003624 * "foreground()" function
3625 */
3626 static void
3627f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3628{
3629#ifdef FEAT_GUI
3630 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003631 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003632 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003633 return;
3634 }
3635#endif
3636#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003637 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003638#endif
3639}
3640
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003641 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003642common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643{
3644 char_u *s;
3645 char_u *name;
3646 int use_string = FALSE;
3647 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003648 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003649
3650 if (argvars[0].v_type == VAR_FUNC)
3651 {
3652 /* function(MyFunc, [arg], dict) */
3653 s = argvars[0].vval.v_string;
3654 }
3655 else if (argvars[0].v_type == VAR_PARTIAL
3656 && argvars[0].vval.v_partial != NULL)
3657 {
3658 /* function(dict.MyFunc, [arg]) */
3659 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003660 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003661 }
3662 else
3663 {
3664 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003665 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003666 use_string = TRUE;
3667 }
3668
Bram Moolenaar843b8842016-08-21 14:36:15 +02003669 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003670 {
3671 name = s;
3672 trans_name = trans_function_name(&name, FALSE,
3673 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3674 if (*name != NUL)
3675 s = NULL;
3676 }
3677
Bram Moolenaar843b8842016-08-21 14:36:15 +02003678 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3679 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003680 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003681 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003682 else if (trans_name != NULL && (is_funcref
3683 ? find_func(trans_name) == NULL
3684 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003685 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003686 else
3687 {
3688 int dict_idx = 0;
3689 int arg_idx = 0;
3690 list_T *list = NULL;
3691
3692 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3693 {
3694 char sid_buf[25];
3695 int off = *s == 's' ? 2 : 5;
3696
3697 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3698 * also be called from another script. Using trans_function_name()
3699 * would also work, but some plugins depend on the name being
3700 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003701 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003702 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003703 if (name != NULL)
3704 {
3705 STRCPY(name, sid_buf);
3706 STRCAT(name, s + off);
3707 }
3708 }
3709 else
3710 name = vim_strsave(s);
3711
3712 if (argvars[1].v_type != VAR_UNKNOWN)
3713 {
3714 if (argvars[2].v_type != VAR_UNKNOWN)
3715 {
3716 /* function(name, [args], dict) */
3717 arg_idx = 1;
3718 dict_idx = 2;
3719 }
3720 else if (argvars[1].v_type == VAR_DICT)
3721 /* function(name, dict) */
3722 dict_idx = 1;
3723 else
3724 /* function(name, [args]) */
3725 arg_idx = 1;
3726 if (dict_idx > 0)
3727 {
3728 if (argvars[dict_idx].v_type != VAR_DICT)
3729 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003730 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003731 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003732 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003733 }
3734 if (argvars[dict_idx].vval.v_dict == NULL)
3735 dict_idx = 0;
3736 }
3737 if (arg_idx > 0)
3738 {
3739 if (argvars[arg_idx].v_type != VAR_LIST)
3740 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003741 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003742 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003743 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003744 }
3745 list = argvars[arg_idx].vval.v_list;
3746 if (list == NULL || list->lv_len == 0)
3747 arg_idx = 0;
3748 }
3749 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003750 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003751 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003752 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003753
3754 /* result is a VAR_PARTIAL */
3755 if (pt == NULL)
3756 vim_free(name);
3757 else
3758 {
3759 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3760 {
3761 listitem_T *li;
3762 int i = 0;
3763 int arg_len = 0;
3764 int lv_len = 0;
3765
3766 if (arg_pt != NULL)
3767 arg_len = arg_pt->pt_argc;
3768 if (list != NULL)
3769 lv_len = list->lv_len;
3770 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003771 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003772 if (pt->pt_argv == NULL)
3773 {
3774 vim_free(pt);
3775 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003776 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003777 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003778 for (i = 0; i < arg_len; i++)
3779 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3780 if (lv_len > 0)
3781 for (li = list->lv_first; li != NULL;
3782 li = li->li_next)
3783 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003784 }
3785
3786 /* For "function(dict.func, [], dict)" and "func" is a partial
3787 * use "dict". That is backwards compatible. */
3788 if (dict_idx > 0)
3789 {
3790 /* The dict is bound explicitly, pt_auto is FALSE. */
3791 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3792 ++pt->pt_dict->dv_refcount;
3793 }
3794 else if (arg_pt != NULL)
3795 {
3796 /* If the dict was bound automatically the result is also
3797 * bound automatically. */
3798 pt->pt_dict = arg_pt->pt_dict;
3799 pt->pt_auto = arg_pt->pt_auto;
3800 if (pt->pt_dict != NULL)
3801 ++pt->pt_dict->dv_refcount;
3802 }
3803
3804 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003805 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3806 {
3807 pt->pt_func = arg_pt->pt_func;
3808 func_ptr_ref(pt->pt_func);
3809 vim_free(name);
3810 }
3811 else if (is_funcref)
3812 {
3813 pt->pt_func = find_func(trans_name);
3814 func_ptr_ref(pt->pt_func);
3815 vim_free(name);
3816 }
3817 else
3818 {
3819 pt->pt_name = name;
3820 func_ref(name);
3821 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003822 }
3823 rettv->v_type = VAR_PARTIAL;
3824 rettv->vval.v_partial = pt;
3825 }
3826 else
3827 {
3828 /* result is a VAR_FUNC */
3829 rettv->v_type = VAR_FUNC;
3830 rettv->vval.v_string = name;
3831 func_ref(name);
3832 }
3833 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003834theend:
3835 vim_free(trans_name);
3836}
3837
3838/*
3839 * "funcref()" function
3840 */
3841 static void
3842f_funcref(typval_T *argvars, typval_T *rettv)
3843{
3844 common_function(argvars, rettv, TRUE);
3845}
3846
3847/*
3848 * "function()" function
3849 */
3850 static void
3851f_function(typval_T *argvars, typval_T *rettv)
3852{
3853 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003854}
3855
3856/*
3857 * "garbagecollect()" function
3858 */
3859 static void
3860f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
3861{
3862 /* This is postponed until we are back at the toplevel, because we may be
3863 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
3864 want_garbage_collect = TRUE;
3865
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003866 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003867 garbage_collect_at_exit = TRUE;
3868}
3869
3870/*
3871 * "get()" function
3872 */
3873 static void
3874f_get(typval_T *argvars, typval_T *rettv)
3875{
3876 listitem_T *li;
3877 list_T *l;
3878 dictitem_T *di;
3879 dict_T *d;
3880 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003881 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003882
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003883 if (argvars[0].v_type == VAR_BLOB)
3884 {
3885 int error = FALSE;
3886 int idx = tv_get_number_chk(&argvars[1], &error);
3887
3888 if (!error)
3889 {
3890 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003891 if (idx < 0)
3892 idx = blob_len(argvars[0].vval.v_blob) + idx;
3893 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
3894 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003895 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003896 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003897 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01003898 tv = rettv;
3899 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003900 }
3901 }
3902 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003903 {
3904 if ((l = argvars[0].vval.v_list) != NULL)
3905 {
3906 int error = FALSE;
3907
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003908 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003909 if (!error && li != NULL)
3910 tv = &li->li_tv;
3911 }
3912 }
3913 else if (argvars[0].v_type == VAR_DICT)
3914 {
3915 if ((d = argvars[0].vval.v_dict) != NULL)
3916 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003917 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003918 if (di != NULL)
3919 tv = &di->di_tv;
3920 }
3921 }
3922 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
3923 {
3924 partial_T *pt;
3925 partial_T fref_pt;
3926
3927 if (argvars[0].v_type == VAR_PARTIAL)
3928 pt = argvars[0].vval.v_partial;
3929 else
3930 {
3931 vim_memset(&fref_pt, 0, sizeof(fref_pt));
3932 fref_pt.pt_name = argvars[0].vval.v_string;
3933 pt = &fref_pt;
3934 }
3935
3936 if (pt != NULL)
3937 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003938 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003939 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003940
3941 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
3942 {
3943 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003944 n = partial_name(pt);
3945 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003946 rettv->vval.v_string = NULL;
3947 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003948 {
3949 rettv->vval.v_string = vim_strsave(n);
3950 if (rettv->v_type == VAR_FUNC)
3951 func_ref(rettv->vval.v_string);
3952 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003953 }
3954 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003955 {
3956 what_is_dict = TRUE;
3957 if (pt->pt_dict != NULL)
3958 rettv_dict_set(rettv, pt->pt_dict);
3959 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003960 else if (STRCMP(what, "args") == 0)
3961 {
3962 rettv->v_type = VAR_LIST;
3963 if (rettv_list_alloc(rettv) == OK)
3964 {
3965 int i;
3966
3967 for (i = 0; i < pt->pt_argc; ++i)
3968 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
3969 }
3970 }
3971 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003972 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02003973
3974 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
3975 // third argument
3976 if (!what_is_dict)
3977 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003978 }
3979 }
3980 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01003981 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003982
3983 if (tv == NULL)
3984 {
3985 if (argvars[2].v_type != VAR_UNKNOWN)
3986 copy_tv(&argvars[2], rettv);
3987 }
3988 else
3989 copy_tv(tv, rettv);
3990}
3991
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003992/*
3993 * Returns buffer options, variables and other attributes in a dictionary.
3994 */
3995 static dict_T *
3996get_buffer_info(buf_T *buf)
3997{
3998 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02003999 tabpage_T *tp;
4000 win_T *wp;
4001 list_T *windows;
4002
4003 dict = dict_alloc();
4004 if (dict == NULL)
4005 return NULL;
4006
Bram Moolenaare0be1672018-07-08 16:50:37 +02004007 dict_add_number(dict, "bufnr", buf->b_fnum);
4008 dict_add_string(dict, "name", buf->b_ffname);
4009 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4010 : buflist_findlnum(buf));
4011 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4012 dict_add_number(dict, "listed", buf->b_p_bl);
4013 dict_add_number(dict, "changed", bufIsChanged(buf));
4014 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4015 dict_add_number(dict, "hidden",
4016 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004017
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004018 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004019 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004020
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004021 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004022 windows = list_alloc();
4023 if (windows != NULL)
4024 {
4025 FOR_ALL_TAB_WINDOWS(tp, wp)
4026 if (wp->w_buffer == buf)
4027 list_append_number(windows, (varnumber_T)wp->w_id);
4028 dict_add_list(dict, "windows", windows);
4029 }
4030
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004031#ifdef FEAT_TEXT_PROP
4032 // List of popup windows displaying this buffer
4033 windows = list_alloc();
4034 if (windows != NULL)
4035 {
4036 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4037 if (wp->w_buffer == buf)
4038 list_append_number(windows, (varnumber_T)wp->w_id);
4039 FOR_ALL_TABPAGES(tp)
4040 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4041 if (wp->w_buffer == buf)
4042 list_append_number(windows, (varnumber_T)wp->w_id);
4043
4044 dict_add_list(dict, "popups", windows);
4045 }
4046#endif
4047
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004048#ifdef FEAT_SIGNS
4049 if (buf->b_signlist != NULL)
4050 {
4051 /* List of signs placed in this buffer */
4052 list_T *signs = list_alloc();
4053 if (signs != NULL)
4054 {
4055 get_buffer_signs(buf, signs);
4056 dict_add_list(dict, "signs", signs);
4057 }
4058 }
4059#endif
4060
4061 return dict;
4062}
4063
4064/*
4065 * "getbufinfo()" function
4066 */
4067 static void
4068f_getbufinfo(typval_T *argvars, typval_T *rettv)
4069{
4070 buf_T *buf = NULL;
4071 buf_T *argbuf = NULL;
4072 dict_T *d;
4073 int filtered = FALSE;
4074 int sel_buflisted = FALSE;
4075 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004076 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004077
4078 if (rettv_list_alloc(rettv) != OK)
4079 return;
4080
4081 /* List of all the buffers or selected buffers */
4082 if (argvars[0].v_type == VAR_DICT)
4083 {
4084 dict_T *sel_d = argvars[0].vval.v_dict;
4085
4086 if (sel_d != NULL)
4087 {
4088 dictitem_T *di;
4089
4090 filtered = TRUE;
4091
4092 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004093 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004094 sel_buflisted = TRUE;
4095
4096 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004097 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004098 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004099
4100 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004101 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004102 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004103 }
4104 }
4105 else if (argvars[0].v_type != VAR_UNKNOWN)
4106 {
4107 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004108 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004109 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004110 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004111 --emsg_off;
4112 if (argbuf == NULL)
4113 return;
4114 }
4115
4116 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004117 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004118 {
4119 if (argbuf != NULL && argbuf != buf)
4120 continue;
4121 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004122 || (sel_buflisted && !buf->b_p_bl)
4123 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004124 continue;
4125
4126 d = get_buffer_info(buf);
4127 if (d != NULL)
4128 list_append_dict(rettv->vval.v_list, d);
4129 if (argbuf != NULL)
4130 return;
4131 }
4132}
4133
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004134/*
4135 * Get line or list of lines from buffer "buf" into "rettv".
4136 * Return a range (from start to end) of lines in rettv from the specified
4137 * buffer.
4138 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4139 */
4140 static void
4141get_buffer_lines(
4142 buf_T *buf,
4143 linenr_T start,
4144 linenr_T end,
4145 int retlist,
4146 typval_T *rettv)
4147{
4148 char_u *p;
4149
4150 rettv->v_type = VAR_STRING;
4151 rettv->vval.v_string = NULL;
4152 if (retlist && rettv_list_alloc(rettv) == FAIL)
4153 return;
4154
4155 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4156 return;
4157
4158 if (!retlist)
4159 {
4160 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4161 p = ml_get_buf(buf, start, FALSE);
4162 else
4163 p = (char_u *)"";
4164 rettv->vval.v_string = vim_strsave(p);
4165 }
4166 else
4167 {
4168 if (end < start)
4169 return;
4170
4171 if (start < 1)
4172 start = 1;
4173 if (end > buf->b_ml.ml_line_count)
4174 end = buf->b_ml.ml_line_count;
4175 while (start <= end)
4176 if (list_append_string(rettv->vval.v_list,
4177 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4178 break;
4179 }
4180}
4181
4182/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004183 * "getbufline()" function
4184 */
4185 static void
4186f_getbufline(typval_T *argvars, typval_T *rettv)
4187{
4188 linenr_T lnum;
4189 linenr_T end;
4190 buf_T *buf;
4191
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004192 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004193 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004194 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004195 --emsg_off;
4196
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004197 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004198 if (argvars[2].v_type == VAR_UNKNOWN)
4199 end = lnum;
4200 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004201 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004202
4203 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4204}
4205
4206/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004207 * "getchangelist()" function
4208 */
4209 static void
4210f_getchangelist(typval_T *argvars, typval_T *rettv)
4211{
4212#ifdef FEAT_JUMPLIST
4213 buf_T *buf;
4214 int i;
4215 list_T *l;
4216 dict_T *d;
4217#endif
4218
4219 if (rettv_list_alloc(rettv) != OK)
4220 return;
4221
4222#ifdef FEAT_JUMPLIST
Bram Moolenaar4c313b12019-08-24 22:58:31 +02004223 if (argvars[0].v_type == VAR_UNKNOWN)
4224 buf = curbuf;
4225 else
4226 {
4227 (void)tv_get_number(&argvars[0]); // issue errmsg if type error
4228 ++emsg_off;
4229 buf = tv_get_buf(&argvars[0], FALSE);
4230 --emsg_off;
4231 }
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004232 if (buf == NULL)
4233 return;
4234
4235 l = list_alloc();
4236 if (l == NULL)
4237 return;
4238
4239 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4240 return;
4241 /*
4242 * The current window change list index tracks only the position in the
4243 * current buffer change list. For other buffers, use the change list
4244 * length as the current index.
4245 */
4246 list_append_number(rettv->vval.v_list,
4247 (varnumber_T)((buf == curwin->w_buffer)
4248 ? curwin->w_changelistidx : buf->b_changelistlen));
4249
4250 for (i = 0; i < buf->b_changelistlen; ++i)
4251 {
4252 if (buf->b_changelist[i].lnum == 0)
4253 continue;
4254 if ((d = dict_alloc()) == NULL)
4255 return;
4256 if (list_append_dict(l, d) == FAIL)
4257 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004258 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4259 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004260 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004261 }
4262#endif
4263}
4264/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004265 * "getchar()" function
4266 */
4267 static void
4268f_getchar(typval_T *argvars, typval_T *rettv)
4269{
4270 varnumber_T n;
4271 int error = FALSE;
4272
Bram Moolenaar84d93902018-09-11 20:10:20 +02004273#ifdef MESSAGE_QUEUE
4274 // vpeekc() used to check for messages, but that caused problems, invoking
4275 // a callback where it was not expected. Some plugins use getchar(1) in a
4276 // loop to await a message, therefore make sure we check for messages here.
4277 parse_queued_messages();
4278#endif
4279
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004280 /* Position the cursor. Needed after a message that ends in a space. */
4281 windgoto(msg_row, msg_col);
4282
4283 ++no_mapping;
4284 ++allow_keys;
4285 for (;;)
4286 {
4287 if (argvars[0].v_type == VAR_UNKNOWN)
4288 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004289 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004290 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004291 /* getchar(1): only check if char avail */
4292 n = vpeekc_any();
4293 else if (error || vpeekc_any() == NUL)
4294 /* illegal argument or getchar(0) and no char avail: return zero */
4295 n = 0;
4296 else
4297 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004298 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004299
4300 if (n == K_IGNORE)
4301 continue;
4302 break;
4303 }
4304 --no_mapping;
4305 --allow_keys;
4306
4307 set_vim_var_nr(VV_MOUSE_WIN, 0);
4308 set_vim_var_nr(VV_MOUSE_WINID, 0);
4309 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4310 set_vim_var_nr(VV_MOUSE_COL, 0);
4311
4312 rettv->vval.v_number = n;
4313 if (IS_SPECIAL(n) || mod_mask != 0)
4314 {
4315 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4316 int i = 0;
4317
4318 /* Turn a special key into three bytes, plus modifier. */
4319 if (mod_mask != 0)
4320 {
4321 temp[i++] = K_SPECIAL;
4322 temp[i++] = KS_MODIFIER;
4323 temp[i++] = mod_mask;
4324 }
4325 if (IS_SPECIAL(n))
4326 {
4327 temp[i++] = K_SPECIAL;
4328 temp[i++] = K_SECOND(n);
4329 temp[i++] = K_THIRD(n);
4330 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004331 else if (has_mbyte)
4332 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004333 else
4334 temp[i++] = n;
4335 temp[i++] = NUL;
4336 rettv->v_type = VAR_STRING;
4337 rettv->vval.v_string = vim_strsave(temp);
4338
4339#ifdef FEAT_MOUSE
4340 if (is_mouse_key(n))
4341 {
4342 int row = mouse_row;
4343 int col = mouse_col;
4344 win_T *win;
4345 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004346 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004347 int winnr = 1;
4348
4349 if (row >= 0 && col >= 0)
4350 {
4351 /* Find the window at the mouse coordinates and compute the
4352 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004353 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004354 if (win == NULL)
4355 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004356 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004357# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004358 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004359 winnr = 0;
4360 else
4361# endif
4362 for (wp = firstwin; wp != win && wp != NULL;
4363 wp = wp->w_next)
4364 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004365 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4366 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4367 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4368 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4369 }
4370 }
4371#endif
4372 }
4373}
4374
4375/*
4376 * "getcharmod()" function
4377 */
4378 static void
4379f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4380{
4381 rettv->vval.v_number = mod_mask;
4382}
4383
4384/*
4385 * "getcharsearch()" function
4386 */
4387 static void
4388f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4389{
4390 if (rettv_dict_alloc(rettv) != FAIL)
4391 {
4392 dict_T *dict = rettv->vval.v_dict;
4393
Bram Moolenaare0be1672018-07-08 16:50:37 +02004394 dict_add_string(dict, "char", last_csearch());
4395 dict_add_number(dict, "forward", last_csearch_forward());
4396 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004397 }
4398}
4399
4400/*
4401 * "getcmdline()" function
4402 */
4403 static void
4404f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4405{
4406 rettv->v_type = VAR_STRING;
4407 rettv->vval.v_string = get_cmdline_str();
4408}
4409
4410/*
4411 * "getcmdpos()" function
4412 */
4413 static void
4414f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4415{
4416 rettv->vval.v_number = get_cmdline_pos() + 1;
4417}
4418
4419/*
4420 * "getcmdtype()" function
4421 */
4422 static void
4423f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4424{
4425 rettv->v_type = VAR_STRING;
4426 rettv->vval.v_string = alloc(2);
4427 if (rettv->vval.v_string != NULL)
4428 {
4429 rettv->vval.v_string[0] = get_cmdline_type();
4430 rettv->vval.v_string[1] = NUL;
4431 }
4432}
4433
4434/*
4435 * "getcmdwintype()" function
4436 */
4437 static void
4438f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4439{
4440 rettv->v_type = VAR_STRING;
4441 rettv->vval.v_string = NULL;
4442#ifdef FEAT_CMDWIN
4443 rettv->vval.v_string = alloc(2);
4444 if (rettv->vval.v_string != NULL)
4445 {
4446 rettv->vval.v_string[0] = cmdwin_type;
4447 rettv->vval.v_string[1] = NUL;
4448 }
4449#endif
4450}
4451
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004452/*
4453 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004454 *
4455 * Return the current working directory of a window in a tab page.
4456 * First optional argument 'winnr' is the window number or -1 and the second
4457 * optional argument 'tabnr' is the tab page number.
4458 *
4459 * If no arguments are supplied, then return the directory of the current
4460 * window.
4461 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4462 * the specified window.
4463 * If 'winnr' is 0 then return the directory of the current window.
4464 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4465 * directory of the specified tab page. Otherwise return the directory of the
4466 * specified window in the specified tab page.
4467 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004468 */
4469 static void
4470f_getcwd(typval_T *argvars, typval_T *rettv)
4471{
4472 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004473 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004474 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004475 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004476
4477 rettv->v_type = VAR_STRING;
4478 rettv->vval.v_string = NULL;
4479
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004480 if (argvars[0].v_type == VAR_NUMBER
4481 && argvars[0].vval.v_number == -1
4482 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004483 global = TRUE;
4484 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004485 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004486
4487 if (wp != NULL && wp->w_localdir != NULL)
4488 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004489 else if (tp != NULL && tp->tp_localdir != NULL)
4490 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4491 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004492 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004493 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004494 rettv->vval.v_string = vim_strsave(globaldir);
4495 else
4496 {
4497 cwd = alloc(MAXPATHL);
4498 if (cwd != NULL)
4499 {
4500 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4501 rettv->vval.v_string = vim_strsave(cwd);
4502 vim_free(cwd);
4503 }
4504 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004505 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004506#ifdef BACKSLASH_IN_FILENAME
4507 if (rettv->vval.v_string != NULL)
4508 slash_adjust(rettv->vval.v_string);
4509#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004510}
4511
4512/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004513 * "getenv()" function
4514 */
4515 static void
4516f_getenv(typval_T *argvars, typval_T *rettv)
4517{
4518 int mustfree = FALSE;
4519 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4520
4521 if (p == NULL)
4522 {
4523 rettv->v_type = VAR_SPECIAL;
4524 rettv->vval.v_number = VVAL_NULL;
4525 return;
4526 }
4527 if (!mustfree)
4528 p = vim_strsave(p);
4529 rettv->vval.v_string = p;
4530 rettv->v_type = VAR_STRING;
4531}
4532
4533/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004534 * "getfontname()" function
4535 */
4536 static void
4537f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4538{
4539 rettv->v_type = VAR_STRING;
4540 rettv->vval.v_string = NULL;
4541#ifdef FEAT_GUI
4542 if (gui.in_use)
4543 {
4544 GuiFont font;
4545 char_u *name = NULL;
4546
4547 if (argvars[0].v_type == VAR_UNKNOWN)
4548 {
4549 /* Get the "Normal" font. Either the name saved by
4550 * hl_set_font_name() or from the font ID. */
4551 font = gui.norm_font;
4552 name = hl_get_font_name();
4553 }
4554 else
4555 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004556 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004557 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4558 return;
4559 font = gui_mch_get_font(name, FALSE);
4560 if (font == NOFONT)
4561 return; /* Invalid font name, return empty string. */
4562 }
4563 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4564 if (argvars[0].v_type != VAR_UNKNOWN)
4565 gui_mch_free_font(font);
4566 }
4567#endif
4568}
4569
4570/*
4571 * "getfperm({fname})" function
4572 */
4573 static void
4574f_getfperm(typval_T *argvars, typval_T *rettv)
4575{
4576 char_u *fname;
4577 stat_T st;
4578 char_u *perm = NULL;
4579 char_u flags[] = "rwx";
4580 int i;
4581
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004582 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004583
4584 rettv->v_type = VAR_STRING;
4585 if (mch_stat((char *)fname, &st) >= 0)
4586 {
4587 perm = vim_strsave((char_u *)"---------");
4588 if (perm != NULL)
4589 {
4590 for (i = 0; i < 9; i++)
4591 {
4592 if (st.st_mode & (1 << (8 - i)))
4593 perm[i] = flags[i % 3];
4594 }
4595 }
4596 }
4597 rettv->vval.v_string = perm;
4598}
4599
4600/*
4601 * "getfsize({fname})" function
4602 */
4603 static void
4604f_getfsize(typval_T *argvars, typval_T *rettv)
4605{
4606 char_u *fname;
4607 stat_T st;
4608
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004609 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004610
4611 rettv->v_type = VAR_NUMBER;
4612
4613 if (mch_stat((char *)fname, &st) >= 0)
4614 {
4615 if (mch_isdir(fname))
4616 rettv->vval.v_number = 0;
4617 else
4618 {
4619 rettv->vval.v_number = (varnumber_T)st.st_size;
4620
4621 /* non-perfect check for overflow */
4622 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4623 rettv->vval.v_number = -2;
4624 }
4625 }
4626 else
4627 rettv->vval.v_number = -1;
4628}
4629
4630/*
4631 * "getftime({fname})" function
4632 */
4633 static void
4634f_getftime(typval_T *argvars, typval_T *rettv)
4635{
4636 char_u *fname;
4637 stat_T st;
4638
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004639 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004640
4641 if (mch_stat((char *)fname, &st) >= 0)
4642 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4643 else
4644 rettv->vval.v_number = -1;
4645}
4646
4647/*
4648 * "getftype({fname})" function
4649 */
4650 static void
4651f_getftype(typval_T *argvars, typval_T *rettv)
4652{
4653 char_u *fname;
4654 stat_T st;
4655 char_u *type = NULL;
4656 char *t;
4657
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004658 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004659
4660 rettv->v_type = VAR_STRING;
4661 if (mch_lstat((char *)fname, &st) >= 0)
4662 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004663 if (S_ISREG(st.st_mode))
4664 t = "file";
4665 else if (S_ISDIR(st.st_mode))
4666 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004667 else if (S_ISLNK(st.st_mode))
4668 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004669 else if (S_ISBLK(st.st_mode))
4670 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004671 else if (S_ISCHR(st.st_mode))
4672 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004673 else if (S_ISFIFO(st.st_mode))
4674 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004675 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02004676 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004677 else
4678 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004679 type = vim_strsave((char_u *)t);
4680 }
4681 rettv->vval.v_string = type;
4682}
4683
4684/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004685 * "getjumplist()" function
4686 */
4687 static void
4688f_getjumplist(typval_T *argvars, typval_T *rettv)
4689{
4690#ifdef FEAT_JUMPLIST
4691 win_T *wp;
4692 int i;
4693 list_T *l;
4694 dict_T *d;
4695#endif
4696
4697 if (rettv_list_alloc(rettv) != OK)
4698 return;
4699
4700#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004701 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004702 if (wp == NULL)
4703 return;
4704
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01004705 cleanup_jumplist(wp, TRUE);
4706
Bram Moolenaar4f505882018-02-10 21:06:32 +01004707 l = list_alloc();
4708 if (l == NULL)
4709 return;
4710
4711 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4712 return;
4713 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4714
4715 for (i = 0; i < wp->w_jumplistlen; ++i)
4716 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004717 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4718 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004719 if ((d = dict_alloc()) == NULL)
4720 return;
4721 if (list_append_dict(l, d) == FAIL)
4722 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004723 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4724 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004725 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004726 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004727 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02004728 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004729 }
4730#endif
4731}
4732
4733/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 * "getline(lnum, [end])" function
4735 */
4736 static void
4737f_getline(typval_T *argvars, typval_T *rettv)
4738{
4739 linenr_T lnum;
4740 linenr_T end;
4741 int retlist;
4742
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004743 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004744 if (argvars[1].v_type == VAR_UNKNOWN)
4745 {
4746 end = 0;
4747 retlist = FALSE;
4748 }
4749 else
4750 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004751 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004752 retlist = TRUE;
4753 }
4754
4755 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4756}
4757
4758/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004759 * "getpid()" function
4760 */
4761 static void
4762f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
4763{
4764 rettv->vval.v_number = mch_get_pid();
4765}
4766
4767 static void
4768getpos_both(
4769 typval_T *argvars,
4770 typval_T *rettv,
4771 int getcurpos)
4772{
4773 pos_T *fp;
4774 list_T *l;
4775 int fnum = -1;
4776
4777 if (rettv_list_alloc(rettv) == OK)
4778 {
4779 l = rettv->vval.v_list;
4780 if (getcurpos)
4781 fp = &curwin->w_cursor;
4782 else
4783 fp = var2fpos(&argvars[0], TRUE, &fnum);
4784 if (fnum != -1)
4785 list_append_number(l, (varnumber_T)fnum);
4786 else
4787 list_append_number(l, (varnumber_T)0);
4788 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
4789 : (varnumber_T)0);
4790 list_append_number(l, (fp != NULL)
4791 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
4792 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01004793 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004794 (varnumber_T)0);
4795 if (getcurpos)
4796 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01004797 int save_set_curswant = curwin->w_set_curswant;
4798 colnr_T save_curswant = curwin->w_curswant;
4799 colnr_T save_virtcol = curwin->w_virtcol;
4800
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004801 update_curswant();
4802 list_append_number(l, curwin->w_curswant == MAXCOL ?
4803 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01004804
4805 // Do not change "curswant", as it is unexpected that a get
4806 // function has a side effect.
4807 if (save_set_curswant)
4808 {
4809 curwin->w_set_curswant = save_set_curswant;
4810 curwin->w_curswant = save_curswant;
4811 curwin->w_virtcol = save_virtcol;
4812 curwin->w_valid &= ~VALID_VIRTCOL;
4813 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004814 }
4815 }
4816 else
4817 rettv->vval.v_number = FALSE;
4818}
4819
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004820/*
4821 * "getcurpos()" function
4822 */
4823 static void
4824f_getcurpos(typval_T *argvars, typval_T *rettv)
4825{
4826 getpos_both(argvars, rettv, TRUE);
4827}
4828
4829/*
4830 * "getpos(string)" function
4831 */
4832 static void
4833f_getpos(typval_T *argvars, typval_T *rettv)
4834{
4835 getpos_both(argvars, rettv, FALSE);
4836}
4837
4838/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004839 * "getreg()" function
4840 */
4841 static void
4842f_getreg(typval_T *argvars, typval_T *rettv)
4843{
4844 char_u *strregname;
4845 int regname;
4846 int arg2 = FALSE;
4847 int return_list = FALSE;
4848 int error = FALSE;
4849
4850 if (argvars[0].v_type != VAR_UNKNOWN)
4851 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004852 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004853 error = strregname == NULL;
4854 if (argvars[1].v_type != VAR_UNKNOWN)
4855 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004856 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004857 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004858 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004859 }
4860 }
4861 else
4862 strregname = get_vim_var_str(VV_REG);
4863
4864 if (error)
4865 return;
4866
4867 regname = (strregname == NULL ? '"' : *strregname);
4868 if (regname == 0)
4869 regname = '"';
4870
4871 if (return_list)
4872 {
4873 rettv->v_type = VAR_LIST;
4874 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
4875 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
4876 if (rettv->vval.v_list == NULL)
4877 (void)rettv_list_alloc(rettv);
4878 else
4879 ++rettv->vval.v_list->lv_refcount;
4880 }
4881 else
4882 {
4883 rettv->v_type = VAR_STRING;
4884 rettv->vval.v_string = get_reg_contents(regname,
4885 arg2 ? GREG_EXPR_SRC : 0);
4886 }
4887}
4888
4889/*
4890 * "getregtype()" function
4891 */
4892 static void
4893f_getregtype(typval_T *argvars, typval_T *rettv)
4894{
4895 char_u *strregname;
4896 int regname;
4897 char_u buf[NUMBUFLEN + 2];
4898 long reglen = 0;
4899
4900 if (argvars[0].v_type != VAR_UNKNOWN)
4901 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004902 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004903 if (strregname == NULL) /* type error; errmsg already given */
4904 {
4905 rettv->v_type = VAR_STRING;
4906 rettv->vval.v_string = NULL;
4907 return;
4908 }
4909 }
4910 else
4911 /* Default to v:register */
4912 strregname = get_vim_var_str(VV_REG);
4913
4914 regname = (strregname == NULL ? '"' : *strregname);
4915 if (regname == 0)
4916 regname = '"';
4917
4918 buf[0] = NUL;
4919 buf[1] = NUL;
4920 switch (get_reg_type(regname, &reglen))
4921 {
4922 case MLINE: buf[0] = 'V'; break;
4923 case MCHAR: buf[0] = 'v'; break;
4924 case MBLOCK:
4925 buf[0] = Ctrl_V;
4926 sprintf((char *)buf + 1, "%ld", reglen + 1);
4927 break;
4928 }
4929 rettv->v_type = VAR_STRING;
4930 rettv->vval.v_string = vim_strsave(buf);
4931}
4932
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004933/*
4934 * Returns information (variables, options, etc.) about a tab page
4935 * as a dictionary.
4936 */
4937 static dict_T *
4938get_tabpage_info(tabpage_T *tp, int tp_idx)
4939{
4940 win_T *wp;
4941 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004942 list_T *l;
4943
4944 dict = dict_alloc();
4945 if (dict == NULL)
4946 return NULL;
4947
Bram Moolenaare0be1672018-07-08 16:50:37 +02004948 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004949
4950 l = list_alloc();
4951 if (l != NULL)
4952 {
4953 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004954 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004955 list_append_number(l, (varnumber_T)wp->w_id);
4956 dict_add_list(dict, "windows", l);
4957 }
4958
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004959 /* Make a reference to tabpage variables */
4960 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004961
4962 return dict;
4963}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004964
4965/*
4966 * "gettabinfo()" function
4967 */
4968 static void
4969f_gettabinfo(typval_T *argvars, typval_T *rettv)
4970{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004971 tabpage_T *tp, *tparg = NULL;
4972 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02004973 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004974
4975 if (rettv_list_alloc(rettv) != OK)
4976 return;
4977
4978 if (argvars[0].v_type != VAR_UNKNOWN)
4979 {
4980 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004981 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004982 if (tparg == NULL)
4983 return;
4984 }
4985
4986 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004987 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004988 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02004989 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004990 if (tparg != NULL && tp != tparg)
4991 continue;
4992 d = get_tabpage_info(tp, tpnr);
4993 if (d != NULL)
4994 list_append_dict(rettv->vval.v_list, d);
4995 if (tparg != NULL)
4996 return;
4997 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004998}
4999
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005000/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005001 * "gettagstack()" function
5002 */
5003 static void
5004f_gettagstack(typval_T *argvars, typval_T *rettv)
5005{
5006 win_T *wp = curwin; // default is current window
5007
5008 if (rettv_dict_alloc(rettv) != OK)
5009 return;
5010
5011 if (argvars[0].v_type != VAR_UNKNOWN)
5012 {
5013 wp = find_win_by_nr_or_id(&argvars[0]);
5014 if (wp == NULL)
5015 return;
5016 }
5017
5018 get_tagstack(wp, rettv->vval.v_dict);
5019}
5020
5021/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005022 * Returns information about a window as a dictionary.
5023 */
5024 static dict_T *
5025get_win_info(win_T *wp, short tpnr, short winnr)
5026{
5027 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005028
5029 dict = dict_alloc();
5030 if (dict == NULL)
5031 return NULL;
5032
Bram Moolenaare0be1672018-07-08 16:50:37 +02005033 dict_add_number(dict, "tabnr", tpnr);
5034 dict_add_number(dict, "winnr", winnr);
5035 dict_add_number(dict, "winid", wp->w_id);
5036 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005037 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005038 dict_add_number(dict, "topline", wp->w_topline);
5039 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005040#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005041 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005042#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005043 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005044 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005045 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005046
Bram Moolenaar69905d12017-08-13 18:14:47 +02005047#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005048 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005049#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005050#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005051 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5052 dict_add_number(dict, "loclist",
5053 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005054#endif
5055
Bram Moolenaar30567352016-08-27 21:25:44 +02005056 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005057 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005058
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005059 return dict;
5060}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005061
5062/*
5063 * "getwininfo()" function
5064 */
5065 static void
5066f_getwininfo(typval_T *argvars, typval_T *rettv)
5067{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005068 tabpage_T *tp;
5069 win_T *wp = NULL, *wparg = NULL;
5070 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005071 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005072
5073 if (rettv_list_alloc(rettv) != OK)
5074 return;
5075
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005076 if (argvars[0].v_type != VAR_UNKNOWN)
5077 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005078 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005079 if (wparg == NULL)
5080 return;
5081 }
5082
5083 /* Collect information about either all the windows across all the tab
5084 * pages or one particular window.
5085 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005086 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005087 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005088 tabnr++;
5089 winnr = 0;
5090 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005091 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005092 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005093 if (wparg != NULL && wp != wparg)
5094 continue;
5095 d = get_win_info(wp, tabnr, winnr);
5096 if (d != NULL)
5097 list_append_dict(rettv->vval.v_list, d);
5098 if (wparg != NULL)
5099 /* found information about a specific window */
5100 return;
5101 }
5102 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005103}
5104
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005106 * "win_execute()" function
5107 */
5108 static void
5109f_win_execute(typval_T *argvars, typval_T *rettv)
5110{
5111 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005112 tabpage_T *tp;
5113 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005114 win_T *save_curwin;
5115 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005116
Bram Moolenaar820680b2019-08-09 14:56:22 +02005117 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005118 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005119 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005120 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005121 check_cursor();
5122 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005123 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005124 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005125 }
5126}
5127
5128/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005129 * "win_findbuf()" function
5130 */
5131 static void
5132f_win_findbuf(typval_T *argvars, typval_T *rettv)
5133{
5134 if (rettv_list_alloc(rettv) != FAIL)
5135 win_findbuf(argvars, rettv->vval.v_list);
5136}
5137
5138/*
5139 * "win_getid()" function
5140 */
5141 static void
5142f_win_getid(typval_T *argvars, typval_T *rettv)
5143{
5144 rettv->vval.v_number = win_getid(argvars);
5145}
5146
5147/*
5148 * "win_gotoid()" function
5149 */
5150 static void
5151f_win_gotoid(typval_T *argvars, typval_T *rettv)
5152{
5153 rettv->vval.v_number = win_gotoid(argvars);
5154}
5155
5156/*
5157 * "win_id2tabwin()" function
5158 */
5159 static void
5160f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5161{
5162 if (rettv_list_alloc(rettv) != FAIL)
5163 win_id2tabwin(argvars, rettv->vval.v_list);
5164}
5165
5166/*
5167 * "win_id2win()" function
5168 */
5169 static void
5170f_win_id2win(typval_T *argvars, typval_T *rettv)
5171{
5172 rettv->vval.v_number = win_id2win(argvars);
5173}
5174
5175/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005176 * "win_screenpos()" function
5177 */
5178 static void
5179f_win_screenpos(typval_T *argvars, typval_T *rettv)
5180{
5181 win_T *wp;
5182
5183 if (rettv_list_alloc(rettv) == FAIL)
5184 return;
5185
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005186 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005187 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5188 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5189}
5190
5191/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005192 * "getwinpos({timeout})" function
5193 */
5194 static void
5195f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5196{
5197 int x = -1;
5198 int y = -1;
5199
5200 if (rettv_list_alloc(rettv) == FAIL)
5201 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005202#if defined(FEAT_GUI) \
5203 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5204 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005205 {
5206 varnumber_T timeout = 100;
5207
5208 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005209 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005210
5211 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005212 }
5213#endif
5214 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5215 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5216}
5217
5218
5219/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005220 * "getwinposx()" function
5221 */
5222 static void
5223f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5224{
5225 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005226#if defined(FEAT_GUI) \
5227 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5228 || defined(MSWIN)
5229
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005230 {
5231 int x, y;
5232
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005233 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005234 rettv->vval.v_number = x;
5235 }
5236#endif
5237}
5238
5239/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005240 * "getwinposy()" function
5241 */
5242 static void
5243f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5244{
5245 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005246#if defined(FEAT_GUI) \
5247 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5248 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005249 {
5250 int x, y;
5251
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005252 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005253 rettv->vval.v_number = y;
5254 }
5255#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005256}
5257
5258/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005259 * "glob()" function
5260 */
5261 static void
5262f_glob(typval_T *argvars, typval_T *rettv)
5263{
5264 int options = WILD_SILENT|WILD_USE_NL;
5265 expand_T xpc;
5266 int error = FALSE;
5267
5268 /* When the optional second argument is non-zero, don't remove matches
5269 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5270 rettv->v_type = VAR_STRING;
5271 if (argvars[1].v_type != VAR_UNKNOWN)
5272 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005273 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005274 options |= WILD_KEEP_ALL;
5275 if (argvars[2].v_type != VAR_UNKNOWN)
5276 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005277 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005278 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005279 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005280 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005281 options |= WILD_ALLLINKS;
5282 }
5283 }
5284 if (!error)
5285 {
5286 ExpandInit(&xpc);
5287 xpc.xp_context = EXPAND_FILES;
5288 if (p_wic)
5289 options += WILD_ICASE;
5290 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005291 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 NULL, options, WILD_ALL);
5293 else if (rettv_list_alloc(rettv) != FAIL)
5294 {
5295 int i;
5296
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005297 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 NULL, options, WILD_ALL_KEEP);
5299 for (i = 0; i < xpc.xp_numfiles; i++)
5300 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5301
5302 ExpandCleanup(&xpc);
5303 }
5304 }
5305 else
5306 rettv->vval.v_string = NULL;
5307}
5308
5309/*
5310 * "globpath()" function
5311 */
5312 static void
5313f_globpath(typval_T *argvars, typval_T *rettv)
5314{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005315 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005316 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005317 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005318 int error = FALSE;
5319 garray_T ga;
5320 int i;
5321
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005322 // When the optional second argument is non-zero, don't remove matches
5323 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005324 rettv->v_type = VAR_STRING;
5325 if (argvars[2].v_type != VAR_UNKNOWN)
5326 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005327 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005328 flags |= WILD_KEEP_ALL;
5329 if (argvars[3].v_type != VAR_UNKNOWN)
5330 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005331 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005332 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005333 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005334 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005335 flags |= WILD_ALLLINKS;
5336 }
5337 }
5338 if (file != NULL && !error)
5339 {
5340 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005341 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005342 if (rettv->v_type == VAR_STRING)
5343 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5344 else if (rettv_list_alloc(rettv) != FAIL)
5345 for (i = 0; i < ga.ga_len; ++i)
5346 list_append_string(rettv->vval.v_list,
5347 ((char_u **)(ga.ga_data))[i], -1);
5348 ga_clear_strings(&ga);
5349 }
5350 else
5351 rettv->vval.v_string = NULL;
5352}
5353
5354/*
5355 * "glob2regpat()" function
5356 */
5357 static void
5358f_glob2regpat(typval_T *argvars, typval_T *rettv)
5359{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005360 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005361
5362 rettv->v_type = VAR_STRING;
5363 rettv->vval.v_string = (pat == NULL)
5364 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5365}
5366
5367/* for VIM_VERSION_ defines */
5368#include "version.h"
5369
5370/*
5371 * "has()" function
5372 */
5373 static void
5374f_has(typval_T *argvars, typval_T *rettv)
5375{
5376 int i;
5377 char_u *name;
5378 int n = FALSE;
5379 static char *(has_list[]) =
5380 {
5381#ifdef AMIGA
5382 "amiga",
5383# ifdef FEAT_ARP
5384 "arp",
5385# endif
5386#endif
5387#ifdef __BEOS__
5388 "beos",
5389#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005390#if defined(BSD) && !defined(MACOS_X)
5391 "bsd",
5392#endif
5393#ifdef hpux
5394 "hpux",
5395#endif
5396#ifdef __linux__
5397 "linux",
5398#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005399#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005400 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5401 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005402# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005403 "macunix", /* Mac OS X, with the darwin feature */
5404 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005405# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005406#endif
5407#ifdef __QNX__
5408 "qnx",
5409#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005410#ifdef SUN_SYSTEM
5411 "sun",
5412#else
5413 "moon",
5414#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005415#ifdef UNIX
5416 "unix",
5417#endif
5418#ifdef VMS
5419 "vms",
5420#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005421#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005422 "win32",
5423#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005424#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005425 "win32unix",
5426#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005427#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005428 "win64",
5429#endif
5430#ifdef EBCDIC
5431 "ebcdic",
5432#endif
5433#ifndef CASE_INSENSITIVE_FILENAME
5434 "fname_case",
5435#endif
5436#ifdef HAVE_ACL
5437 "acl",
5438#endif
5439#ifdef FEAT_ARABIC
5440 "arabic",
5441#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005442 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005443#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005444 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005445#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005446#ifdef FEAT_AUTOSERVERNAME
5447 "autoservername",
5448#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005449#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005450 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01005451# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005452 "balloon_multiline",
5453# endif
5454#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005455#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005456 "balloon_eval_term",
5457#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005458#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5459 "builtin_terms",
5460# ifdef ALL_BUILTIN_TCAPS
5461 "all_builtin_terms",
5462# endif
5463#endif
5464#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01005465 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005466 || defined(FEAT_GUI_MOTIF))
5467 "browsefilter",
5468#endif
5469#ifdef FEAT_BYTEOFF
5470 "byte_offset",
5471#endif
5472#ifdef FEAT_JOB_CHANNEL
5473 "channel",
5474#endif
5475#ifdef FEAT_CINDENT
5476 "cindent",
5477#endif
5478#ifdef FEAT_CLIENTSERVER
5479 "clientserver",
5480#endif
5481#ifdef FEAT_CLIPBOARD
5482 "clipboard",
5483#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005484 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005485 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005486#ifdef FEAT_COMMENTS
5487 "comments",
5488#endif
5489#ifdef FEAT_CONCEAL
5490 "conceal",
5491#endif
5492#ifdef FEAT_CRYPT
5493 "cryptv",
5494 "crypt-blowfish",
5495 "crypt-blowfish2",
5496#endif
5497#ifdef FEAT_CSCOPE
5498 "cscope",
5499#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005500 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005501#ifdef CURSOR_SHAPE
5502 "cursorshape",
5503#endif
5504#ifdef DEBUG
5505 "debug",
5506#endif
5507#ifdef FEAT_CON_DIALOG
5508 "dialog_con",
5509#endif
5510#ifdef FEAT_GUI_DIALOG
5511 "dialog_gui",
5512#endif
5513#ifdef FEAT_DIFF
5514 "diff",
5515#endif
5516#ifdef FEAT_DIGRAPHS
5517 "digraphs",
5518#endif
5519#ifdef FEAT_DIRECTX
5520 "directx",
5521#endif
5522#ifdef FEAT_DND
5523 "dnd",
5524#endif
5525#ifdef FEAT_EMACS_TAGS
5526 "emacs_tags",
5527#endif
5528 "eval", /* always present, of course! */
5529 "ex_extra", /* graduated feature */
5530#ifdef FEAT_SEARCH_EXTRA
5531 "extra_search",
5532#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005533#ifdef FEAT_SEARCHPATH
5534 "file_in_path",
5535#endif
5536#ifdef FEAT_FILTERPIPE
5537 "filterpipe",
5538#endif
5539#ifdef FEAT_FIND_ID
5540 "find_in_path",
5541#endif
5542#ifdef FEAT_FLOAT
5543 "float",
5544#endif
5545#ifdef FEAT_FOLDING
5546 "folding",
5547#endif
5548#ifdef FEAT_FOOTER
5549 "footer",
5550#endif
5551#if !defined(USE_SYSTEM) && defined(UNIX)
5552 "fork",
5553#endif
5554#ifdef FEAT_GETTEXT
5555 "gettext",
5556#endif
5557#ifdef FEAT_GUI
5558 "gui",
5559#endif
5560#ifdef FEAT_GUI_ATHENA
5561# ifdef FEAT_GUI_NEXTAW
5562 "gui_neXtaw",
5563# else
5564 "gui_athena",
5565# endif
5566#endif
5567#ifdef FEAT_GUI_GTK
5568 "gui_gtk",
5569# ifdef USE_GTK3
5570 "gui_gtk3",
5571# else
5572 "gui_gtk2",
5573# endif
5574#endif
5575#ifdef FEAT_GUI_GNOME
5576 "gui_gnome",
5577#endif
5578#ifdef FEAT_GUI_MAC
5579 "gui_mac",
5580#endif
5581#ifdef FEAT_GUI_MOTIF
5582 "gui_motif",
5583#endif
5584#ifdef FEAT_GUI_PHOTON
5585 "gui_photon",
5586#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005587#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005588 "gui_win32",
5589#endif
5590#ifdef FEAT_HANGULIN
5591 "hangul_input",
5592#endif
5593#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5594 "iconv",
5595#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005596 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005597#ifdef FEAT_JOB_CHANNEL
5598 "job",
5599#endif
5600#ifdef FEAT_JUMPLIST
5601 "jumplist",
5602#endif
5603#ifdef FEAT_KEYMAP
5604 "keymap",
5605#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005606 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005607#ifdef FEAT_LANGMAP
5608 "langmap",
5609#endif
5610#ifdef FEAT_LIBCALL
5611 "libcall",
5612#endif
5613#ifdef FEAT_LINEBREAK
5614 "linebreak",
5615#endif
5616#ifdef FEAT_LISP
5617 "lispindent",
5618#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005619 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005620 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005621#ifdef FEAT_LUA
5622# ifndef DYNAMIC_LUA
5623 "lua",
5624# endif
5625#endif
5626#ifdef FEAT_MENU
5627 "menu",
5628#endif
5629#ifdef FEAT_SESSION
5630 "mksession",
5631#endif
5632#ifdef FEAT_MODIFY_FNAME
5633 "modify_fname",
5634#endif
5635#ifdef FEAT_MOUSE
5636 "mouse",
5637#endif
5638#ifdef FEAT_MOUSESHAPE
5639 "mouseshape",
5640#endif
5641#if defined(UNIX) || defined(VMS)
5642# ifdef FEAT_MOUSE_DEC
5643 "mouse_dec",
5644# endif
5645# ifdef FEAT_MOUSE_GPM
5646 "mouse_gpm",
5647# endif
5648# ifdef FEAT_MOUSE_JSB
5649 "mouse_jsbterm",
5650# endif
5651# ifdef FEAT_MOUSE_NET
5652 "mouse_netterm",
5653# endif
5654# ifdef FEAT_MOUSE_PTERM
5655 "mouse_pterm",
5656# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01005657# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005658 "mouse_sgr",
5659# endif
5660# ifdef FEAT_SYSMOUSE
5661 "mouse_sysmouse",
5662# endif
5663# ifdef FEAT_MOUSE_URXVT
5664 "mouse_urxvt",
5665# endif
5666# ifdef FEAT_MOUSE_XTERM
5667 "mouse_xterm",
5668# endif
5669#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005670 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005671#ifdef FEAT_MBYTE_IME
5672 "multi_byte_ime",
5673#endif
5674#ifdef FEAT_MULTI_LANG
5675 "multi_lang",
5676#endif
5677#ifdef FEAT_MZSCHEME
5678#ifndef DYNAMIC_MZSCHEME
5679 "mzscheme",
5680#endif
5681#endif
5682#ifdef FEAT_NUM64
5683 "num64",
5684#endif
5685#ifdef FEAT_OLE
5686 "ole",
5687#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02005688#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005689 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02005690#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005691#ifdef FEAT_PATH_EXTRA
5692 "path_extra",
5693#endif
5694#ifdef FEAT_PERL
5695#ifndef DYNAMIC_PERL
5696 "perl",
5697#endif
5698#endif
5699#ifdef FEAT_PERSISTENT_UNDO
5700 "persistent_undo",
5701#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005702#if defined(FEAT_PYTHON)
5703 "python_compiled",
5704# if defined(DYNAMIC_PYTHON)
5705 "python_dynamic",
5706# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005707 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005708 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005709# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005710#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005711#if defined(FEAT_PYTHON3)
5712 "python3_compiled",
5713# if defined(DYNAMIC_PYTHON3)
5714 "python3_dynamic",
5715# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005716 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005717 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01005718# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005719#endif
5720#ifdef FEAT_POSTSCRIPT
5721 "postscript",
5722#endif
5723#ifdef FEAT_PRINTER
5724 "printer",
5725#endif
5726#ifdef FEAT_PROFILE
5727 "profile",
5728#endif
5729#ifdef FEAT_RELTIME
5730 "reltime",
5731#endif
5732#ifdef FEAT_QUICKFIX
5733 "quickfix",
5734#endif
5735#ifdef FEAT_RIGHTLEFT
5736 "rightleft",
5737#endif
5738#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
5739 "ruby",
5740#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005741 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005742#ifdef FEAT_CMDL_INFO
5743 "showcmd",
5744 "cmdline_info",
5745#endif
5746#ifdef FEAT_SIGNS
5747 "signs",
5748#endif
5749#ifdef FEAT_SMARTINDENT
5750 "smartindent",
5751#endif
5752#ifdef STARTUPTIME
5753 "startuptime",
5754#endif
5755#ifdef FEAT_STL_OPT
5756 "statusline",
5757#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005758#ifdef FEAT_NETBEANS_INTG
5759 "netbeans_intg",
5760#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02005761#ifdef FEAT_SOUND
5762 "sound",
5763#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005764#ifdef FEAT_SPELL
5765 "spell",
5766#endif
5767#ifdef FEAT_SYN_HL
5768 "syntax",
5769#endif
5770#if defined(USE_SYSTEM) || !defined(UNIX)
5771 "system",
5772#endif
5773#ifdef FEAT_TAG_BINS
5774 "tag_binary",
5775#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005776#ifdef FEAT_TCL
5777# ifndef DYNAMIC_TCL
5778 "tcl",
5779# endif
5780#endif
5781#ifdef FEAT_TERMGUICOLORS
5782 "termguicolors",
5783#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005784#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02005785 "terminal",
5786#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005787#ifdef TERMINFO
5788 "terminfo",
5789#endif
5790#ifdef FEAT_TERMRESPONSE
5791 "termresponse",
5792#endif
5793#ifdef FEAT_TEXTOBJ
5794 "textobjects",
5795#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01005796#ifdef FEAT_TEXT_PROP
5797 "textprop",
5798#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799#ifdef HAVE_TGETENT
5800 "tgetent",
5801#endif
5802#ifdef FEAT_TIMERS
5803 "timers",
5804#endif
5805#ifdef FEAT_TITLE
5806 "title",
5807#endif
5808#ifdef FEAT_TOOLBAR
5809 "toolbar",
5810#endif
5811#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
5812 "unnamedplus",
5813#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005814 "user-commands", /* was accidentally included in 5.4 */
5815 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005816#ifdef FEAT_VARTABS
5817 "vartabs",
5818#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02005819 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005820#ifdef FEAT_VIMINFO
5821 "viminfo",
5822#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02005823 "vimscript-1",
5824 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02005825 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005826 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005827 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005828 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005829 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01005830#ifdef FEAT_VTP
5831 "vtp",
5832#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005833#ifdef FEAT_WILDIGN
5834 "wildignore",
5835#endif
5836#ifdef FEAT_WILDMENU
5837 "wildmenu",
5838#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005839 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005840#ifdef FEAT_WAK
5841 "winaltkeys",
5842#endif
5843#ifdef FEAT_WRITEBACKUP
5844 "writebackup",
5845#endif
5846#ifdef FEAT_XIM
5847 "xim",
5848#endif
5849#ifdef FEAT_XFONTSET
5850 "xfontset",
5851#endif
5852#ifdef FEAT_XPM_W32
5853 "xpm",
5854 "xpm_w32", /* for backward compatibility */
5855#else
5856# if defined(HAVE_XPM)
5857 "xpm",
5858# endif
5859#endif
5860#ifdef USE_XSMP
5861 "xsmp",
5862#endif
5863#ifdef USE_XSMP_INTERACT
5864 "xsmp_interact",
5865#endif
5866#ifdef FEAT_XCLIPBOARD
5867 "xterm_clipboard",
5868#endif
5869#ifdef FEAT_XTERM_SAVE
5870 "xterm_save",
5871#endif
5872#if defined(UNIX) && defined(FEAT_X11)
5873 "X11",
5874#endif
5875 NULL
5876 };
5877
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005878 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005879 for (i = 0; has_list[i] != NULL; ++i)
5880 if (STRICMP(name, has_list[i]) == 0)
5881 {
5882 n = TRUE;
5883 break;
5884 }
5885
5886 if (n == FALSE)
5887 {
5888 if (STRNICMP(name, "patch", 5) == 0)
5889 {
5890 if (name[5] == '-'
5891 && STRLEN(name) >= 11
5892 && vim_isdigit(name[6])
5893 && vim_isdigit(name[8])
5894 && vim_isdigit(name[10]))
5895 {
5896 int major = atoi((char *)name + 6);
5897 int minor = atoi((char *)name + 8);
5898
5899 /* Expect "patch-9.9.01234". */
5900 n = (major < VIM_VERSION_MAJOR
5901 || (major == VIM_VERSION_MAJOR
5902 && (minor < VIM_VERSION_MINOR
5903 || (minor == VIM_VERSION_MINOR
5904 && has_patch(atoi((char *)name + 10))))));
5905 }
5906 else
5907 n = has_patch(atoi((char *)name + 5));
5908 }
5909 else if (STRICMP(name, "vim_starting") == 0)
5910 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01005911 else if (STRICMP(name, "ttyin") == 0)
5912 n = mch_input_isatty();
5913 else if (STRICMP(name, "ttyout") == 0)
5914 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005915 else if (STRICMP(name, "multi_byte_encoding") == 0)
5916 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01005917#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005918 else if (STRICMP(name, "balloon_multiline") == 0)
5919 n = multiline_balloon_available();
5920#endif
5921#ifdef DYNAMIC_TCL
5922 else if (STRICMP(name, "tcl") == 0)
5923 n = tcl_enabled(FALSE);
5924#endif
5925#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
5926 else if (STRICMP(name, "iconv") == 0)
5927 n = iconv_enabled(FALSE);
5928#endif
5929#ifdef DYNAMIC_LUA
5930 else if (STRICMP(name, "lua") == 0)
5931 n = lua_enabled(FALSE);
5932#endif
5933#ifdef DYNAMIC_MZSCHEME
5934 else if (STRICMP(name, "mzscheme") == 0)
5935 n = mzscheme_enabled(FALSE);
5936#endif
5937#ifdef DYNAMIC_RUBY
5938 else if (STRICMP(name, "ruby") == 0)
5939 n = ruby_enabled(FALSE);
5940#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005941#ifdef DYNAMIC_PYTHON
5942 else if (STRICMP(name, "python") == 0)
5943 n = python_enabled(FALSE);
5944#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005945#ifdef DYNAMIC_PYTHON3
5946 else if (STRICMP(name, "python3") == 0)
5947 n = python3_enabled(FALSE);
5948#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01005949#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
5950 else if (STRICMP(name, "pythonx") == 0)
5951 {
5952# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
5953 if (p_pyx == 0)
5954 n = python3_enabled(FALSE) || python_enabled(FALSE);
5955 else if (p_pyx == 3)
5956 n = python3_enabled(FALSE);
5957 else if (p_pyx == 2)
5958 n = python_enabled(FALSE);
5959# elif defined(DYNAMIC_PYTHON)
5960 n = python_enabled(FALSE);
5961# elif defined(DYNAMIC_PYTHON3)
5962 n = python3_enabled(FALSE);
5963# endif
5964 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005965#endif
5966#ifdef DYNAMIC_PERL
5967 else if (STRICMP(name, "perl") == 0)
5968 n = perl_enabled(FALSE);
5969#endif
5970#ifdef FEAT_GUI
5971 else if (STRICMP(name, "gui_running") == 0)
5972 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005973# ifdef FEAT_BROWSE
5974 else if (STRICMP(name, "browse") == 0)
5975 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
5976# endif
5977#endif
5978#ifdef FEAT_SYN_HL
5979 else if (STRICMP(name, "syntax_items") == 0)
5980 n = syntax_present(curwin);
5981#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01005982#ifdef FEAT_VTP
5983 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02005984 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005985#endif
5986#ifdef FEAT_NETBEANS_INTG
5987 else if (STRICMP(name, "netbeans_enabled") == 0)
5988 n = netbeans_active();
5989#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02005990#ifdef FEAT_MOUSE_GPM
5991 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
5992 n = gpm_enabled();
5993#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005994#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02005995 else if (STRICMP(name, "terminal") == 0)
5996 n = terminal_enabled();
5997#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005998#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01005999 else if (STRICMP(name, "conpty") == 0)
6000 n = use_conpty();
6001#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006002#ifdef FEAT_CLIPBOARD
6003 else if (STRICMP(name, "clipboard_working") == 0)
6004 n = clip_star.available;
6005#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006006 }
6007
6008 rettv->vval.v_number = n;
6009}
6010
6011/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006012 * "haslocaldir()" function
6013 */
6014 static void
6015f_haslocaldir(typval_T *argvars, typval_T *rettv)
6016{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006017 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006018 win_T *wp = NULL;
6019
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006020 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6021
6022 // Check for window-local and tab-local directories
6023 if (wp != NULL && wp->w_localdir != NULL)
6024 rettv->vval.v_number = 1;
6025 else if (tp != NULL && tp->tp_localdir != NULL)
6026 rettv->vval.v_number = 2;
6027 else
6028 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006029}
6030
6031/*
6032 * "hasmapto()" function
6033 */
6034 static void
6035f_hasmapto(typval_T *argvars, typval_T *rettv)
6036{
6037 char_u *name;
6038 char_u *mode;
6039 char_u buf[NUMBUFLEN];
6040 int abbr = FALSE;
6041
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006042 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006043 if (argvars[1].v_type == VAR_UNKNOWN)
6044 mode = (char_u *)"nvo";
6045 else
6046 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006047 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006048 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006049 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006050 }
6051
6052 if (map_to_exists(name, mode, abbr))
6053 rettv->vval.v_number = TRUE;
6054 else
6055 rettv->vval.v_number = FALSE;
6056}
6057
6058/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006059 * "highlightID(name)" function
6060 */
6061 static void
6062f_hlID(typval_T *argvars, typval_T *rettv)
6063{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006064 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006065}
6066
6067/*
6068 * "highlight_exists()" function
6069 */
6070 static void
6071f_hlexists(typval_T *argvars, typval_T *rettv)
6072{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006073 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006074}
6075
6076/*
6077 * "hostname()" function
6078 */
6079 static void
6080f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6081{
6082 char_u hostname[256];
6083
6084 mch_get_host_name(hostname, 256);
6085 rettv->v_type = VAR_STRING;
6086 rettv->vval.v_string = vim_strsave(hostname);
6087}
6088
6089/*
6090 * iconv() function
6091 */
6092 static void
6093f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6094{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006095 char_u buf1[NUMBUFLEN];
6096 char_u buf2[NUMBUFLEN];
6097 char_u *from, *to, *str;
6098 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006099
6100 rettv->v_type = VAR_STRING;
6101 rettv->vval.v_string = NULL;
6102
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006103 str = tv_get_string(&argvars[0]);
6104 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6105 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006106 vimconv.vc_type = CONV_NONE;
6107 convert_setup(&vimconv, from, to);
6108
6109 /* If the encodings are equal, no conversion needed. */
6110 if (vimconv.vc_type == CONV_NONE)
6111 rettv->vval.v_string = vim_strsave(str);
6112 else
6113 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6114
6115 convert_setup(&vimconv, NULL, NULL);
6116 vim_free(from);
6117 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006118}
6119
6120/*
6121 * "indent()" function
6122 */
6123 static void
6124f_indent(typval_T *argvars, typval_T *rettv)
6125{
6126 linenr_T lnum;
6127
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006128 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006129 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6130 rettv->vval.v_number = get_indent_lnum(lnum);
6131 else
6132 rettv->vval.v_number = -1;
6133}
6134
6135/*
6136 * "index()" function
6137 */
6138 static void
6139f_index(typval_T *argvars, typval_T *rettv)
6140{
6141 list_T *l;
6142 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006143 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006144 long idx = 0;
6145 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006146 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006147
6148 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006149 if (argvars[0].v_type == VAR_BLOB)
6150 {
6151 typval_T tv;
6152 int start = 0;
6153
6154 if (argvars[2].v_type != VAR_UNKNOWN)
6155 {
6156 start = tv_get_number_chk(&argvars[2], &error);
6157 if (error)
6158 return;
6159 }
6160 b = argvars[0].vval.v_blob;
6161 if (b == NULL)
6162 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006163 if (start < 0)
6164 {
6165 start = blob_len(b) + start;
6166 if (start < 0)
6167 start = 0;
6168 }
6169
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006170 for (idx = start; idx < blob_len(b); ++idx)
6171 {
6172 tv.v_type = VAR_NUMBER;
6173 tv.vval.v_number = blob_get(b, idx);
6174 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6175 {
6176 rettv->vval.v_number = idx;
6177 return;
6178 }
6179 }
6180 return;
6181 }
6182 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006183 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006184 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 return;
6186 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006187
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006188 l = argvars[0].vval.v_list;
6189 if (l != NULL)
6190 {
6191 item = l->lv_first;
6192 if (argvars[2].v_type != VAR_UNKNOWN)
6193 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006194 /* Start at specified item. Use the cached index that list_find()
6195 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006196 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197 idx = l->lv_idx;
6198 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006199 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006200 if (error)
6201 item = NULL;
6202 }
6203
6204 for ( ; item != NULL; item = item->li_next, ++idx)
6205 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6206 {
6207 rettv->vval.v_number = idx;
6208 break;
6209 }
6210 }
6211}
6212
6213static int inputsecret_flag = 0;
6214
6215/*
6216 * "input()" function
6217 * Also handles inputsecret() when inputsecret is set.
6218 */
6219 static void
6220f_input(typval_T *argvars, typval_T *rettv)
6221{
6222 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6223}
6224
6225/*
6226 * "inputdialog()" function
6227 */
6228 static void
6229f_inputdialog(typval_T *argvars, typval_T *rettv)
6230{
6231#if defined(FEAT_GUI_TEXTDIALOG)
6232 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6233 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6234 {
6235 char_u *message;
6236 char_u buf[NUMBUFLEN];
6237 char_u *defstr = (char_u *)"";
6238
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006239 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006240 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006241 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006242 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6243 else
6244 IObuff[0] = NUL;
6245 if (message != NULL && defstr != NULL
6246 && do_dialog(VIM_QUESTION, NULL, message,
6247 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6248 rettv->vval.v_string = vim_strsave(IObuff);
6249 else
6250 {
6251 if (message != NULL && defstr != NULL
6252 && argvars[1].v_type != VAR_UNKNOWN
6253 && argvars[2].v_type != VAR_UNKNOWN)
6254 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006255 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006256 else
6257 rettv->vval.v_string = NULL;
6258 }
6259 rettv->v_type = VAR_STRING;
6260 }
6261 else
6262#endif
6263 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6264}
6265
6266/*
6267 * "inputlist()" function
6268 */
6269 static void
6270f_inputlist(typval_T *argvars, typval_T *rettv)
6271{
6272 listitem_T *li;
6273 int selected;
6274 int mouse_used;
6275
6276#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006277 /* While starting up, there is no place to enter text. When running tests
6278 * with --not-a-term we assume feedkeys() will be used. */
6279 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006280 return;
6281#endif
6282 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6283 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006284 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006285 return;
6286 }
6287
6288 msg_start();
6289 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6290 lines_left = Rows; /* avoid more prompt */
6291 msg_scroll = TRUE;
6292 msg_clr_eos();
6293
6294 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6295 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006296 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006297 msg_putchar('\n');
6298 }
6299
6300 /* Ask for choice. */
6301 selected = prompt_for_number(&mouse_used);
6302 if (mouse_used)
6303 selected -= lines_left;
6304
6305 rettv->vval.v_number = selected;
6306}
6307
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006308static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6309
6310/*
6311 * "inputrestore()" function
6312 */
6313 static void
6314f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6315{
6316 if (ga_userinput.ga_len > 0)
6317 {
6318 --ga_userinput.ga_len;
6319 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6320 + ga_userinput.ga_len);
6321 /* default return is zero == OK */
6322 }
6323 else if (p_verbose > 1)
6324 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006325 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006326 rettv->vval.v_number = 1; /* Failed */
6327 }
6328}
6329
6330/*
6331 * "inputsave()" function
6332 */
6333 static void
6334f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6335{
6336 /* Add an entry to the stack of typeahead storage. */
6337 if (ga_grow(&ga_userinput, 1) == OK)
6338 {
6339 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6340 + ga_userinput.ga_len);
6341 ++ga_userinput.ga_len;
6342 /* default return is zero == OK */
6343 }
6344 else
6345 rettv->vval.v_number = 1; /* Failed */
6346}
6347
6348/*
6349 * "inputsecret()" function
6350 */
6351 static void
6352f_inputsecret(typval_T *argvars, typval_T *rettv)
6353{
6354 ++cmdline_star;
6355 ++inputsecret_flag;
6356 f_input(argvars, rettv);
6357 --cmdline_star;
6358 --inputsecret_flag;
6359}
6360
6361/*
6362 * "insert()" function
6363 */
6364 static void
6365f_insert(typval_T *argvars, typval_T *rettv)
6366{
6367 long before = 0;
6368 listitem_T *item;
6369 list_T *l;
6370 int error = FALSE;
6371
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006372 if (argvars[0].v_type == VAR_BLOB)
6373 {
6374 int val, len;
6375 char_u *p;
6376
6377 len = blob_len(argvars[0].vval.v_blob);
6378 if (argvars[2].v_type != VAR_UNKNOWN)
6379 {
6380 before = (long)tv_get_number_chk(&argvars[2], &error);
6381 if (error)
6382 return; // type error; errmsg already given
6383 if (before < 0 || before > len)
6384 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006385 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006386 return;
6387 }
6388 }
6389 val = tv_get_number_chk(&argvars[1], &error);
6390 if (error)
6391 return;
6392 if (val < 0 || val > 255)
6393 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006394 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006395 return;
6396 }
6397
6398 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6399 return;
6400 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6401 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6402 *(p + before) = val;
6403 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6404
6405 copy_tv(&argvars[0], rettv);
6406 }
6407 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006408 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006409 else if ((l = argvars[0].vval.v_list) != NULL
6410 && !var_check_lock(l->lv_lock,
6411 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006412 {
6413 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006414 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006415 if (error)
6416 return; /* type error; errmsg already given */
6417
6418 if (before == l->lv_len)
6419 item = NULL;
6420 else
6421 {
6422 item = list_find(l, before);
6423 if (item == NULL)
6424 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006425 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006426 l = NULL;
6427 }
6428 }
6429 if (l != NULL)
6430 {
6431 list_insert_tv(l, &argvars[1], item);
6432 copy_tv(&argvars[0], rettv);
6433 }
6434 }
6435}
6436
6437/*
6438 * "invert(expr)" function
6439 */
6440 static void
6441f_invert(typval_T *argvars, typval_T *rettv)
6442{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006443 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006444}
6445
6446/*
6447 * "isdirectory()" function
6448 */
6449 static void
6450f_isdirectory(typval_T *argvars, typval_T *rettv)
6451{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006452 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006453}
6454
6455/*
6456 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6457 * or it refers to a List or Dictionary that is locked.
6458 */
6459 static int
6460tv_islocked(typval_T *tv)
6461{
6462 return (tv->v_lock & VAR_LOCKED)
6463 || (tv->v_type == VAR_LIST
6464 && tv->vval.v_list != NULL
6465 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6466 || (tv->v_type == VAR_DICT
6467 && tv->vval.v_dict != NULL
6468 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6469}
6470
6471/*
6472 * "islocked()" function
6473 */
6474 static void
6475f_islocked(typval_T *argvars, typval_T *rettv)
6476{
6477 lval_T lv;
6478 char_u *end;
6479 dictitem_T *di;
6480
6481 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006482 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006483 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006484 if (end != NULL && lv.ll_name != NULL)
6485 {
6486 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006487 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006488 else
6489 {
6490 if (lv.ll_tv == NULL)
6491 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006492 di = find_var(lv.ll_name, NULL, TRUE);
6493 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006494 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006495 /* Consider a variable locked when:
6496 * 1. the variable itself is locked
6497 * 2. the value of the variable is locked.
6498 * 3. the List or Dict value is locked.
6499 */
6500 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6501 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006502 }
6503 }
6504 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006505 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006506 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006507 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006508 else if (lv.ll_list != NULL)
6509 /* List item. */
6510 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6511 else
6512 /* Dictionary item. */
6513 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6514 }
6515 }
6516
6517 clear_lval(&lv);
6518}
6519
6520#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6521/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02006522 * "isinf()" function
6523 */
6524 static void
6525f_isinf(typval_T *argvars, typval_T *rettv)
6526{
6527 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
6528 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
6529}
6530
6531/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006532 * "isnan()" function
6533 */
6534 static void
6535f_isnan(typval_T *argvars, typval_T *rettv)
6536{
6537 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6538 && isnan(argvars[0].vval.v_float);
6539}
6540#endif
6541
6542/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006543 * "last_buffer_nr()" function.
6544 */
6545 static void
6546f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6547{
6548 int n = 0;
6549 buf_T *buf;
6550
Bram Moolenaar29323592016-07-24 22:04:11 +02006551 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006552 if (n < buf->b_fnum)
6553 n = buf->b_fnum;
6554
6555 rettv->vval.v_number = n;
6556}
6557
6558/*
6559 * "len()" function
6560 */
6561 static void
6562f_len(typval_T *argvars, typval_T *rettv)
6563{
6564 switch (argvars[0].v_type)
6565 {
6566 case VAR_STRING:
6567 case VAR_NUMBER:
6568 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006569 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006571 case VAR_BLOB:
6572 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6573 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006574 case VAR_LIST:
6575 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6576 break;
6577 case VAR_DICT:
6578 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6579 break;
6580 case VAR_UNKNOWN:
6581 case VAR_SPECIAL:
6582 case VAR_FLOAT:
6583 case VAR_FUNC:
6584 case VAR_PARTIAL:
6585 case VAR_JOB:
6586 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006587 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588 break;
6589 }
6590}
6591
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006592 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006593libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006594{
6595#ifdef FEAT_LIBCALL
6596 char_u *string_in;
6597 char_u **string_result;
6598 int nr_result;
6599#endif
6600
6601 rettv->v_type = type;
6602 if (type != VAR_NUMBER)
6603 rettv->vval.v_string = NULL;
6604
6605 if (check_restricted() || check_secure())
6606 return;
6607
6608#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02006609 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006610 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6611 {
6612 string_in = NULL;
6613 if (argvars[2].v_type == VAR_STRING)
6614 string_in = argvars[2].vval.v_string;
6615 if (type == VAR_NUMBER)
6616 string_result = NULL;
6617 else
6618 string_result = &rettv->vval.v_string;
6619 if (mch_libcall(argvars[0].vval.v_string,
6620 argvars[1].vval.v_string,
6621 string_in,
6622 argvars[2].vval.v_number,
6623 string_result,
6624 &nr_result) == OK
6625 && type == VAR_NUMBER)
6626 rettv->vval.v_number = nr_result;
6627 }
6628#endif
6629}
6630
6631/*
6632 * "libcall()" function
6633 */
6634 static void
6635f_libcall(typval_T *argvars, typval_T *rettv)
6636{
6637 libcall_common(argvars, rettv, VAR_STRING);
6638}
6639
6640/*
6641 * "libcallnr()" function
6642 */
6643 static void
6644f_libcallnr(typval_T *argvars, typval_T *rettv)
6645{
6646 libcall_common(argvars, rettv, VAR_NUMBER);
6647}
6648
6649/*
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006650 * "line(string, [winid])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006651 */
6652 static void
6653f_line(typval_T *argvars, typval_T *rettv)
6654{
6655 linenr_T lnum = 0;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006656 pos_T *fp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006657 int fnum;
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006658 int id;
6659 tabpage_T *tp;
6660 win_T *wp;
6661 win_T *save_curwin;
6662 tabpage_T *save_curtab;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006663
Bram Moolenaar8e0a8e72019-09-02 22:56:24 +02006664 if (argvars[1].v_type != VAR_UNKNOWN)
6665 {
6666 // use window specified in the second argument
6667 id = (int)tv_get_number(&argvars[1]);
6668 wp = win_id2wp_tp(id, &tp);
6669 if (wp != NULL && tp != NULL)
6670 {
6671 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE)
6672 == OK)
6673 {
6674 check_cursor();
6675 fp = var2fpos(&argvars[0], TRUE, &fnum);
6676 }
6677 restore_win_noblock(save_curwin, save_curtab, TRUE);
6678 }
6679 }
6680 else
6681 // use current window
6682 fp = var2fpos(&argvars[0], TRUE, &fnum);
6683
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006684 if (fp != NULL)
6685 lnum = fp->lnum;
6686 rettv->vval.v_number = lnum;
6687}
6688
6689/*
6690 * "line2byte(lnum)" function
6691 */
6692 static void
6693f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
6694{
6695#ifndef FEAT_BYTEOFF
6696 rettv->vval.v_number = -1;
6697#else
6698 linenr_T lnum;
6699
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006700 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006701 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
6702 rettv->vval.v_number = -1;
6703 else
6704 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
6705 if (rettv->vval.v_number >= 0)
6706 ++rettv->vval.v_number;
6707#endif
6708}
6709
6710/*
6711 * "lispindent(lnum)" function
6712 */
6713 static void
6714f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
6715{
6716#ifdef FEAT_LISP
6717 pos_T pos;
6718 linenr_T lnum;
6719
6720 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006721 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006722 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6723 {
6724 curwin->w_cursor.lnum = lnum;
6725 rettv->vval.v_number = get_lisp_indent();
6726 curwin->w_cursor = pos;
6727 }
6728 else
6729#endif
6730 rettv->vval.v_number = -1;
6731}
6732
6733/*
6734 * "localtime()" function
6735 */
6736 static void
6737f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
6738{
6739 rettv->vval.v_number = (varnumber_T)time(NULL);
6740}
6741
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006742#ifdef FEAT_FLOAT
6743/*
6744 * "log()" function
6745 */
6746 static void
6747f_log(typval_T *argvars, typval_T *rettv)
6748{
6749 float_T f = 0.0;
6750
6751 rettv->v_type = VAR_FLOAT;
6752 if (get_float_arg(argvars, &f) == OK)
6753 rettv->vval.v_float = log(f);
6754 else
6755 rettv->vval.v_float = 0.0;
6756}
6757
6758/*
6759 * "log10()" function
6760 */
6761 static void
6762f_log10(typval_T *argvars, typval_T *rettv)
6763{
6764 float_T f = 0.0;
6765
6766 rettv->v_type = VAR_FLOAT;
6767 if (get_float_arg(argvars, &f) == OK)
6768 rettv->vval.v_float = log10(f);
6769 else
6770 rettv->vval.v_float = 0.0;
6771}
6772#endif
6773
6774#ifdef FEAT_LUA
6775/*
6776 * "luaeval()" function
6777 */
6778 static void
6779f_luaeval(typval_T *argvars, typval_T *rettv)
6780{
6781 char_u *str;
6782 char_u buf[NUMBUFLEN];
6783
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006784 if (check_restricted() || check_secure())
6785 return;
6786
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006787 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006788 do_luaeval(str, argvars + 1, rettv);
6789}
6790#endif
6791
6792/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006793 * "maparg()" function
6794 */
6795 static void
6796f_maparg(typval_T *argvars, typval_T *rettv)
6797{
6798 get_maparg(argvars, rettv, TRUE);
6799}
6800
6801/*
6802 * "mapcheck()" function
6803 */
6804 static void
6805f_mapcheck(typval_T *argvars, typval_T *rettv)
6806{
6807 get_maparg(argvars, rettv, FALSE);
6808}
6809
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006810typedef enum
6811{
6812 MATCH_END, /* matchend() */
6813 MATCH_MATCH, /* match() */
6814 MATCH_STR, /* matchstr() */
6815 MATCH_LIST, /* matchlist() */
6816 MATCH_POS /* matchstrpos() */
6817} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006818
6819 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006820find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006821{
6822 char_u *str = NULL;
6823 long len = 0;
6824 char_u *expr = NULL;
6825 char_u *pat;
6826 regmatch_T regmatch;
6827 char_u patbuf[NUMBUFLEN];
6828 char_u strbuf[NUMBUFLEN];
6829 char_u *save_cpo;
6830 long start = 0;
6831 long nth = 1;
6832 colnr_T startcol = 0;
6833 int match = 0;
6834 list_T *l = NULL;
6835 listitem_T *li = NULL;
6836 long idx = 0;
6837 char_u *tofree = NULL;
6838
6839 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
6840 save_cpo = p_cpo;
6841 p_cpo = (char_u *)"";
6842
6843 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006844 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006845 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006846 /* type MATCH_LIST: return empty list when there are no matches.
6847 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006848 if (rettv_list_alloc(rettv) == FAIL)
6849 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006850 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 && (list_append_string(rettv->vval.v_list,
6852 (char_u *)"", 0) == FAIL
6853 || list_append_number(rettv->vval.v_list,
6854 (varnumber_T)-1) == FAIL
6855 || list_append_number(rettv->vval.v_list,
6856 (varnumber_T)-1) == FAIL
6857 || list_append_number(rettv->vval.v_list,
6858 (varnumber_T)-1) == FAIL))
6859 {
6860 list_free(rettv->vval.v_list);
6861 rettv->vval.v_list = NULL;
6862 goto theend;
6863 }
6864 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006865 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006866 {
6867 rettv->v_type = VAR_STRING;
6868 rettv->vval.v_string = NULL;
6869 }
6870
6871 if (argvars[0].v_type == VAR_LIST)
6872 {
6873 if ((l = argvars[0].vval.v_list) == NULL)
6874 goto theend;
6875 li = l->lv_first;
6876 }
6877 else
6878 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006879 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006880 len = (long)STRLEN(str);
6881 }
6882
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006883 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006884 if (pat == NULL)
6885 goto theend;
6886
6887 if (argvars[2].v_type != VAR_UNKNOWN)
6888 {
6889 int error = FALSE;
6890
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006891 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892 if (error)
6893 goto theend;
6894 if (l != NULL)
6895 {
6896 li = list_find(l, start);
6897 if (li == NULL)
6898 goto theend;
6899 idx = l->lv_idx; /* use the cached index */
6900 }
6901 else
6902 {
6903 if (start < 0)
6904 start = 0;
6905 if (start > len)
6906 goto theend;
6907 /* When "count" argument is there ignore matches before "start",
6908 * otherwise skip part of the string. Differs when pattern is "^"
6909 * or "\<". */
6910 if (argvars[3].v_type != VAR_UNKNOWN)
6911 startcol = start;
6912 else
6913 {
6914 str += start;
6915 len -= start;
6916 }
6917 }
6918
6919 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006920 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006921 if (error)
6922 goto theend;
6923 }
6924
6925 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
6926 if (regmatch.regprog != NULL)
6927 {
6928 regmatch.rm_ic = p_ic;
6929
6930 for (;;)
6931 {
6932 if (l != NULL)
6933 {
6934 if (li == NULL)
6935 {
6936 match = FALSE;
6937 break;
6938 }
6939 vim_free(tofree);
6940 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
6941 if (str == NULL)
6942 break;
6943 }
6944
6945 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
6946
6947 if (match && --nth <= 0)
6948 break;
6949 if (l == NULL && !match)
6950 break;
6951
6952 /* Advance to just after the match. */
6953 if (l != NULL)
6954 {
6955 li = li->li_next;
6956 ++idx;
6957 }
6958 else
6959 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006960 startcol = (colnr_T)(regmatch.startp[0]
6961 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006962 if (startcol > (colnr_T)len
6963 || str + startcol <= regmatch.startp[0])
6964 {
6965 match = FALSE;
6966 break;
6967 }
6968 }
6969 }
6970
6971 if (match)
6972 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006973 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006974 {
6975 listitem_T *li1 = rettv->vval.v_list->lv_first;
6976 listitem_T *li2 = li1->li_next;
6977 listitem_T *li3 = li2->li_next;
6978 listitem_T *li4 = li3->li_next;
6979
6980 vim_free(li1->li_tv.vval.v_string);
6981 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
6982 (int)(regmatch.endp[0] - regmatch.startp[0]));
6983 li3->li_tv.vval.v_number =
6984 (varnumber_T)(regmatch.startp[0] - expr);
6985 li4->li_tv.vval.v_number =
6986 (varnumber_T)(regmatch.endp[0] - expr);
6987 if (l != NULL)
6988 li2->li_tv.vval.v_number = (varnumber_T)idx;
6989 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02006990 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006991 {
6992 int i;
6993
6994 /* return list with matched string and submatches */
6995 for (i = 0; i < NSUBEXP; ++i)
6996 {
6997 if (regmatch.endp[i] == NULL)
6998 {
6999 if (list_append_string(rettv->vval.v_list,
7000 (char_u *)"", 0) == FAIL)
7001 break;
7002 }
7003 else if (list_append_string(rettv->vval.v_list,
7004 regmatch.startp[i],
7005 (int)(regmatch.endp[i] - regmatch.startp[i]))
7006 == FAIL)
7007 break;
7008 }
7009 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007010 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007011 {
7012 /* return matched string */
7013 if (l != NULL)
7014 copy_tv(&li->li_tv, rettv);
7015 else
7016 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7017 (int)(regmatch.endp[0] - regmatch.startp[0]));
7018 }
7019 else if (l != NULL)
7020 rettv->vval.v_number = idx;
7021 else
7022 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007023 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024 rettv->vval.v_number =
7025 (varnumber_T)(regmatch.startp[0] - str);
7026 else
7027 rettv->vval.v_number =
7028 (varnumber_T)(regmatch.endp[0] - str);
7029 rettv->vval.v_number += (varnumber_T)(str - expr);
7030 }
7031 }
7032 vim_regfree(regmatch.regprog);
7033 }
7034
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007035theend:
7036 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007037 /* matchstrpos() without a list: drop the second item. */
7038 listitem_remove(rettv->vval.v_list,
7039 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007040 vim_free(tofree);
7041 p_cpo = save_cpo;
7042}
7043
7044/*
7045 * "match()" function
7046 */
7047 static void
7048f_match(typval_T *argvars, typval_T *rettv)
7049{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007050 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007051}
7052
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007053/*
7054 * "matchend()" function
7055 */
7056 static void
7057f_matchend(typval_T *argvars, typval_T *rettv)
7058{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007059 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007060}
7061
7062/*
7063 * "matchlist()" function
7064 */
7065 static void
7066f_matchlist(typval_T *argvars, typval_T *rettv)
7067{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007068 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069}
7070
7071/*
7072 * "matchstr()" function
7073 */
7074 static void
7075f_matchstr(typval_T *argvars, typval_T *rettv)
7076{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007077 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007078}
7079
7080/*
7081 * "matchstrpos()" function
7082 */
7083 static void
7084f_matchstrpos(typval_T *argvars, typval_T *rettv)
7085{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007086 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007087}
7088
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007089 static void
7090max_min(typval_T *argvars, typval_T *rettv, int domax)
7091{
7092 varnumber_T n = 0;
7093 varnumber_T i;
7094 int error = FALSE;
7095
7096 if (argvars[0].v_type == VAR_LIST)
7097 {
7098 list_T *l;
7099 listitem_T *li;
7100
7101 l = argvars[0].vval.v_list;
7102 if (l != NULL)
7103 {
7104 li = l->lv_first;
7105 if (li != NULL)
7106 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007107 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007108 for (;;)
7109 {
7110 li = li->li_next;
7111 if (li == NULL)
7112 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007113 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007114 if (domax ? i > n : i < n)
7115 n = i;
7116 }
7117 }
7118 }
7119 }
7120 else if (argvars[0].v_type == VAR_DICT)
7121 {
7122 dict_T *d;
7123 int first = TRUE;
7124 hashitem_T *hi;
7125 int todo;
7126
7127 d = argvars[0].vval.v_dict;
7128 if (d != NULL)
7129 {
7130 todo = (int)d->dv_hashtab.ht_used;
7131 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7132 {
7133 if (!HASHITEM_EMPTY(hi))
7134 {
7135 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007136 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007137 if (first)
7138 {
7139 n = i;
7140 first = FALSE;
7141 }
7142 else if (domax ? i > n : i < n)
7143 n = i;
7144 }
7145 }
7146 }
7147 }
7148 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007149 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007150 rettv->vval.v_number = error ? 0 : n;
7151}
7152
7153/*
7154 * "max()" function
7155 */
7156 static void
7157f_max(typval_T *argvars, typval_T *rettv)
7158{
7159 max_min(argvars, rettv, TRUE);
7160}
7161
7162/*
7163 * "min()" function
7164 */
7165 static void
7166f_min(typval_T *argvars, typval_T *rettv)
7167{
7168 max_min(argvars, rettv, FALSE);
7169}
7170
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007171/*
7172 * Create the directory in which "dir" is located, and higher levels when
7173 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007174 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007175 */
7176 static int
7177mkdir_recurse(char_u *dir, int prot)
7178{
7179 char_u *p;
7180 char_u *updir;
7181 int r = FAIL;
7182
7183 /* Get end of directory name in "dir".
7184 * We're done when it's "/" or "c:/". */
7185 p = gettail_sep(dir);
7186 if (p <= get_past_head(dir))
7187 return OK;
7188
7189 /* If the directory exists we're done. Otherwise: create it.*/
7190 updir = vim_strnsave(dir, (int)(p - dir));
7191 if (updir == NULL)
7192 return FAIL;
7193 if (mch_isdir(updir))
7194 r = OK;
7195 else if (mkdir_recurse(updir, prot) == OK)
7196 r = vim_mkdir_emsg(updir, prot);
7197 vim_free(updir);
7198 return r;
7199}
7200
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007201/*
7202 * "mkdir()" function
7203 */
7204 static void
7205f_mkdir(typval_T *argvars, typval_T *rettv)
7206{
7207 char_u *dir;
7208 char_u buf[NUMBUFLEN];
7209 int prot = 0755;
7210
7211 rettv->vval.v_number = FAIL;
7212 if (check_restricted() || check_secure())
7213 return;
7214
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007215 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007216 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007217 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007218
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007219 if (*gettail(dir) == NUL)
7220 /* remove trailing slashes */
7221 *gettail_sep(dir) = NUL;
7222
7223 if (argvars[1].v_type != VAR_UNKNOWN)
7224 {
7225 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007226 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007227 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007228 if (prot == -1)
7229 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007230 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007231 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007232 {
7233 if (mch_isdir(dir))
7234 {
7235 /* With the "p" flag it's OK if the dir already exists. */
7236 rettv->vval.v_number = OK;
7237 return;
7238 }
7239 mkdir_recurse(dir, prot);
7240 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007241 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007242 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007243}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007244
7245/*
7246 * "mode()" function
7247 */
7248 static void
7249f_mode(typval_T *argvars, typval_T *rettv)
7250{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007251 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007252
Bram Moolenaar612cc382018-07-29 15:34:26 +02007253 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007254
7255 if (time_for_testing == 93784)
7256 {
7257 /* Testing the two-character code. */
7258 buf[0] = 'x';
7259 buf[1] = '!';
7260 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007261#ifdef FEAT_TERMINAL
7262 else if (term_use_loop())
7263 buf[0] = 't';
7264#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007265 else if (VIsual_active)
7266 {
7267 if (VIsual_select)
7268 buf[0] = VIsual_mode + 's' - 'v';
7269 else
7270 buf[0] = VIsual_mode;
7271 }
7272 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7273 || State == CONFIRM)
7274 {
7275 buf[0] = 'r';
7276 if (State == ASKMORE)
7277 buf[1] = 'm';
7278 else if (State == CONFIRM)
7279 buf[1] = '?';
7280 }
7281 else if (State == EXTERNCMD)
7282 buf[0] = '!';
7283 else if (State & INSERT)
7284 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007285 if (State & VREPLACE_FLAG)
7286 {
7287 buf[0] = 'R';
7288 buf[1] = 'v';
7289 }
7290 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007291 {
7292 if (State & REPLACE_FLAG)
7293 buf[0] = 'R';
7294 else
7295 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007296 if (ins_compl_active())
7297 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007298 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007299 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007300 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007301 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007302 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007303 {
7304 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007305 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007306 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007307 else if (exmode_active == EXMODE_NORMAL)
7308 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007309 }
7310 else
7311 {
7312 buf[0] = 'n';
7313 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007314 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007315 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007316 // to be able to detect force-linewise/blockwise/characterwise operations
7317 buf[2] = motion_force;
7318 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007319 else if (restart_edit == 'I' || restart_edit == 'R'
7320 || restart_edit == 'V')
7321 {
7322 buf[1] = 'i';
7323 buf[2] = restart_edit;
7324 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007325 }
7326
7327 /* Clear out the minor mode when the argument is not a non-zero number or
7328 * non-empty string. */
7329 if (!non_zero_arg(&argvars[0]))
7330 buf[1] = NUL;
7331
7332 rettv->vval.v_string = vim_strsave(buf);
7333 rettv->v_type = VAR_STRING;
7334}
7335
7336#if defined(FEAT_MZSCHEME) || defined(PROTO)
7337/*
7338 * "mzeval()" function
7339 */
7340 static void
7341f_mzeval(typval_T *argvars, typval_T *rettv)
7342{
7343 char_u *str;
7344 char_u buf[NUMBUFLEN];
7345
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007346 if (check_restricted() || check_secure())
7347 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007348 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007349 do_mzeval(str, rettv);
7350}
7351
7352 void
7353mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7354{
7355 typval_T argvars[3];
7356
7357 argvars[0].v_type = VAR_STRING;
7358 argvars[0].vval.v_string = name;
7359 copy_tv(args, &argvars[1]);
7360 argvars[2].v_type = VAR_UNKNOWN;
7361 f_call(argvars, rettv);
7362 clear_tv(&argvars[1]);
7363}
7364#endif
7365
7366/*
7367 * "nextnonblank()" function
7368 */
7369 static void
7370f_nextnonblank(typval_T *argvars, typval_T *rettv)
7371{
7372 linenr_T lnum;
7373
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007374 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007375 {
7376 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7377 {
7378 lnum = 0;
7379 break;
7380 }
7381 if (*skipwhite(ml_get(lnum)) != NUL)
7382 break;
7383 }
7384 rettv->vval.v_number = lnum;
7385}
7386
7387/*
7388 * "nr2char()" function
7389 */
7390 static void
7391f_nr2char(typval_T *argvars, typval_T *rettv)
7392{
7393 char_u buf[NUMBUFLEN];
7394
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007395 if (has_mbyte)
7396 {
7397 int utf8 = 0;
7398
7399 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007400 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007401 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007402 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007403 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007404 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007405 }
7406 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007407 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007408 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007409 buf[1] = NUL;
7410 }
7411 rettv->v_type = VAR_STRING;
7412 rettv->vval.v_string = vim_strsave(buf);
7413}
7414
7415/*
7416 * "or(expr, expr)" function
7417 */
7418 static void
7419f_or(typval_T *argvars, typval_T *rettv)
7420{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007421 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7422 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007423}
7424
7425/*
7426 * "pathshorten()" function
7427 */
7428 static void
7429f_pathshorten(typval_T *argvars, typval_T *rettv)
7430{
7431 char_u *p;
7432
7433 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007434 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007435 if (p == NULL)
7436 rettv->vval.v_string = NULL;
7437 else
7438 {
7439 p = vim_strsave(p);
7440 rettv->vval.v_string = p;
7441 if (p != NULL)
7442 shorten_dir(p);
7443 }
7444}
7445
7446#ifdef FEAT_PERL
7447/*
7448 * "perleval()" function
7449 */
7450 static void
7451f_perleval(typval_T *argvars, typval_T *rettv)
7452{
7453 char_u *str;
7454 char_u buf[NUMBUFLEN];
7455
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007456 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007457 do_perleval(str, rettv);
7458}
7459#endif
7460
7461#ifdef FEAT_FLOAT
7462/*
7463 * "pow()" function
7464 */
7465 static void
7466f_pow(typval_T *argvars, typval_T *rettv)
7467{
7468 float_T fx = 0.0, fy = 0.0;
7469
7470 rettv->v_type = VAR_FLOAT;
7471 if (get_float_arg(argvars, &fx) == OK
7472 && get_float_arg(&argvars[1], &fy) == OK)
7473 rettv->vval.v_float = pow(fx, fy);
7474 else
7475 rettv->vval.v_float = 0.0;
7476}
7477#endif
7478
7479/*
7480 * "prevnonblank()" function
7481 */
7482 static void
7483f_prevnonblank(typval_T *argvars, typval_T *rettv)
7484{
7485 linenr_T lnum;
7486
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007487 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007488 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7489 lnum = 0;
7490 else
7491 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7492 --lnum;
7493 rettv->vval.v_number = lnum;
7494}
7495
7496/* This dummy va_list is here because:
7497 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7498 * - locally in the function results in a "used before set" warning
7499 * - using va_start() to initialize it gives "function with fixed args" error */
7500static va_list ap;
7501
7502/*
7503 * "printf()" function
7504 */
7505 static void
7506f_printf(typval_T *argvars, typval_T *rettv)
7507{
7508 char_u buf[NUMBUFLEN];
7509 int len;
7510 char_u *s;
7511 int saved_did_emsg = did_emsg;
7512 char *fmt;
7513
7514 rettv->v_type = VAR_STRING;
7515 rettv->vval.v_string = NULL;
7516
7517 /* Get the required length, allocate the buffer and do it for real. */
7518 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007519 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007520 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007521 if (!did_emsg)
7522 {
7523 s = alloc(len + 1);
7524 if (s != NULL)
7525 {
7526 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007527 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7528 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007529 }
7530 }
7531 did_emsg |= saved_did_emsg;
7532}
7533
7534/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007535 * "pum_getpos()" function
7536 */
7537 static void
7538f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7539{
7540 if (rettv_dict_alloc(rettv) != OK)
7541 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007542 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007543}
7544
7545/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007546 * "pumvisible()" function
7547 */
7548 static void
7549f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7550{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007551 if (pum_visible())
7552 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007553}
7554
7555#ifdef FEAT_PYTHON3
7556/*
7557 * "py3eval()" function
7558 */
7559 static void
7560f_py3eval(typval_T *argvars, typval_T *rettv)
7561{
7562 char_u *str;
7563 char_u buf[NUMBUFLEN];
7564
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007565 if (check_restricted() || check_secure())
7566 return;
7567
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007568 if (p_pyx == 0)
7569 p_pyx = 3;
7570
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007571 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007572 do_py3eval(str, rettv);
7573}
7574#endif
7575
7576#ifdef FEAT_PYTHON
7577/*
7578 * "pyeval()" function
7579 */
7580 static void
7581f_pyeval(typval_T *argvars, typval_T *rettv)
7582{
7583 char_u *str;
7584 char_u buf[NUMBUFLEN];
7585
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007586 if (check_restricted() || check_secure())
7587 return;
7588
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007589 if (p_pyx == 0)
7590 p_pyx = 2;
7591
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007592 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007593 do_pyeval(str, rettv);
7594}
7595#endif
7596
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007597#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7598/*
7599 * "pyxeval()" function
7600 */
7601 static void
7602f_pyxeval(typval_T *argvars, typval_T *rettv)
7603{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007604 if (check_restricted() || check_secure())
7605 return;
7606
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007607# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7608 init_pyxversion();
7609 if (p_pyx == 2)
7610 f_pyeval(argvars, rettv);
7611 else
7612 f_py3eval(argvars, rettv);
7613# elif defined(FEAT_PYTHON)
7614 f_pyeval(argvars, rettv);
7615# elif defined(FEAT_PYTHON3)
7616 f_py3eval(argvars, rettv);
7617# endif
7618}
7619#endif
7620
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007621/*
7622 * "range()" function
7623 */
7624 static void
7625f_range(typval_T *argvars, typval_T *rettv)
7626{
7627 varnumber_T start;
7628 varnumber_T end;
7629 varnumber_T stride = 1;
7630 varnumber_T i;
7631 int error = FALSE;
7632
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007633 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007634 if (argvars[1].v_type == VAR_UNKNOWN)
7635 {
7636 end = start - 1;
7637 start = 0;
7638 }
7639 else
7640 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007641 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007642 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007643 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007644 }
7645
7646 if (error)
7647 return; /* type error; errmsg already given */
7648 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007649 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007650 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007651 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007652 else
7653 {
7654 if (rettv_list_alloc(rettv) == OK)
7655 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7656 if (list_append_number(rettv->vval.v_list,
7657 (varnumber_T)i) == FAIL)
7658 break;
7659 }
7660}
7661
7662/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007663 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007664 */
7665 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007666readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007667{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007668 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007669 typval_T save_val;
7670 typval_T rettv;
7671 typval_T argv[2];
7672 int retval = 0;
7673 int error = FALSE;
7674
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007675 if (expr->v_type == VAR_UNKNOWN)
7676 return 1;
7677
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007678 prepare_vimvar(VV_VAL, &save_val);
7679 set_vim_var_string(VV_VAL, name, -1);
7680 argv[0].v_type = VAR_STRING;
7681 argv[0].vval.v_string = name;
7682
7683 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
7684 goto theend;
7685
7686 retval = tv_get_number_chk(&rettv, &error);
7687 if (error)
7688 retval = -1;
7689 clear_tv(&rettv);
7690
7691theend:
7692 set_vim_var_string(VV_VAL, NULL, 0);
7693 restore_vimvar(VV_VAL, &save_val);
7694 return retval;
7695}
7696
7697/*
7698 * "readdir()" function
7699 */
7700 static void
7701f_readdir(typval_T *argvars, typval_T *rettv)
7702{
7703 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007704 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007705 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007706 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007707 garray_T ga;
7708 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007709
7710 if (rettv_list_alloc(rettv) == FAIL)
7711 return;
7712 path = tv_get_string(&argvars[0]);
7713 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007714
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02007715 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
7716 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007717 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007718 for (i = 0; i < ga.ga_len; i++)
7719 {
7720 p = ((char_u **)ga.ga_data)[i];
7721 list_append_string(rettv->vval.v_list, p, -1);
7722 }
7723 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02007724 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02007725}
7726
7727/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007728 * "readfile()" function
7729 */
7730 static void
7731f_readfile(typval_T *argvars, typval_T *rettv)
7732{
7733 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007734 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007735 int failed = FALSE;
7736 char_u *fname;
7737 FILE *fd;
7738 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
7739 int io_size = sizeof(buf);
7740 int readlen; /* size of last fread() */
7741 char_u *prev = NULL; /* previously read bytes, if any */
7742 long prevlen = 0; /* length of data in prev */
7743 long prevsize = 0; /* size of prev buffer */
7744 long maxline = MAXLNUM;
7745 long cnt = 0;
7746 char_u *p; /* position in buf */
7747 char_u *start; /* start of current line */
7748
7749 if (argvars[1].v_type != VAR_UNKNOWN)
7750 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007751 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007752 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007753 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
7754 blob = TRUE;
7755
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007756 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007757 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007758 }
7759
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007760 if (blob)
7761 {
7762 if (rettv_blob_alloc(rettv) == FAIL)
7763 return;
7764 }
7765 else
7766 {
7767 if (rettv_list_alloc(rettv) == FAIL)
7768 return;
7769 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007770
7771 /* Always open the file in binary mode, library functions have a mind of
7772 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007773 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007774 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
7775 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007776 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777 return;
7778 }
7779
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007780 if (blob)
7781 {
7782 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
7783 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007784 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007785 blob_free(rettv->vval.v_blob);
7786 }
7787 fclose(fd);
7788 return;
7789 }
7790
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007791 while (cnt < maxline || maxline < 0)
7792 {
7793 readlen = (int)fread(buf, 1, io_size, fd);
7794
7795 /* This for loop processes what was read, but is also entered at end
7796 * of file so that either:
7797 * - an incomplete line gets written
7798 * - a "binary" file gets an empty line at the end if it ends in a
7799 * newline. */
7800 for (p = buf, start = buf;
7801 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
7802 ++p)
7803 {
7804 if (*p == '\n' || readlen <= 0)
7805 {
7806 listitem_T *li;
7807 char_u *s = NULL;
7808 long_u len = p - start;
7809
7810 /* Finished a line. Remove CRs before NL. */
7811 if (readlen > 0 && !binary)
7812 {
7813 while (len > 0 && start[len - 1] == '\r')
7814 --len;
7815 /* removal may cross back to the "prev" string */
7816 if (len == 0)
7817 while (prevlen > 0 && prev[prevlen - 1] == '\r')
7818 --prevlen;
7819 }
7820 if (prevlen == 0)
7821 s = vim_strnsave(start, (int)len);
7822 else
7823 {
7824 /* Change "prev" buffer to be the right size. This way
7825 * the bytes are only copied once, and very long lines are
7826 * allocated only once. */
7827 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
7828 {
7829 mch_memmove(s + prevlen, start, len);
7830 s[prevlen + len] = NUL;
7831 prev = NULL; /* the list will own the string */
7832 prevlen = prevsize = 0;
7833 }
7834 }
7835 if (s == NULL)
7836 {
7837 do_outofmem_msg((long_u) prevlen + len + 1);
7838 failed = TRUE;
7839 break;
7840 }
7841
7842 if ((li = listitem_alloc()) == NULL)
7843 {
7844 vim_free(s);
7845 failed = TRUE;
7846 break;
7847 }
7848 li->li_tv.v_type = VAR_STRING;
7849 li->li_tv.v_lock = 0;
7850 li->li_tv.vval.v_string = s;
7851 list_append(rettv->vval.v_list, li);
7852
7853 start = p + 1; /* step over newline */
7854 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
7855 break;
7856 }
7857 else if (*p == NUL)
7858 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007859 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
7860 * when finding the BF and check the previous two bytes. */
7861 else if (*p == 0xbf && enc_utf8 && !binary)
7862 {
7863 /* Find the two bytes before the 0xbf. If p is at buf, or buf
7864 * + 1, these may be in the "prev" string. */
7865 char_u back1 = p >= buf + 1 ? p[-1]
7866 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
7867 char_u back2 = p >= buf + 2 ? p[-2]
7868 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
7869 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
7870
7871 if (back2 == 0xef && back1 == 0xbb)
7872 {
7873 char_u *dest = p - 2;
7874
7875 /* Usually a BOM is at the beginning of a file, and so at
7876 * the beginning of a line; then we can just step over it.
7877 */
7878 if (start == dest)
7879 start = p + 1;
7880 else
7881 {
7882 /* have to shuffle buf to close gap */
7883 int adjust_prevlen = 0;
7884
7885 if (dest < buf)
7886 {
7887 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
7888 dest = buf;
7889 }
7890 if (readlen > p - buf + 1)
7891 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
7892 readlen -= 3 - adjust_prevlen;
7893 prevlen -= adjust_prevlen;
7894 p = dest - 1;
7895 }
7896 }
7897 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007898 } /* for */
7899
7900 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
7901 break;
7902 if (start < p)
7903 {
7904 /* There's part of a line in buf, store it in "prev". */
7905 if (p - start + prevlen >= prevsize)
7906 {
7907 /* need bigger "prev" buffer */
7908 char_u *newprev;
7909
7910 /* A common use case is ordinary text files and "prev" gets a
7911 * fragment of a line, so the first allocation is made
7912 * small, to avoid repeatedly 'allocing' large and
7913 * 'reallocing' small. */
7914 if (prevsize == 0)
7915 prevsize = (long)(p - start);
7916 else
7917 {
7918 long grow50pc = (prevsize * 3) / 2;
7919 long growmin = (long)((p - start) * 2 + prevlen);
7920 prevsize = grow50pc > growmin ? grow50pc : growmin;
7921 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02007922 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007923 if (newprev == NULL)
7924 {
7925 do_outofmem_msg((long_u)prevsize);
7926 failed = TRUE;
7927 break;
7928 }
7929 prev = newprev;
7930 }
7931 /* Add the line part to end of "prev". */
7932 mch_memmove(prev + prevlen, start, p - start);
7933 prevlen += (long)(p - start);
7934 }
7935 } /* while */
7936
7937 /*
7938 * For a negative line count use only the lines at the end of the file,
7939 * free the rest.
7940 */
7941 if (!failed && maxline < 0)
7942 while (cnt > -maxline)
7943 {
7944 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
7945 --cnt;
7946 }
7947
7948 if (failed)
7949 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02007950 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007951 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02007952 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007953 }
7954
7955 vim_free(prev);
7956 fclose(fd);
7957}
7958
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02007959 static void
7960return_register(int regname, typval_T *rettv)
7961{
7962 char_u buf[2] = {0, 0};
7963
7964 buf[0] = (char_u)regname;
7965 rettv->v_type = VAR_STRING;
7966 rettv->vval.v_string = vim_strsave(buf);
7967}
7968
7969/*
7970 * "reg_executing()" function
7971 */
7972 static void
7973f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
7974{
7975 return_register(reg_executing, rettv);
7976}
7977
7978/*
7979 * "reg_recording()" function
7980 */
7981 static void
7982f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
7983{
7984 return_register(reg_recording, rettv);
7985}
7986
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007987#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007988/*
7989 * Convert a List to proftime_T.
7990 * Return FAIL when there is something wrong.
7991 */
7992 static int
7993list2proftime(typval_T *arg, proftime_T *tm)
7994{
7995 long n1, n2;
7996 int error = FALSE;
7997
7998 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
7999 || arg->vval.v_list->lv_len != 2)
8000 return FAIL;
8001 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8002 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008003# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008004 tm->HighPart = n1;
8005 tm->LowPart = n2;
8006# else
8007 tm->tv_sec = n1;
8008 tm->tv_usec = n2;
8009# endif
8010 return error ? FAIL : OK;
8011}
8012#endif /* FEAT_RELTIME */
8013
8014/*
8015 * "reltime()" function
8016 */
8017 static void
8018f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8019{
8020#ifdef FEAT_RELTIME
8021 proftime_T res;
8022 proftime_T start;
8023
8024 if (argvars[0].v_type == VAR_UNKNOWN)
8025 {
8026 /* No arguments: get current time. */
8027 profile_start(&res);
8028 }
8029 else if (argvars[1].v_type == VAR_UNKNOWN)
8030 {
8031 if (list2proftime(&argvars[0], &res) == FAIL)
8032 return;
8033 profile_end(&res);
8034 }
8035 else
8036 {
8037 /* Two arguments: compute the difference. */
8038 if (list2proftime(&argvars[0], &start) == FAIL
8039 || list2proftime(&argvars[1], &res) == FAIL)
8040 return;
8041 profile_sub(&res, &start);
8042 }
8043
8044 if (rettv_list_alloc(rettv) == OK)
8045 {
8046 long n1, n2;
8047
Bram Moolenaar4f974752019-02-17 17:44:42 +01008048# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008049 n1 = res.HighPart;
8050 n2 = res.LowPart;
8051# else
8052 n1 = res.tv_sec;
8053 n2 = res.tv_usec;
8054# endif
8055 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8056 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8057 }
8058#endif
8059}
8060
8061#ifdef FEAT_FLOAT
8062/*
8063 * "reltimefloat()" function
8064 */
8065 static void
8066f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8067{
8068# ifdef FEAT_RELTIME
8069 proftime_T tm;
8070# endif
8071
8072 rettv->v_type = VAR_FLOAT;
8073 rettv->vval.v_float = 0;
8074# ifdef FEAT_RELTIME
8075 if (list2proftime(&argvars[0], &tm) == OK)
8076 rettv->vval.v_float = profile_float(&tm);
8077# endif
8078}
8079#endif
8080
8081/*
8082 * "reltimestr()" function
8083 */
8084 static void
8085f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8086{
8087#ifdef FEAT_RELTIME
8088 proftime_T tm;
8089#endif
8090
8091 rettv->v_type = VAR_STRING;
8092 rettv->vval.v_string = NULL;
8093#ifdef FEAT_RELTIME
8094 if (list2proftime(&argvars[0], &tm) == OK)
8095 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8096#endif
8097}
8098
8099#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008100 static void
8101make_connection(void)
8102{
8103 if (X_DISPLAY == NULL
8104# ifdef FEAT_GUI
8105 && !gui.in_use
8106# endif
8107 )
8108 {
8109 x_force_connect = TRUE;
8110 setup_term_clip();
8111 x_force_connect = FALSE;
8112 }
8113}
8114
8115 static int
8116check_connection(void)
8117{
8118 make_connection();
8119 if (X_DISPLAY == NULL)
8120 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008121 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008122 return FAIL;
8123 }
8124 return OK;
8125}
8126#endif
8127
8128#ifdef FEAT_CLIENTSERVER
8129 static void
8130remote_common(typval_T *argvars, typval_T *rettv, int expr)
8131{
8132 char_u *server_name;
8133 char_u *keys;
8134 char_u *r = NULL;
8135 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008136 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008137# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008138 HWND w;
8139# else
8140 Window w;
8141# endif
8142
8143 if (check_restricted() || check_secure())
8144 return;
8145
8146# ifdef FEAT_X11
8147 if (check_connection() == FAIL)
8148 return;
8149# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008150 if (argvars[2].v_type != VAR_UNKNOWN
8151 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008152 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008153
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008154 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008155 if (server_name == NULL)
8156 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008157 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008158# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008159 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008160# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008161 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8162 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008163# endif
8164 {
8165 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008166 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008167 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008168 vim_free(r);
8169 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008170 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008171 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008172 return;
8173 }
8174
8175 rettv->vval.v_string = r;
8176
8177 if (argvars[2].v_type != VAR_UNKNOWN)
8178 {
8179 dictitem_T v;
8180 char_u str[30];
8181 char_u *idvar;
8182
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008183 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008184 if (idvar != NULL && *idvar != NUL)
8185 {
8186 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8187 v.di_tv.v_type = VAR_STRING;
8188 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008189 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008190 vim_free(v.di_tv.vval.v_string);
8191 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008192 }
8193}
8194#endif
8195
8196/*
8197 * "remote_expr()" function
8198 */
8199 static void
8200f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8201{
8202 rettv->v_type = VAR_STRING;
8203 rettv->vval.v_string = NULL;
8204#ifdef FEAT_CLIENTSERVER
8205 remote_common(argvars, rettv, TRUE);
8206#endif
8207}
8208
8209/*
8210 * "remote_foreground()" function
8211 */
8212 static void
8213f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8214{
8215#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008216# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008217 /* On Win32 it's done in this application. */
8218 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008219 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008220
8221 if (server_name != NULL)
8222 serverForeground(server_name);
8223 }
8224# else
8225 /* Send a foreground() expression to the server. */
8226 argvars[1].v_type = VAR_STRING;
8227 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8228 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008229 rettv->v_type = VAR_STRING;
8230 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008231 remote_common(argvars, rettv, TRUE);
8232 vim_free(argvars[1].vval.v_string);
8233# endif
8234#endif
8235}
8236
8237 static void
8238f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8239{
8240#ifdef FEAT_CLIENTSERVER
8241 dictitem_T v;
8242 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008243# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008244 long_u n = 0;
8245# endif
8246 char_u *serverid;
8247
8248 if (check_restricted() || check_secure())
8249 {
8250 rettv->vval.v_number = -1;
8251 return;
8252 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008253 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008254 if (serverid == NULL)
8255 {
8256 rettv->vval.v_number = -1;
8257 return; /* type error; errmsg already given */
8258 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008259# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008260 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8261 if (n == 0)
8262 rettv->vval.v_number = -1;
8263 else
8264 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008265 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008266 rettv->vval.v_number = (s != NULL);
8267 }
8268# else
8269 if (check_connection() == FAIL)
8270 return;
8271
8272 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8273 serverStrToWin(serverid), &s);
8274# endif
8275
8276 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8277 {
8278 char_u *retvar;
8279
8280 v.di_tv.v_type = VAR_STRING;
8281 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008282 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008283 if (retvar != NULL)
8284 set_var(retvar, &v.di_tv, FALSE);
8285 vim_free(v.di_tv.vval.v_string);
8286 }
8287#else
8288 rettv->vval.v_number = -1;
8289#endif
8290}
8291
8292 static void
8293f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8294{
8295 char_u *r = NULL;
8296
8297#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008298 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008299
8300 if (serverid != NULL && !check_restricted() && !check_secure())
8301 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008302 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008303# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008304 /* The server's HWND is encoded in the 'id' parameter */
8305 long_u n = 0;
8306# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008307
8308 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008309 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008310
Bram Moolenaar4f974752019-02-17 17:44:42 +01008311# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008312 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8313 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008314 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008315 if (r == NULL)
8316# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008317 if (check_connection() == FAIL
8318 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8319 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008320# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008321 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008322 }
8323#endif
8324 rettv->v_type = VAR_STRING;
8325 rettv->vval.v_string = r;
8326}
8327
8328/*
8329 * "remote_send()" function
8330 */
8331 static void
8332f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8333{
8334 rettv->v_type = VAR_STRING;
8335 rettv->vval.v_string = NULL;
8336#ifdef FEAT_CLIENTSERVER
8337 remote_common(argvars, rettv, FALSE);
8338#endif
8339}
8340
8341/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008342 * "remote_startserver()" function
8343 */
8344 static void
8345f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8346{
8347#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008348 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008349
8350 if (server == NULL)
8351 return; /* type error; errmsg already given */
8352 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008353 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008354 else
8355 {
8356# ifdef FEAT_X11
8357 if (check_connection() == OK)
8358 serverRegisterName(X_DISPLAY, server);
8359# else
8360 serverSetName(server);
8361# endif
8362 }
8363#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008364 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008365#endif
8366}
8367
8368/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008369 * "remove()" function
8370 */
8371 static void
8372f_remove(typval_T *argvars, typval_T *rettv)
8373{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008374 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8375
8376 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008377 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008378 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008379 blob_remove(argvars, rettv);
8380 else if (argvars[0].v_type == VAR_LIST)
8381 list_remove(argvars, rettv, arg_errmsg);
8382 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008383 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008384}
8385
8386/*
8387 * "rename({from}, {to})" function
8388 */
8389 static void
8390f_rename(typval_T *argvars, typval_T *rettv)
8391{
8392 char_u buf[NUMBUFLEN];
8393
8394 if (check_restricted() || check_secure())
8395 rettv->vval.v_number = -1;
8396 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008397 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8398 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008399}
8400
8401/*
8402 * "repeat()" function
8403 */
8404 static void
8405f_repeat(typval_T *argvars, typval_T *rettv)
8406{
8407 char_u *p;
8408 int n;
8409 int slen;
8410 int len;
8411 char_u *r;
8412 int i;
8413
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008414 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008415 if (argvars[0].v_type == VAR_LIST)
8416 {
8417 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8418 while (n-- > 0)
8419 if (list_extend(rettv->vval.v_list,
8420 argvars[0].vval.v_list, NULL) == FAIL)
8421 break;
8422 }
8423 else
8424 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008425 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008426 rettv->v_type = VAR_STRING;
8427 rettv->vval.v_string = NULL;
8428
8429 slen = (int)STRLEN(p);
8430 len = slen * n;
8431 if (len <= 0)
8432 return;
8433
8434 r = alloc(len + 1);
8435 if (r != NULL)
8436 {
8437 for (i = 0; i < n; i++)
8438 mch_memmove(r + i * slen, p, (size_t)slen);
8439 r[len] = NUL;
8440 }
8441
8442 rettv->vval.v_string = r;
8443 }
8444}
8445
8446/*
8447 * "resolve()" function
8448 */
8449 static void
8450f_resolve(typval_T *argvars, typval_T *rettv)
8451{
8452 char_u *p;
8453#ifdef HAVE_READLINK
8454 char_u *buf = NULL;
8455#endif
8456
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008457 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008458#ifdef FEAT_SHORTCUT
8459 {
8460 char_u *v = NULL;
8461
Bram Moolenaardce1e892019-02-10 23:18:53 +01008462 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008463 if (v != NULL)
8464 rettv->vval.v_string = v;
8465 else
8466 rettv->vval.v_string = vim_strsave(p);
8467 }
8468#else
8469# ifdef HAVE_READLINK
8470 {
8471 char_u *cpy;
8472 int len;
8473 char_u *remain = NULL;
8474 char_u *q;
8475 int is_relative_to_current = FALSE;
8476 int has_trailing_pathsep = FALSE;
8477 int limit = 100;
8478
8479 p = vim_strsave(p);
8480
8481 if (p[0] == '.' && (vim_ispathsep(p[1])
8482 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8483 is_relative_to_current = TRUE;
8484
8485 len = STRLEN(p);
8486 if (len > 0 && after_pathsep(p, p + len))
8487 {
8488 has_trailing_pathsep = TRUE;
8489 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8490 }
8491
8492 q = getnextcomp(p);
8493 if (*q != NUL)
8494 {
8495 /* Separate the first path component in "p", and keep the
8496 * remainder (beginning with the path separator). */
8497 remain = vim_strsave(q - 1);
8498 q[-1] = NUL;
8499 }
8500
8501 buf = alloc(MAXPATHL + 1);
8502 if (buf == NULL)
8503 goto fail;
8504
8505 for (;;)
8506 {
8507 for (;;)
8508 {
8509 len = readlink((char *)p, (char *)buf, MAXPATHL);
8510 if (len <= 0)
8511 break;
8512 buf[len] = NUL;
8513
8514 if (limit-- == 0)
8515 {
8516 vim_free(p);
8517 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008518 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008519 rettv->vval.v_string = NULL;
8520 goto fail;
8521 }
8522
8523 /* Ensure that the result will have a trailing path separator
8524 * if the argument has one. */
8525 if (remain == NULL && has_trailing_pathsep)
8526 add_pathsep(buf);
8527
8528 /* Separate the first path component in the link value and
8529 * concatenate the remainders. */
8530 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8531 if (*q != NUL)
8532 {
8533 if (remain == NULL)
8534 remain = vim_strsave(q - 1);
8535 else
8536 {
8537 cpy = concat_str(q - 1, remain);
8538 if (cpy != NULL)
8539 {
8540 vim_free(remain);
8541 remain = cpy;
8542 }
8543 }
8544 q[-1] = NUL;
8545 }
8546
8547 q = gettail(p);
8548 if (q > p && *q == NUL)
8549 {
8550 /* Ignore trailing path separator. */
8551 q[-1] = NUL;
8552 q = gettail(p);
8553 }
8554 if (q > p && !mch_isFullName(buf))
8555 {
8556 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02008557 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008558 if (cpy != NULL)
8559 {
8560 STRCPY(cpy, p);
8561 STRCPY(gettail(cpy), buf);
8562 vim_free(p);
8563 p = cpy;
8564 }
8565 }
8566 else
8567 {
8568 vim_free(p);
8569 p = vim_strsave(buf);
8570 }
8571 }
8572
8573 if (remain == NULL)
8574 break;
8575
8576 /* Append the first path component of "remain" to "p". */
8577 q = getnextcomp(remain + 1);
8578 len = q - remain - (*q != NUL);
8579 cpy = vim_strnsave(p, STRLEN(p) + len);
8580 if (cpy != NULL)
8581 {
8582 STRNCAT(cpy, remain, len);
8583 vim_free(p);
8584 p = cpy;
8585 }
8586 /* Shorten "remain". */
8587 if (*q != NUL)
8588 STRMOVE(remain, q - 1);
8589 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01008590 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008591 }
8592
8593 /* If the result is a relative path name, make it explicitly relative to
8594 * the current directory if and only if the argument had this form. */
8595 if (!vim_ispathsep(*p))
8596 {
8597 if (is_relative_to_current
8598 && *p != NUL
8599 && !(p[0] == '.'
8600 && (p[1] == NUL
8601 || vim_ispathsep(p[1])
8602 || (p[1] == '.'
8603 && (p[2] == NUL
8604 || vim_ispathsep(p[2]))))))
8605 {
8606 /* Prepend "./". */
8607 cpy = concat_str((char_u *)"./", p);
8608 if (cpy != NULL)
8609 {
8610 vim_free(p);
8611 p = cpy;
8612 }
8613 }
8614 else if (!is_relative_to_current)
8615 {
8616 /* Strip leading "./". */
8617 q = p;
8618 while (q[0] == '.' && vim_ispathsep(q[1]))
8619 q += 2;
8620 if (q > p)
8621 STRMOVE(p, p + 2);
8622 }
8623 }
8624
8625 /* Ensure that the result will have no trailing path separator
8626 * if the argument had none. But keep "/" or "//". */
8627 if (!has_trailing_pathsep)
8628 {
8629 q = p + STRLEN(p);
8630 if (after_pathsep(p, q))
8631 *gettail_sep(p) = NUL;
8632 }
8633
8634 rettv->vval.v_string = p;
8635 }
8636# else
8637 rettv->vval.v_string = vim_strsave(p);
8638# endif
8639#endif
8640
8641 simplify_filename(rettv->vval.v_string);
8642
8643#ifdef HAVE_READLINK
8644fail:
8645 vim_free(buf);
8646#endif
8647 rettv->v_type = VAR_STRING;
8648}
8649
8650/*
8651 * "reverse({list})" function
8652 */
8653 static void
8654f_reverse(typval_T *argvars, typval_T *rettv)
8655{
8656 list_T *l;
8657 listitem_T *li, *ni;
8658
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008659 if (argvars[0].v_type == VAR_BLOB)
8660 {
8661 blob_T *b = argvars[0].vval.v_blob;
8662 int i, len = blob_len(b);
8663
8664 for (i = 0; i < len / 2; i++)
8665 {
8666 int tmp = blob_get(b, i);
8667
8668 blob_set(b, i, blob_get(b, len - i - 1));
8669 blob_set(b, len - i - 1, tmp);
8670 }
8671 rettv_blob_set(rettv, b);
8672 return;
8673 }
8674
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008675 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008676 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008677 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01008678 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008679 (char_u *)N_("reverse() argument"), TRUE))
8680 {
8681 li = l->lv_last;
8682 l->lv_first = l->lv_last = NULL;
8683 l->lv_len = 0;
8684 while (li != NULL)
8685 {
8686 ni = li->li_prev;
8687 list_append(l, li);
8688 li = ni;
8689 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02008690 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008691 l->lv_idx = l->lv_len - l->lv_idx - 1;
8692 }
8693}
8694
8695#define SP_NOMOVE 0x01 /* don't move cursor */
8696#define SP_REPEAT 0x02 /* repeat to find outer pair */
8697#define SP_RETCOUNT 0x04 /* return matchcount */
8698#define SP_SETPCMARK 0x08 /* set previous context mark */
8699#define SP_START 0x10 /* accept match at start position */
8700#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
8701#define SP_END 0x40 /* leave cursor at end of match */
8702#define SP_COLUMN 0x80 /* start at cursor column */
8703
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008704/*
8705 * Get flags for a search function.
8706 * Possibly sets "p_ws".
8707 * Returns BACKWARD, FORWARD or zero (for an error).
8708 */
8709 static int
8710get_search_arg(typval_T *varp, int *flagsp)
8711{
8712 int dir = FORWARD;
8713 char_u *flags;
8714 char_u nbuf[NUMBUFLEN];
8715 int mask;
8716
8717 if (varp->v_type != VAR_UNKNOWN)
8718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008719 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008720 if (flags == NULL)
8721 return 0; /* type error; errmsg already given */
8722 while (*flags != NUL)
8723 {
8724 switch (*flags)
8725 {
8726 case 'b': dir = BACKWARD; break;
8727 case 'w': p_ws = TRUE; break;
8728 case 'W': p_ws = FALSE; break;
8729 default: mask = 0;
8730 if (flagsp != NULL)
8731 switch (*flags)
8732 {
8733 case 'c': mask = SP_START; break;
8734 case 'e': mask = SP_END; break;
8735 case 'm': mask = SP_RETCOUNT; break;
8736 case 'n': mask = SP_NOMOVE; break;
8737 case 'p': mask = SP_SUBPAT; break;
8738 case 'r': mask = SP_REPEAT; break;
8739 case 's': mask = SP_SETPCMARK; break;
8740 case 'z': mask = SP_COLUMN; break;
8741 }
8742 if (mask == 0)
8743 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008744 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008745 dir = 0;
8746 }
8747 else
8748 *flagsp |= mask;
8749 }
8750 if (dir == 0)
8751 break;
8752 ++flags;
8753 }
8754 }
8755 return dir;
8756}
8757
8758/*
8759 * Shared by search() and searchpos() functions.
8760 */
8761 static int
8762search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
8763{
8764 int flags;
8765 char_u *pat;
8766 pos_T pos;
8767 pos_T save_cursor;
8768 int save_p_ws = p_ws;
8769 int dir;
8770 int retval = 0; /* default: FAIL */
8771 long lnum_stop = 0;
8772 proftime_T tm;
8773#ifdef FEAT_RELTIME
8774 long time_limit = 0;
8775#endif
8776 int options = SEARCH_KEEP;
8777 int subpatnum;
8778
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008779 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008780 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
8781 if (dir == 0)
8782 goto theend;
8783 flags = *flagsp;
8784 if (flags & SP_START)
8785 options |= SEARCH_START;
8786 if (flags & SP_END)
8787 options |= SEARCH_END;
8788 if (flags & SP_COLUMN)
8789 options |= SEARCH_COL;
8790
8791 /* Optional arguments: line number to stop searching and timeout. */
8792 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
8793 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008794 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008795 if (lnum_stop < 0)
8796 goto theend;
8797#ifdef FEAT_RELTIME
8798 if (argvars[3].v_type != VAR_UNKNOWN)
8799 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008800 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008801 if (time_limit < 0)
8802 goto theend;
8803 }
8804#endif
8805 }
8806
8807#ifdef FEAT_RELTIME
8808 /* Set the time limit, if there is one. */
8809 profile_setlimit(time_limit, &tm);
8810#endif
8811
8812 /*
8813 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
8814 * Check to make sure only those flags are set.
8815 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
8816 * flags cannot be set. Check for that condition also.
8817 */
8818 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
8819 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
8820 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008821 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008822 goto theend;
8823 }
8824
8825 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01008826 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02008827 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008828 if (subpatnum != FAIL)
8829 {
8830 if (flags & SP_SUBPAT)
8831 retval = subpatnum;
8832 else
8833 retval = pos.lnum;
8834 if (flags & SP_SETPCMARK)
8835 setpcmark();
8836 curwin->w_cursor = pos;
8837 if (match_pos != NULL)
8838 {
8839 /* Store the match cursor position */
8840 match_pos->lnum = pos.lnum;
8841 match_pos->col = pos.col + 1;
8842 }
8843 /* "/$" will put the cursor after the end of the line, may need to
8844 * correct that here */
8845 check_cursor();
8846 }
8847
8848 /* If 'n' flag is used: restore cursor position. */
8849 if (flags & SP_NOMOVE)
8850 curwin->w_cursor = save_cursor;
8851 else
8852 curwin->w_set_curswant = TRUE;
8853theend:
8854 p_ws = save_p_ws;
8855
8856 return retval;
8857}
8858
8859#ifdef FEAT_FLOAT
8860
8861/*
8862 * round() is not in C90, use ceil() or floor() instead.
8863 */
8864 float_T
8865vim_round(float_T f)
8866{
8867 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
8868}
8869
8870/*
8871 * "round({float})" function
8872 */
8873 static void
8874f_round(typval_T *argvars, typval_T *rettv)
8875{
8876 float_T f = 0.0;
8877
8878 rettv->v_type = VAR_FLOAT;
8879 if (get_float_arg(argvars, &f) == OK)
8880 rettv->vval.v_float = vim_round(f);
8881 else
8882 rettv->vval.v_float = 0.0;
8883}
8884#endif
8885
Bram Moolenaare99be0e2019-03-26 22:51:09 +01008886#ifdef FEAT_RUBY
8887/*
8888 * "rubyeval()" function
8889 */
8890 static void
8891f_rubyeval(typval_T *argvars, typval_T *rettv)
8892{
8893 char_u *str;
8894 char_u buf[NUMBUFLEN];
8895
8896 str = tv_get_string_buf(&argvars[0], buf);
8897 do_rubyeval(str, rettv);
8898}
8899#endif
8900
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008901/*
8902 * "screenattr()" function
8903 */
8904 static void
8905f_screenattr(typval_T *argvars, typval_T *rettv)
8906{
8907 int row;
8908 int col;
8909 int c;
8910
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008911 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8912 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008913 if (row < 0 || row >= screen_Rows
8914 || col < 0 || col >= screen_Columns)
8915 c = -1;
8916 else
8917 c = ScreenAttrs[LineOffset[row] + col];
8918 rettv->vval.v_number = c;
8919}
8920
8921/*
8922 * "screenchar()" function
8923 */
8924 static void
8925f_screenchar(typval_T *argvars, typval_T *rettv)
8926{
8927 int row;
8928 int col;
8929 int off;
8930 int c;
8931
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008932 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8933 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01008934 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008935 c = -1;
8936 else
8937 {
8938 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008939 if (enc_utf8 && ScreenLinesUC[off] != 0)
8940 c = ScreenLinesUC[off];
8941 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008942 c = ScreenLines[off];
8943 }
8944 rettv->vval.v_number = c;
8945}
8946
8947/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01008948 * "screenchars()" function
8949 */
8950 static void
8951f_screenchars(typval_T *argvars, typval_T *rettv)
8952{
8953 int row;
8954 int col;
8955 int off;
8956 int c;
8957 int i;
8958
8959 if (rettv_list_alloc(rettv) == FAIL)
8960 return;
8961 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
8962 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
8963 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
8964 return;
8965
8966 off = LineOffset[row] + col;
8967 if (enc_utf8 && ScreenLinesUC[off] != 0)
8968 c = ScreenLinesUC[off];
8969 else
8970 c = ScreenLines[off];
8971 list_append_number(rettv->vval.v_list, (varnumber_T)c);
8972
8973 if (enc_utf8)
8974
8975 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
8976 list_append_number(rettv->vval.v_list,
8977 (varnumber_T)ScreenLinesC[i][off]);
8978}
8979
8980/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008981 * "screencol()" function
8982 *
8983 * First column is 1 to be consistent with virtcol().
8984 */
8985 static void
8986f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
8987{
8988 rettv->vval.v_number = screen_screencol() + 1;
8989}
8990
8991/*
8992 * "screenrow()" function
8993 */
8994 static void
8995f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
8996{
8997 rettv->vval.v_number = screen_screenrow() + 1;
8998}
8999
9000/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009001 * "screenstring()" function
9002 */
9003 static void
9004f_screenstring(typval_T *argvars, typval_T *rettv)
9005{
9006 int row;
9007 int col;
9008 int off;
9009 int c;
9010 int i;
9011 char_u buf[MB_MAXBYTES + 1];
9012 int buflen = 0;
9013
9014 rettv->vval.v_string = NULL;
9015 rettv->v_type = VAR_STRING;
9016
9017 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9018 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9019 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9020 return;
9021
9022 off = LineOffset[row] + col;
9023 if (enc_utf8 && ScreenLinesUC[off] != 0)
9024 c = ScreenLinesUC[off];
9025 else
9026 c = ScreenLines[off];
9027 buflen += mb_char2bytes(c, buf);
9028
9029 if (enc_utf8)
9030 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9031 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9032
9033 buf[buflen] = NUL;
9034 rettv->vval.v_string = vim_strsave(buf);
9035}
9036
9037/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009038 * "search()" function
9039 */
9040 static void
9041f_search(typval_T *argvars, typval_T *rettv)
9042{
9043 int flags = 0;
9044
9045 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9046}
9047
9048/*
9049 * "searchdecl()" function
9050 */
9051 static void
9052f_searchdecl(typval_T *argvars, typval_T *rettv)
9053{
9054 int locally = 1;
9055 int thisblock = 0;
9056 int error = FALSE;
9057 char_u *name;
9058
9059 rettv->vval.v_number = 1; /* default: FAIL */
9060
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009061 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009062 if (argvars[1].v_type != VAR_UNKNOWN)
9063 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009064 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009065 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009066 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009067 }
9068 if (!error && name != NULL)
9069 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9070 locally, thisblock, SEARCH_KEEP) == FAIL;
9071}
9072
9073/*
9074 * Used by searchpair() and searchpairpos()
9075 */
9076 static int
9077searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9078{
9079 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009080 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009081 int save_p_ws = p_ws;
9082 int dir;
9083 int flags = 0;
9084 char_u nbuf1[NUMBUFLEN];
9085 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009086 int retval = 0; /* default: FAIL */
9087 long lnum_stop = 0;
9088 long time_limit = 0;
9089
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009090 /* Get the three pattern arguments: start, middle, end. Will result in an
9091 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009092 spat = tv_get_string_chk(&argvars[0]);
9093 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9094 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009095 if (spat == NULL || mpat == NULL || epat == NULL)
9096 goto theend; /* type error */
9097
9098 /* Handle the optional fourth argument: flags */
9099 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9100 if (dir == 0)
9101 goto theend;
9102
9103 /* Don't accept SP_END or SP_SUBPAT.
9104 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9105 */
9106 if ((flags & (SP_END | SP_SUBPAT)) != 0
9107 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9108 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009109 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009110 goto theend;
9111 }
9112
9113 /* Using 'r' implies 'W', otherwise it doesn't work. */
9114 if (flags & SP_REPEAT)
9115 p_ws = FALSE;
9116
9117 /* Optional fifth argument: skip expression */
9118 if (argvars[3].v_type == VAR_UNKNOWN
9119 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009120 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009121 else
9122 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009123 skip = &argvars[4];
9124 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9125 && skip->v_type != VAR_STRING)
9126 {
9127 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009128 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009129 goto theend;
9130 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009131 if (argvars[5].v_type != VAR_UNKNOWN)
9132 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009133 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009134 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009135 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009136 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009137 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009138 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009139#ifdef FEAT_RELTIME
9140 if (argvars[6].v_type != VAR_UNKNOWN)
9141 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009142 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009143 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009144 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009145 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009146 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009147 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009148 }
9149#endif
9150 }
9151 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009152
9153 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9154 match_pos, lnum_stop, time_limit);
9155
9156theend:
9157 p_ws = save_p_ws;
9158
9159 return retval;
9160}
9161
9162/*
9163 * "searchpair()" function
9164 */
9165 static void
9166f_searchpair(typval_T *argvars, typval_T *rettv)
9167{
9168 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9169}
9170
9171/*
9172 * "searchpairpos()" function
9173 */
9174 static void
9175f_searchpairpos(typval_T *argvars, typval_T *rettv)
9176{
9177 pos_T match_pos;
9178 int lnum = 0;
9179 int col = 0;
9180
9181 if (rettv_list_alloc(rettv) == FAIL)
9182 return;
9183
9184 if (searchpair_cmn(argvars, &match_pos) > 0)
9185 {
9186 lnum = match_pos.lnum;
9187 col = match_pos.col;
9188 }
9189
9190 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9191 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9192}
9193
9194/*
9195 * Search for a start/middle/end thing.
9196 * Used by searchpair(), see its documentation for the details.
9197 * Returns 0 or -1 for no match,
9198 */
9199 long
9200do_searchpair(
9201 char_u *spat, /* start pattern */
9202 char_u *mpat, /* middle pattern */
9203 char_u *epat, /* end pattern */
9204 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009205 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009206 int flags, /* SP_SETPCMARK and other SP_ values */
9207 pos_T *match_pos,
9208 linenr_T lnum_stop, /* stop at this line if not zero */
9209 long time_limit UNUSED) /* stop after this many msec */
9210{
9211 char_u *save_cpo;
9212 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9213 long retval = 0;
9214 pos_T pos;
9215 pos_T firstpos;
9216 pos_T foundpos;
9217 pos_T save_cursor;
9218 pos_T save_pos;
9219 int n;
9220 int r;
9221 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009222 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009223 int err;
9224 int options = SEARCH_KEEP;
9225 proftime_T tm;
9226
9227 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9228 save_cpo = p_cpo;
9229 p_cpo = empty_option;
9230
9231#ifdef FEAT_RELTIME
9232 /* Set the time limit, if there is one. */
9233 profile_setlimit(time_limit, &tm);
9234#endif
9235
9236 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9237 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009238 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9239 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009240 if (pat2 == NULL || pat3 == NULL)
9241 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009242 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009243 if (*mpat == NUL)
9244 STRCPY(pat3, pat2);
9245 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009246 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009247 spat, epat, mpat);
9248 if (flags & SP_START)
9249 options |= SEARCH_START;
9250
Bram Moolenaar48570482017-10-30 21:48:41 +01009251 if (skip != NULL)
9252 {
9253 /* Empty string means to not use the skip expression. */
9254 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9255 use_skip = skip->vval.v_string != NULL
9256 && *skip->vval.v_string != NUL;
9257 }
9258
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009259 save_cursor = curwin->w_cursor;
9260 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009261 CLEAR_POS(&firstpos);
9262 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009263 pat = pat3;
9264 for (;;)
9265 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009266 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009267 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009268 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009269 /* didn't find it or found the first match again: FAIL */
9270 break;
9271
9272 if (firstpos.lnum == 0)
9273 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009274 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009275 {
9276 /* Found the same position again. Can happen with a pattern that
9277 * has "\zs" at the end and searching backwards. Advance one
9278 * character and try again. */
9279 if (dir == BACKWARD)
9280 decl(&pos);
9281 else
9282 incl(&pos);
9283 }
9284 foundpos = pos;
9285
9286 /* clear the start flag to avoid getting stuck here */
9287 options &= ~SEARCH_START;
9288
9289 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009290 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009291 {
9292 save_pos = curwin->w_cursor;
9293 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009294 err = FALSE;
9295 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009296 curwin->w_cursor = save_pos;
9297 if (err)
9298 {
9299 /* Evaluating {skip} caused an error, break here. */
9300 curwin->w_cursor = save_cursor;
9301 retval = -1;
9302 break;
9303 }
9304 if (r)
9305 continue;
9306 }
9307
9308 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9309 {
9310 /* Found end when searching backwards or start when searching
9311 * forward: nested pair. */
9312 ++nest;
9313 pat = pat2; /* nested, don't search for middle */
9314 }
9315 else
9316 {
9317 /* Found end when searching forward or start when searching
9318 * backward: end of (nested) pair; or found middle in outer pair. */
9319 if (--nest == 1)
9320 pat = pat3; /* outer level, search for middle */
9321 }
9322
9323 if (nest == 0)
9324 {
9325 /* Found the match: return matchcount or line number. */
9326 if (flags & SP_RETCOUNT)
9327 ++retval;
9328 else
9329 retval = pos.lnum;
9330 if (flags & SP_SETPCMARK)
9331 setpcmark();
9332 curwin->w_cursor = pos;
9333 if (!(flags & SP_REPEAT))
9334 break;
9335 nest = 1; /* search for next unmatched */
9336 }
9337 }
9338
9339 if (match_pos != NULL)
9340 {
9341 /* Store the match cursor position */
9342 match_pos->lnum = curwin->w_cursor.lnum;
9343 match_pos->col = curwin->w_cursor.col + 1;
9344 }
9345
9346 /* If 'n' flag is used or search failed: restore cursor position. */
9347 if ((flags & SP_NOMOVE) || retval == 0)
9348 curwin->w_cursor = save_cursor;
9349
9350theend:
9351 vim_free(pat2);
9352 vim_free(pat3);
9353 if (p_cpo == empty_option)
9354 p_cpo = save_cpo;
9355 else
9356 /* Darn, evaluating the {skip} expression changed the value. */
9357 free_string_option(save_cpo);
9358
9359 return retval;
9360}
9361
9362/*
9363 * "searchpos()" function
9364 */
9365 static void
9366f_searchpos(typval_T *argvars, typval_T *rettv)
9367{
9368 pos_T match_pos;
9369 int lnum = 0;
9370 int col = 0;
9371 int n;
9372 int flags = 0;
9373
9374 if (rettv_list_alloc(rettv) == FAIL)
9375 return;
9376
9377 n = search_cmn(argvars, &match_pos, &flags);
9378 if (n > 0)
9379 {
9380 lnum = match_pos.lnum;
9381 col = match_pos.col;
9382 }
9383
9384 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9385 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9386 if (flags & SP_SUBPAT)
9387 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9388}
9389
9390 static void
9391f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9392{
9393#ifdef FEAT_CLIENTSERVER
9394 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009395 char_u *server = tv_get_string_chk(&argvars[0]);
9396 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009397
9398 rettv->vval.v_number = -1;
9399 if (server == NULL || reply == NULL)
9400 return;
9401 if (check_restricted() || check_secure())
9402 return;
9403# ifdef FEAT_X11
9404 if (check_connection() == FAIL)
9405 return;
9406# endif
9407
9408 if (serverSendReply(server, reply) < 0)
9409 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009410 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009411 return;
9412 }
9413 rettv->vval.v_number = 0;
9414#else
9415 rettv->vval.v_number = -1;
9416#endif
9417}
9418
9419 static void
9420f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9421{
9422 char_u *r = NULL;
9423
9424#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009425# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009426 r = serverGetVimNames();
9427# else
9428 make_connection();
9429 if (X_DISPLAY != NULL)
9430 r = serverGetVimNames(X_DISPLAY);
9431# endif
9432#endif
9433 rettv->v_type = VAR_STRING;
9434 rettv->vval.v_string = r;
9435}
9436
9437/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009438 * "setbufline()" function
9439 */
9440 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009441f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009442{
9443 linenr_T lnum;
9444 buf_T *buf;
9445
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009446 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009447 if (buf == NULL)
9448 rettv->vval.v_number = 1; /* FAIL */
9449 else
9450 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009451 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009452 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009453 }
9454}
9455
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009456 static void
9457f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9458{
9459 dict_T *d;
9460 dictitem_T *di;
9461 char_u *csearch;
9462
9463 if (argvars[0].v_type != VAR_DICT)
9464 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009465 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009466 return;
9467 }
9468
9469 if ((d = argvars[0].vval.v_dict) != NULL)
9470 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01009471 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009472 if (csearch != NULL)
9473 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009474 if (enc_utf8)
9475 {
9476 int pcc[MAX_MCO];
9477 int c = utfc_ptr2char(csearch, pcc);
9478
9479 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9480 }
9481 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009482 set_last_csearch(PTR2CHAR(csearch),
9483 csearch, MB_PTR2LEN(csearch));
9484 }
9485
9486 di = dict_find(d, (char_u *)"forward", -1);
9487 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009488 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009489 ? FORWARD : BACKWARD);
9490
9491 di = dict_find(d, (char_u *)"until", -1);
9492 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009493 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009494 }
9495}
9496
9497/*
9498 * "setcmdpos()" function
9499 */
9500 static void
9501f_setcmdpos(typval_T *argvars, typval_T *rettv)
9502{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009503 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009504
9505 if (pos >= 0)
9506 rettv->vval.v_number = set_cmdline_pos(pos);
9507}
9508
9509/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02009510 * "setenv()" function
9511 */
9512 static void
9513f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
9514{
9515 char_u namebuf[NUMBUFLEN];
9516 char_u valbuf[NUMBUFLEN];
9517 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
9518
9519 if (argvars[1].v_type == VAR_SPECIAL
9520 && argvars[1].vval.v_number == VVAL_NULL)
9521 vim_unsetenv(name);
9522 else
9523 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
9524}
9525
9526/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009527 * "setfperm({fname}, {mode})" function
9528 */
9529 static void
9530f_setfperm(typval_T *argvars, typval_T *rettv)
9531{
9532 char_u *fname;
9533 char_u modebuf[NUMBUFLEN];
9534 char_u *mode_str;
9535 int i;
9536 int mask;
9537 int mode = 0;
9538
9539 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009540 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009541 if (fname == NULL)
9542 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009543 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009544 if (mode_str == NULL)
9545 return;
9546 if (STRLEN(mode_str) != 9)
9547 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009548 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009549 return;
9550 }
9551
9552 mask = 1;
9553 for (i = 8; i >= 0; --i)
9554 {
9555 if (mode_str[i] != '-')
9556 mode |= mask;
9557 mask = mask << 1;
9558 }
9559 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9560}
9561
9562/*
9563 * "setline()" function
9564 */
9565 static void
9566f_setline(typval_T *argvars, typval_T *rettv)
9567{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009568 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009569
Bram Moolenaarca851592018-06-06 21:04:07 +02009570 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009571}
9572
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009573/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009574 * "setpos()" function
9575 */
9576 static void
9577f_setpos(typval_T *argvars, typval_T *rettv)
9578{
9579 pos_T pos;
9580 int fnum;
9581 char_u *name;
9582 colnr_T curswant = -1;
9583
9584 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009585 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009586 if (name != NULL)
9587 {
9588 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
9589 {
9590 if (--pos.col < 0)
9591 pos.col = 0;
9592 if (name[0] == '.' && name[1] == NUL)
9593 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01009594 /* set cursor; "fnum" is ignored */
9595 curwin->w_cursor = pos;
9596 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009597 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01009598 curwin->w_curswant = curswant - 1;
9599 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009600 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +01009601 check_cursor();
9602 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009603 }
9604 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
9605 {
9606 /* set mark */
9607 if (setmark_pos(name[1], &pos, fnum) == OK)
9608 rettv->vval.v_number = 0;
9609 }
9610 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009611 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009612 }
9613 }
9614}
9615
9616/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009617 * "setreg()" function
9618 */
9619 static void
9620f_setreg(typval_T *argvars, typval_T *rettv)
9621{
9622 int regname;
9623 char_u *strregname;
9624 char_u *stropt;
9625 char_u *strval;
9626 int append;
9627 char_u yank_type;
9628 long block_len;
9629
9630 block_len = -1;
9631 yank_type = MAUTO;
9632 append = FALSE;
9633
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009634 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009635 rettv->vval.v_number = 1; /* FAIL is default */
9636
9637 if (strregname == NULL)
9638 return; /* type error; errmsg already given */
9639 regname = *strregname;
9640 if (regname == 0 || regname == '@')
9641 regname = '"';
9642
9643 if (argvars[2].v_type != VAR_UNKNOWN)
9644 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009645 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009646 if (stropt == NULL)
9647 return; /* type error */
9648 for (; *stropt != NUL; ++stropt)
9649 switch (*stropt)
9650 {
9651 case 'a': case 'A': /* append */
9652 append = TRUE;
9653 break;
9654 case 'v': case 'c': /* character-wise selection */
9655 yank_type = MCHAR;
9656 break;
9657 case 'V': case 'l': /* line-wise selection */
9658 yank_type = MLINE;
9659 break;
9660 case 'b': case Ctrl_V: /* block-wise selection */
9661 yank_type = MBLOCK;
9662 if (VIM_ISDIGIT(stropt[1]))
9663 {
9664 ++stropt;
9665 block_len = getdigits(&stropt) - 1;
9666 --stropt;
9667 }
9668 break;
9669 }
9670 }
9671
9672 if (argvars[1].v_type == VAR_LIST)
9673 {
9674 char_u **lstval;
9675 char_u **allocval;
9676 char_u buf[NUMBUFLEN];
9677 char_u **curval;
9678 char_u **curallocval;
9679 list_T *ll = argvars[1].vval.v_list;
9680 listitem_T *li;
9681 int len;
9682
9683 /* If the list is NULL handle like an empty list. */
9684 len = ll == NULL ? 0 : ll->lv_len;
9685
9686 /* First half: use for pointers to result lines; second half: use for
9687 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +02009688 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009689 if (lstval == NULL)
9690 return;
9691 curval = lstval;
9692 allocval = lstval + len + 2;
9693 curallocval = allocval;
9694
9695 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
9696 li = li->li_next)
9697 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009698 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009699 if (strval == NULL)
9700 goto free_lstval;
9701 if (strval == buf)
9702 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009703 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009704 * overwrite the string. */
9705 strval = vim_strsave(buf);
9706 if (strval == NULL)
9707 goto free_lstval;
9708 *curallocval++ = strval;
9709 }
9710 *curval++ = strval;
9711 }
9712 *curval++ = NULL;
9713
9714 write_reg_contents_lst(regname, lstval, -1,
9715 append, yank_type, block_len);
9716free_lstval:
9717 while (curallocval > allocval)
9718 vim_free(*--curallocval);
9719 vim_free(lstval);
9720 }
9721 else
9722 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009723 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009724 if (strval == NULL)
9725 return;
9726 write_reg_contents_ex(regname, strval, -1,
9727 append, yank_type, block_len);
9728 }
9729 rettv->vval.v_number = 0;
9730}
9731
9732/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01009733 * "settagstack()" function
9734 */
9735 static void
9736f_settagstack(typval_T *argvars, typval_T *rettv)
9737{
9738 static char *e_invact2 = N_("E962: Invalid action: '%s'");
9739 win_T *wp;
9740 dict_T *d;
9741 int action = 'r';
9742
9743 rettv->vval.v_number = -1;
9744
9745 // first argument: window number or id
9746 wp = find_win_by_nr_or_id(&argvars[0]);
9747 if (wp == NULL)
9748 return;
9749
9750 // second argument: dict with items to set in the tag stack
9751 if (argvars[1].v_type != VAR_DICT)
9752 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009753 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01009754 return;
9755 }
9756 d = argvars[1].vval.v_dict;
9757 if (d == NULL)
9758 return;
9759
9760 // third argument: action - 'a' for append and 'r' for replace.
9761 // default is to replace the stack.
9762 if (argvars[2].v_type == VAR_UNKNOWN)
9763 action = 'r';
9764 else if (argvars[2].v_type == VAR_STRING)
9765 {
9766 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009767 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01009768 if (actstr == NULL)
9769 return;
9770 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
9771 action = *actstr;
9772 else
9773 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009774 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +01009775 return;
9776 }
9777 }
9778 else
9779 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009780 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +01009781 return;
9782 }
9783
9784 if (set_tagstack(wp, d, action) == OK)
9785 rettv->vval.v_number = 0;
9786}
9787
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009788#ifdef FEAT_CRYPT
9789/*
9790 * "sha256({string})" function
9791 */
9792 static void
9793f_sha256(typval_T *argvars, typval_T *rettv)
9794{
9795 char_u *p;
9796
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009797 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009798 rettv->vval.v_string = vim_strsave(
9799 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
9800 rettv->v_type = VAR_STRING;
9801}
9802#endif /* FEAT_CRYPT */
9803
9804/*
9805 * "shellescape({string})" function
9806 */
9807 static void
9808f_shellescape(typval_T *argvars, typval_T *rettv)
9809{
Bram Moolenaar20615522017-06-05 18:46:26 +02009810 int do_special = non_zero_arg(&argvars[1]);
9811
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009812 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009813 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009814 rettv->v_type = VAR_STRING;
9815}
9816
9817/*
9818 * shiftwidth() function
9819 */
9820 static void
9821f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
9822{
Bram Moolenaarf9514162018-11-22 03:08:29 +01009823 rettv->vval.v_number = 0;
9824
9825 if (argvars[0].v_type != VAR_UNKNOWN)
9826 {
9827 long col;
9828
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009829 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +01009830 if (col < 0)
9831 return; // type error; errmsg already given
9832#ifdef FEAT_VARTABS
9833 rettv->vval.v_number = get_sw_value_col(curbuf, col);
9834 return;
9835#endif
9836 }
9837
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009838 rettv->vval.v_number = get_sw_value(curbuf);
9839}
9840
9841/*
9842 * "simplify()" function
9843 */
9844 static void
9845f_simplify(typval_T *argvars, typval_T *rettv)
9846{
9847 char_u *p;
9848
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009849 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009850 rettv->vval.v_string = vim_strsave(p);
9851 simplify_filename(rettv->vval.v_string); /* simplify in place */
9852 rettv->v_type = VAR_STRING;
9853}
9854
9855#ifdef FEAT_FLOAT
9856/*
9857 * "sin()" function
9858 */
9859 static void
9860f_sin(typval_T *argvars, typval_T *rettv)
9861{
9862 float_T f = 0.0;
9863
9864 rettv->v_type = VAR_FLOAT;
9865 if (get_float_arg(argvars, &f) == OK)
9866 rettv->vval.v_float = sin(f);
9867 else
9868 rettv->vval.v_float = 0.0;
9869}
9870
9871/*
9872 * "sinh()" function
9873 */
9874 static void
9875f_sinh(typval_T *argvars, typval_T *rettv)
9876{
9877 float_T f = 0.0;
9878
9879 rettv->v_type = VAR_FLOAT;
9880 if (get_float_arg(argvars, &f) == OK)
9881 rettv->vval.v_float = sinh(f);
9882 else
9883 rettv->vval.v_float = 0.0;
9884}
9885#endif
9886
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009887/*
9888 * "soundfold({word})" function
9889 */
9890 static void
9891f_soundfold(typval_T *argvars, typval_T *rettv)
9892{
9893 char_u *s;
9894
9895 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009896 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009897#ifdef FEAT_SPELL
9898 rettv->vval.v_string = eval_soundfold(s);
9899#else
9900 rettv->vval.v_string = vim_strsave(s);
9901#endif
9902}
9903
9904/*
9905 * "spellbadword()" function
9906 */
9907 static void
9908f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
9909{
9910 char_u *word = (char_u *)"";
9911 hlf_T attr = HLF_COUNT;
9912 int len = 0;
9913
9914 if (rettv_list_alloc(rettv) == FAIL)
9915 return;
9916
9917#ifdef FEAT_SPELL
9918 if (argvars[0].v_type == VAR_UNKNOWN)
9919 {
9920 /* Find the start and length of the badly spelled word. */
9921 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
9922 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +01009923 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009924 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +01009925 curwin->w_set_curswant = TRUE;
9926 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009927 }
9928 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
9929 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009930 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009931 int capcol = -1;
9932
9933 if (str != NULL)
9934 {
9935 /* Check the argument for spelling. */
9936 while (*str != NUL)
9937 {
9938 len = spell_check(curwin, str, &attr, &capcol, FALSE);
9939 if (attr != HLF_COUNT)
9940 {
9941 word = str;
9942 break;
9943 }
9944 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +02009945 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +02009946 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009947 }
9948 }
9949 }
9950#endif
9951
9952 list_append_string(rettv->vval.v_list, word, len);
9953 list_append_string(rettv->vval.v_list, (char_u *)(
9954 attr == HLF_SPB ? "bad" :
9955 attr == HLF_SPR ? "rare" :
9956 attr == HLF_SPL ? "local" :
9957 attr == HLF_SPC ? "caps" :
9958 ""), -1);
9959}
9960
9961/*
9962 * "spellsuggest()" function
9963 */
9964 static void
9965f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
9966{
9967#ifdef FEAT_SPELL
9968 char_u *str;
9969 int typeerr = FALSE;
9970 int maxcount;
9971 garray_T ga;
9972 int i;
9973 listitem_T *li;
9974 int need_capital = FALSE;
9975#endif
9976
9977 if (rettv_list_alloc(rettv) == FAIL)
9978 return;
9979
9980#ifdef FEAT_SPELL
9981 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
9982 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009983 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009984 if (argvars[1].v_type != VAR_UNKNOWN)
9985 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009986 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009987 if (maxcount <= 0)
9988 return;
9989 if (argvars[2].v_type != VAR_UNKNOWN)
9990 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009991 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009992 if (typeerr)
9993 return;
9994 }
9995 }
9996 else
9997 maxcount = 25;
9998
9999 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10000
10001 for (i = 0; i < ga.ga_len; ++i)
10002 {
10003 str = ((char_u **)ga.ga_data)[i];
10004
10005 li = listitem_alloc();
10006 if (li == NULL)
10007 vim_free(str);
10008 else
10009 {
10010 li->li_tv.v_type = VAR_STRING;
10011 li->li_tv.v_lock = 0;
10012 li->li_tv.vval.v_string = str;
10013 list_append(rettv->vval.v_list, li);
10014 }
10015 }
10016 ga_clear(&ga);
10017 }
10018#endif
10019}
10020
10021 static void
10022f_split(typval_T *argvars, typval_T *rettv)
10023{
10024 char_u *str;
10025 char_u *end;
10026 char_u *pat = NULL;
10027 regmatch_T regmatch;
10028 char_u patbuf[NUMBUFLEN];
10029 char_u *save_cpo;
10030 int match;
10031 colnr_T col = 0;
10032 int keepempty = FALSE;
10033 int typeerr = FALSE;
10034
10035 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10036 save_cpo = p_cpo;
10037 p_cpo = (char_u *)"";
10038
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010039 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010040 if (argvars[1].v_type != VAR_UNKNOWN)
10041 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010042 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010043 if (pat == NULL)
10044 typeerr = TRUE;
10045 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010046 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010047 }
10048 if (pat == NULL || *pat == NUL)
10049 pat = (char_u *)"[\\x01- ]\\+";
10050
10051 if (rettv_list_alloc(rettv) == FAIL)
10052 return;
10053 if (typeerr)
10054 return;
10055
10056 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10057 if (regmatch.regprog != NULL)
10058 {
10059 regmatch.rm_ic = FALSE;
10060 while (*str != NUL || keepempty)
10061 {
10062 if (*str == NUL)
10063 match = FALSE; /* empty item at the end */
10064 else
10065 match = vim_regexec_nl(&regmatch, str, col);
10066 if (match)
10067 end = regmatch.startp[0];
10068 else
10069 end = str + STRLEN(str);
10070 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10071 && *str != NUL && match && end < regmatch.endp[0]))
10072 {
10073 if (list_append_string(rettv->vval.v_list, str,
10074 (int)(end - str)) == FAIL)
10075 break;
10076 }
10077 if (!match)
10078 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010079 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010080 if (regmatch.endp[0] > str)
10081 col = 0;
10082 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010083 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010084 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010085 str = regmatch.endp[0];
10086 }
10087
10088 vim_regfree(regmatch.regprog);
10089 }
10090
10091 p_cpo = save_cpo;
10092}
10093
10094#ifdef FEAT_FLOAT
10095/*
10096 * "sqrt()" function
10097 */
10098 static void
10099f_sqrt(typval_T *argvars, typval_T *rettv)
10100{
10101 float_T f = 0.0;
10102
10103 rettv->v_type = VAR_FLOAT;
10104 if (get_float_arg(argvars, &f) == OK)
10105 rettv->vval.v_float = sqrt(f);
10106 else
10107 rettv->vval.v_float = 0.0;
10108}
10109
10110/*
10111 * "str2float()" function
10112 */
10113 static void
10114f_str2float(typval_T *argvars, typval_T *rettv)
10115{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010116 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010117 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010118
Bram Moolenaar08243d22017-01-10 16:12:29 +010010119 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010120 p = skipwhite(p + 1);
10121 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010122 if (isneg)
10123 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010124 rettv->v_type = VAR_FLOAT;
10125}
10126#endif
10127
10128/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010129 * "str2list()" function
10130 */
10131 static void
10132f_str2list(typval_T *argvars, typval_T *rettv)
10133{
10134 char_u *p;
10135 int utf8 = FALSE;
10136
10137 if (rettv_list_alloc(rettv) == FAIL)
10138 return;
10139
10140 if (argvars[1].v_type != VAR_UNKNOWN)
10141 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10142
10143 p = tv_get_string(&argvars[0]);
10144
10145 if (has_mbyte || utf8)
10146 {
10147 int (*ptr2len)(char_u *);
10148 int (*ptr2char)(char_u *);
10149
10150 if (utf8 || enc_utf8)
10151 {
10152 ptr2len = utf_ptr2len;
10153 ptr2char = utf_ptr2char;
10154 }
10155 else
10156 {
10157 ptr2len = mb_ptr2len;
10158 ptr2char = mb_ptr2char;
10159 }
10160
10161 for ( ; *p != NUL; p += (*ptr2len)(p))
10162 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10163 }
10164 else
10165 for ( ; *p != NUL; ++p)
10166 list_append_number(rettv->vval.v_list, *p);
10167}
10168
10169/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010170 * "str2nr()" function
10171 */
10172 static void
10173f_str2nr(typval_T *argvars, typval_T *rettv)
10174{
10175 int base = 10;
10176 char_u *p;
10177 varnumber_T n;
10178 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010179 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010180
10181 if (argvars[1].v_type != VAR_UNKNOWN)
10182 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010183 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010184 if (base != 2 && base != 8 && base != 10 && base != 16)
10185 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010186 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010187 return;
10188 }
10189 }
10190
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010191 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010192 isneg = (*p == '-');
10193 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010194 p = skipwhite(p + 1);
10195 switch (base)
10196 {
10197 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10198 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10199 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10200 default: what = 0;
10201 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010202 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10203 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010204 if (isneg)
10205 rettv->vval.v_number = -n;
10206 else
10207 rettv->vval.v_number = n;
10208
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010209}
10210
10211#ifdef HAVE_STRFTIME
10212/*
10213 * "strftime({format}[, {time}])" function
10214 */
10215 static void
10216f_strftime(typval_T *argvars, typval_T *rettv)
10217{
10218 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010219 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010220 struct tm *curtime;
10221 time_t seconds;
10222 char_u *p;
10223
10224 rettv->v_type = VAR_STRING;
10225
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010226 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010227 if (argvars[1].v_type == VAR_UNKNOWN)
10228 seconds = time(NULL);
10229 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010230 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010231 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010232 /* MSVC returns NULL for an invalid value of seconds. */
10233 if (curtime == NULL)
10234 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10235 else
10236 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010237 vimconv_T conv;
10238 char_u *enc;
10239
10240 conv.vc_type = CONV_NONE;
10241 enc = enc_locale();
10242 convert_setup(&conv, p_enc, enc);
10243 if (conv.vc_type != CONV_NONE)
10244 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010245 if (p != NULL)
10246 (void)strftime((char *)result_buf, sizeof(result_buf),
10247 (char *)p, curtime);
10248 else
10249 result_buf[0] = NUL;
10250
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010251 if (conv.vc_type != CONV_NONE)
10252 vim_free(p);
10253 convert_setup(&conv, enc, p_enc);
10254 if (conv.vc_type != CONV_NONE)
10255 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10256 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010257 rettv->vval.v_string = vim_strsave(result_buf);
10258
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010259 /* Release conversion descriptors */
10260 convert_setup(&conv, NULL, NULL);
10261 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010262 }
10263}
10264#endif
10265
10266/*
10267 * "strgetchar()" function
10268 */
10269 static void
10270f_strgetchar(typval_T *argvars, typval_T *rettv)
10271{
10272 char_u *str;
10273 int len;
10274 int error = FALSE;
10275 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010010276 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010277
10278 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010279 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010280 if (str == NULL)
10281 return;
10282 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010283 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010284 if (error)
10285 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010286
Bram Moolenaar13505972019-01-24 15:04:48 +010010287 while (charidx >= 0 && byteidx < len)
10288 {
10289 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010290 {
Bram Moolenaar13505972019-01-24 15:04:48 +010010291 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10292 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010293 }
Bram Moolenaar13505972019-01-24 15:04:48 +010010294 --charidx;
10295 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010296 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010297}
10298
10299/*
10300 * "stridx()" function
10301 */
10302 static void
10303f_stridx(typval_T *argvars, typval_T *rettv)
10304{
10305 char_u buf[NUMBUFLEN];
10306 char_u *needle;
10307 char_u *haystack;
10308 char_u *save_haystack;
10309 char_u *pos;
10310 int start_idx;
10311
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010312 needle = tv_get_string_chk(&argvars[1]);
10313 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010314 rettv->vval.v_number = -1;
10315 if (needle == NULL || haystack == NULL)
10316 return; /* type error; errmsg already given */
10317
10318 if (argvars[2].v_type != VAR_UNKNOWN)
10319 {
10320 int error = FALSE;
10321
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010322 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010323 if (error || start_idx >= (int)STRLEN(haystack))
10324 return;
10325 if (start_idx >= 0)
10326 haystack += start_idx;
10327 }
10328
10329 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10330 if (pos != NULL)
10331 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10332}
10333
10334/*
10335 * "string()" function
10336 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010010337 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010338f_string(typval_T *argvars, typval_T *rettv)
10339{
10340 char_u *tofree;
10341 char_u numbuf[NUMBUFLEN];
10342
10343 rettv->v_type = VAR_STRING;
10344 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10345 get_copyID());
10346 /* Make a copy if we have a value but it's not in allocated memory. */
10347 if (rettv->vval.v_string != NULL && tofree == NULL)
10348 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10349}
10350
10351/*
10352 * "strlen()" function
10353 */
10354 static void
10355f_strlen(typval_T *argvars, typval_T *rettv)
10356{
10357 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010358 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010359}
10360
10361/*
10362 * "strchars()" function
10363 */
10364 static void
10365f_strchars(typval_T *argvars, typval_T *rettv)
10366{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010367 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010368 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010369 varnumber_T len = 0;
10370 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010371
10372 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010373 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010374 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010375 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010376 else
10377 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010378 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10379 while (*s != NUL)
10380 {
10381 func_mb_ptr2char_adv(&s);
10382 ++len;
10383 }
10384 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010385 }
10386}
10387
10388/*
10389 * "strdisplaywidth()" function
10390 */
10391 static void
10392f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10393{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010394 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010395 int col = 0;
10396
10397 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010398 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010399
10400 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10401}
10402
10403/*
10404 * "strwidth()" function
10405 */
10406 static void
10407f_strwidth(typval_T *argvars, typval_T *rettv)
10408{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010409 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010410
Bram Moolenaar13505972019-01-24 15:04:48 +010010411 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010412}
10413
10414/*
10415 * "strcharpart()" function
10416 */
10417 static void
10418f_strcharpart(typval_T *argvars, typval_T *rettv)
10419{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010420 char_u *p;
10421 int nchar;
10422 int nbyte = 0;
10423 int charlen;
10424 int len = 0;
10425 int slen;
10426 int error = FALSE;
10427
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010428 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010429 slen = (int)STRLEN(p);
10430
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010431 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010432 if (!error)
10433 {
10434 if (nchar > 0)
10435 while (nchar > 0 && nbyte < slen)
10436 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020010437 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010438 --nchar;
10439 }
10440 else
10441 nbyte = nchar;
10442 if (argvars[2].v_type != VAR_UNKNOWN)
10443 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010444 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010445 while (charlen > 0 && nbyte + len < slen)
10446 {
10447 int off = nbyte + len;
10448
10449 if (off < 0)
10450 len += 1;
10451 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020010452 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010453 --charlen;
10454 }
10455 }
10456 else
10457 len = slen - nbyte; /* default: all bytes that are available. */
10458 }
10459
10460 /*
10461 * Only return the overlap between the specified part and the actual
10462 * string.
10463 */
10464 if (nbyte < 0)
10465 {
10466 len += nbyte;
10467 nbyte = 0;
10468 }
10469 else if (nbyte > slen)
10470 nbyte = slen;
10471 if (len < 0)
10472 len = 0;
10473 else if (nbyte + len > slen)
10474 len = slen - nbyte;
10475
10476 rettv->v_type = VAR_STRING;
10477 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010478}
10479
10480/*
10481 * "strpart()" function
10482 */
10483 static void
10484f_strpart(typval_T *argvars, typval_T *rettv)
10485{
10486 char_u *p;
10487 int n;
10488 int len;
10489 int slen;
10490 int error = FALSE;
10491
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010492 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010493 slen = (int)STRLEN(p);
10494
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010495 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010496 if (error)
10497 len = 0;
10498 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010499 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010500 else
10501 len = slen - n; /* default len: all bytes that are available. */
10502
10503 /*
10504 * Only return the overlap between the specified part and the actual
10505 * string.
10506 */
10507 if (n < 0)
10508 {
10509 len += n;
10510 n = 0;
10511 }
10512 else if (n > slen)
10513 n = slen;
10514 if (len < 0)
10515 len = 0;
10516 else if (n + len > slen)
10517 len = slen - n;
10518
10519 rettv->v_type = VAR_STRING;
10520 rettv->vval.v_string = vim_strnsave(p + n, len);
10521}
10522
10523/*
10524 * "strridx()" function
10525 */
10526 static void
10527f_strridx(typval_T *argvars, typval_T *rettv)
10528{
10529 char_u buf[NUMBUFLEN];
10530 char_u *needle;
10531 char_u *haystack;
10532 char_u *rest;
10533 char_u *lastmatch = NULL;
10534 int haystack_len, end_idx;
10535
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010536 needle = tv_get_string_chk(&argvars[1]);
10537 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010538
10539 rettv->vval.v_number = -1;
10540 if (needle == NULL || haystack == NULL)
10541 return; /* type error; errmsg already given */
10542
10543 haystack_len = (int)STRLEN(haystack);
10544 if (argvars[2].v_type != VAR_UNKNOWN)
10545 {
10546 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010547 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010548 if (end_idx < 0)
10549 return; /* can never find a match */
10550 }
10551 else
10552 end_idx = haystack_len;
10553
10554 if (*needle == NUL)
10555 {
10556 /* Empty string matches past the end. */
10557 lastmatch = haystack + end_idx;
10558 }
10559 else
10560 {
10561 for (rest = haystack; *rest != '\0'; ++rest)
10562 {
10563 rest = (char_u *)strstr((char *)rest, (char *)needle);
10564 if (rest == NULL || rest > haystack + end_idx)
10565 break;
10566 lastmatch = rest;
10567 }
10568 }
10569
10570 if (lastmatch == NULL)
10571 rettv->vval.v_number = -1;
10572 else
10573 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
10574}
10575
10576/*
10577 * "strtrans()" function
10578 */
10579 static void
10580f_strtrans(typval_T *argvars, typval_T *rettv)
10581{
10582 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010583 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010584}
10585
10586/*
10587 * "submatch()" function
10588 */
10589 static void
10590f_submatch(typval_T *argvars, typval_T *rettv)
10591{
10592 int error = FALSE;
10593 int no;
10594 int retList = 0;
10595
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010596 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010597 if (error)
10598 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020010599 if (no < 0 || no >= NSUBEXP)
10600 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010601 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010010602 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020010603 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010604 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010605 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010606 if (error)
10607 return;
10608
10609 if (retList == 0)
10610 {
10611 rettv->v_type = VAR_STRING;
10612 rettv->vval.v_string = reg_submatch(no);
10613 }
10614 else
10615 {
10616 rettv->v_type = VAR_LIST;
10617 rettv->vval.v_list = reg_submatch_list(no);
10618 }
10619}
10620
10621/*
10622 * "substitute()" function
10623 */
10624 static void
10625f_substitute(typval_T *argvars, typval_T *rettv)
10626{
10627 char_u patbuf[NUMBUFLEN];
10628 char_u subbuf[NUMBUFLEN];
10629 char_u flagsbuf[NUMBUFLEN];
10630
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010631 char_u *str = tv_get_string_chk(&argvars[0]);
10632 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010633 char_u *sub = NULL;
10634 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010635 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010636
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010637 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
10638 expr = &argvars[2];
10639 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010640 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010641
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010642 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010643 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
10644 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010645 rettv->vval.v_string = NULL;
10646 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020010647 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010648}
10649
10650/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020010651 * "swapinfo(swap_filename)" function
10652 */
10653 static void
10654f_swapinfo(typval_T *argvars, typval_T *rettv)
10655{
10656 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010657 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020010658}
10659
10660/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020010661 * "swapname(expr)" function
10662 */
10663 static void
10664f_swapname(typval_T *argvars, typval_T *rettv)
10665{
10666 buf_T *buf;
10667
10668 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010669 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020010670 if (buf == NULL || buf->b_ml.ml_mfp == NULL
10671 || buf->b_ml.ml_mfp->mf_fname == NULL)
10672 rettv->vval.v_string = NULL;
10673 else
10674 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
10675}
10676
10677/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010678 * "synID(lnum, col, trans)" function
10679 */
10680 static void
10681f_synID(typval_T *argvars UNUSED, typval_T *rettv)
10682{
10683 int id = 0;
10684#ifdef FEAT_SYN_HL
10685 linenr_T lnum;
10686 colnr_T col;
10687 int trans;
10688 int transerr = FALSE;
10689
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010690 lnum = tv_get_lnum(argvars); /* -1 on type error */
10691 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
10692 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010693
10694 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
10695 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
10696 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
10697#endif
10698
10699 rettv->vval.v_number = id;
10700}
10701
10702/*
10703 * "synIDattr(id, what [, mode])" function
10704 */
10705 static void
10706f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
10707{
10708 char_u *p = NULL;
10709#ifdef FEAT_SYN_HL
10710 int id;
10711 char_u *what;
10712 char_u *mode;
10713 char_u modebuf[NUMBUFLEN];
10714 int modec;
10715
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010716 id = (int)tv_get_number(&argvars[0]);
10717 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010718 if (argvars[2].v_type != VAR_UNKNOWN)
10719 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010720 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010721 modec = TOLOWER_ASC(mode[0]);
10722 if (modec != 't' && modec != 'c' && modec != 'g')
10723 modec = 0; /* replace invalid with current */
10724 }
10725 else
10726 {
10727#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
10728 if (USE_24BIT)
10729 modec = 'g';
10730 else
10731#endif
10732 if (t_colors > 1)
10733 modec = 'c';
10734 else
10735 modec = 't';
10736 }
10737
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010738 switch (TOLOWER_ASC(what[0]))
10739 {
10740 case 'b':
10741 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
10742 p = highlight_color(id, what, modec);
10743 else /* bold */
10744 p = highlight_has_attr(id, HL_BOLD, modec);
10745 break;
10746
10747 case 'f': /* fg[#] or font */
10748 p = highlight_color(id, what, modec);
10749 break;
10750
10751 case 'i':
10752 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
10753 p = highlight_has_attr(id, HL_INVERSE, modec);
10754 else /* italic */
10755 p = highlight_has_attr(id, HL_ITALIC, modec);
10756 break;
10757
10758 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020010759 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010760 break;
10761
10762 case 'r': /* reverse */
10763 p = highlight_has_attr(id, HL_INVERSE, modec);
10764 break;
10765
10766 case 's':
10767 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
10768 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020010769 /* strikeout */
10770 else if (TOLOWER_ASC(what[1]) == 't' &&
10771 TOLOWER_ASC(what[2]) == 'r')
10772 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010773 else /* standout */
10774 p = highlight_has_attr(id, HL_STANDOUT, modec);
10775 break;
10776
10777 case 'u':
10778 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
10779 /* underline */
10780 p = highlight_has_attr(id, HL_UNDERLINE, modec);
10781 else
10782 /* undercurl */
10783 p = highlight_has_attr(id, HL_UNDERCURL, modec);
10784 break;
10785 }
10786
10787 if (p != NULL)
10788 p = vim_strsave(p);
10789#endif
10790 rettv->v_type = VAR_STRING;
10791 rettv->vval.v_string = p;
10792}
10793
10794/*
10795 * "synIDtrans(id)" function
10796 */
10797 static void
10798f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
10799{
10800 int id;
10801
10802#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010803 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010804
10805 if (id > 0)
10806 id = syn_get_final_id(id);
10807 else
10808#endif
10809 id = 0;
10810
10811 rettv->vval.v_number = id;
10812}
10813
10814/*
10815 * "synconcealed(lnum, col)" function
10816 */
10817 static void
10818f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
10819{
10820#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
10821 linenr_T lnum;
10822 colnr_T col;
10823 int syntax_flags = 0;
10824 int cchar;
10825 int matchid = 0;
10826 char_u str[NUMBUFLEN];
10827#endif
10828
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010829 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010830
10831#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010832 lnum = tv_get_lnum(argvars); /* -1 on type error */
10833 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010834
10835 vim_memset(str, NUL, sizeof(str));
10836
10837 if (rettv_list_alloc(rettv) != FAIL)
10838 {
10839 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
10840 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
10841 && curwin->w_p_cole > 0)
10842 {
10843 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
10844 syntax_flags = get_syntax_info(&matchid);
10845
10846 /* get the conceal character */
10847 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
10848 {
10849 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020010850 if (cchar == NUL && curwin->w_p_cole == 1)
10851 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010852 if (cchar != NUL)
10853 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010854 if (has_mbyte)
10855 (*mb_char2bytes)(cchar, str);
10856 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010857 str[0] = cchar;
10858 }
10859 }
10860 }
10861
10862 list_append_number(rettv->vval.v_list,
10863 (syntax_flags & HL_CONCEAL) != 0);
10864 /* -1 to auto-determine strlen */
10865 list_append_string(rettv->vval.v_list, str, -1);
10866 list_append_number(rettv->vval.v_list, matchid);
10867 }
10868#endif
10869}
10870
10871/*
10872 * "synstack(lnum, col)" function
10873 */
10874 static void
10875f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
10876{
10877#ifdef FEAT_SYN_HL
10878 linenr_T lnum;
10879 colnr_T col;
10880 int i;
10881 int id;
10882#endif
10883
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010884 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010885
10886#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010887 lnum = tv_get_lnum(argvars); /* -1 on type error */
10888 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010889
10890 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
10891 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
10892 && rettv_list_alloc(rettv) != FAIL)
10893 {
10894 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
10895 for (i = 0; ; ++i)
10896 {
10897 id = syn_get_stack_item(i);
10898 if (id < 0)
10899 break;
10900 if (list_append_number(rettv->vval.v_list, id) == FAIL)
10901 break;
10902 }
10903 }
10904#endif
10905}
10906
10907 static void
10908get_cmd_output_as_rettv(
10909 typval_T *argvars,
10910 typval_T *rettv,
10911 int retlist)
10912{
10913 char_u *res = NULL;
10914 char_u *p;
10915 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010916 int err = FALSE;
10917 FILE *fd;
10918 list_T *list = NULL;
10919 int flags = SHELL_SILENT;
10920
10921 rettv->v_type = VAR_STRING;
10922 rettv->vval.v_string = NULL;
10923 if (check_restricted() || check_secure())
10924 goto errret;
10925
10926 if (argvars[1].v_type != VAR_UNKNOWN)
10927 {
10928 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010010929 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010930 * command.
10931 */
10932 if ((infile = vim_tempname('i', TRUE)) == NULL)
10933 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010934 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010935 goto errret;
10936 }
10937
10938 fd = mch_fopen((char *)infile, WRITEBIN);
10939 if (fd == NULL)
10940 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010941 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010942 goto errret;
10943 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010010944 if (argvars[1].v_type == VAR_NUMBER)
10945 {
10946 linenr_T lnum;
10947 buf_T *buf;
10948
10949 buf = buflist_findnr(argvars[1].vval.v_number);
10950 if (buf == NULL)
10951 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010952 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010010953 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010010954 goto errret;
10955 }
10956
10957 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
10958 {
10959 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
10960 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
10961 {
10962 err = TRUE;
10963 break;
10964 }
10965 if (putc(NL, fd) == EOF)
10966 {
10967 err = TRUE;
10968 break;
10969 }
10970 }
10971 }
10972 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010973 {
10974 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
10975 err = TRUE;
10976 }
10977 else
10978 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010010979 size_t len;
10980 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010981
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010982 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010983 if (p == NULL)
10984 {
10985 fclose(fd);
10986 goto errret; /* type error; errmsg already given */
10987 }
10988 len = STRLEN(p);
10989 if (len > 0 && fwrite(p, len, 1, fd) != 1)
10990 err = TRUE;
10991 }
10992 if (fclose(fd) != 0)
10993 err = TRUE;
10994 if (err)
10995 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010996 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010997 goto errret;
10998 }
10999 }
11000
11001 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11002 * echoes typeahead, that messes up the display. */
11003 if (!msg_silent)
11004 flags += SHELL_COOKED;
11005
11006 if (retlist)
11007 {
11008 int len;
11009 listitem_T *li;
11010 char_u *s = NULL;
11011 char_u *start;
11012 char_u *end;
11013 int i;
11014
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011015 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011016 if (res == NULL)
11017 goto errret;
11018
11019 list = list_alloc();
11020 if (list == NULL)
11021 goto errret;
11022
11023 for (i = 0; i < len; ++i)
11024 {
11025 start = res + i;
11026 while (i < len && res[i] != NL)
11027 ++i;
11028 end = res + i;
11029
Bram Moolenaar964b3742019-05-24 18:54:09 +020011030 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011031 if (s == NULL)
11032 goto errret;
11033
11034 for (p = s; start < end; ++p, ++start)
11035 *p = *start == NUL ? NL : *start;
11036 *p = NUL;
11037
11038 li = listitem_alloc();
11039 if (li == NULL)
11040 {
11041 vim_free(s);
11042 goto errret;
11043 }
11044 li->li_tv.v_type = VAR_STRING;
11045 li->li_tv.v_lock = 0;
11046 li->li_tv.vval.v_string = s;
11047 list_append(list, li);
11048 }
11049
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011050 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011051 list = NULL;
11052 }
11053 else
11054 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011055 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011056#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011057 /* translate <CR><NL> into <NL> */
11058 if (res != NULL)
11059 {
11060 char_u *s, *d;
11061
11062 d = res;
11063 for (s = res; *s; ++s)
11064 {
11065 if (s[0] == CAR && s[1] == NL)
11066 ++s;
11067 *d++ = *s;
11068 }
11069 *d = NUL;
11070 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011071#endif
11072 rettv->vval.v_string = res;
11073 res = NULL;
11074 }
11075
11076errret:
11077 if (infile != NULL)
11078 {
11079 mch_remove(infile);
11080 vim_free(infile);
11081 }
11082 if (res != NULL)
11083 vim_free(res);
11084 if (list != NULL)
11085 list_free(list);
11086}
11087
11088/*
11089 * "system()" function
11090 */
11091 static void
11092f_system(typval_T *argvars, typval_T *rettv)
11093{
11094 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11095}
11096
11097/*
11098 * "systemlist()" function
11099 */
11100 static void
11101f_systemlist(typval_T *argvars, typval_T *rettv)
11102{
11103 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11104}
11105
11106/*
11107 * "tabpagebuflist()" function
11108 */
11109 static void
11110f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11111{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011112 tabpage_T *tp;
11113 win_T *wp = NULL;
11114
11115 if (argvars[0].v_type == VAR_UNKNOWN)
11116 wp = firstwin;
11117 else
11118 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011119 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011120 if (tp != NULL)
11121 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11122 }
11123 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11124 {
11125 for (; wp != NULL; wp = wp->w_next)
11126 if (list_append_number(rettv->vval.v_list,
11127 wp->w_buffer->b_fnum) == FAIL)
11128 break;
11129 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011130}
11131
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011132/*
11133 * "tabpagenr()" function
11134 */
11135 static void
11136f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11137{
11138 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011139 char_u *arg;
11140
11141 if (argvars[0].v_type != VAR_UNKNOWN)
11142 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011143 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011144 nr = 0;
11145 if (arg != NULL)
11146 {
11147 if (STRCMP(arg, "$") == 0)
11148 nr = tabpage_index(NULL) - 1;
11149 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011150 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011151 }
11152 }
11153 else
11154 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011155 rettv->vval.v_number = nr;
11156}
11157
11158
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011159/*
11160 * Common code for tabpagewinnr() and winnr().
11161 */
11162 static int
11163get_winnr(tabpage_T *tp, typval_T *argvar)
11164{
11165 win_T *twin;
11166 int nr = 1;
11167 win_T *wp;
11168 char_u *arg;
11169
11170 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11171 if (argvar->v_type != VAR_UNKNOWN)
11172 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011173 int invalid_arg = FALSE;
11174
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011175 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011176 if (arg == NULL)
11177 nr = 0; /* type error; errmsg already given */
11178 else if (STRCMP(arg, "$") == 0)
11179 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11180 else if (STRCMP(arg, "#") == 0)
11181 {
11182 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11183 if (twin == NULL)
11184 nr = 0;
11185 }
11186 else
11187 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011188 long count;
11189 char_u *endp;
11190
11191 // Extract the window count (if specified). e.g. winnr('3j')
11192 count = strtol((char *)arg, (char **)&endp, 10);
11193 if (count <= 0)
11194 count = 1; // if count is not specified, default to 1
11195 if (endp != NULL && *endp != '\0')
11196 {
11197 if (STRCMP(endp, "j") == 0)
11198 twin = win_vert_neighbor(tp, twin, FALSE, count);
11199 else if (STRCMP(endp, "k") == 0)
11200 twin = win_vert_neighbor(tp, twin, TRUE, count);
11201 else if (STRCMP(endp, "h") == 0)
11202 twin = win_horz_neighbor(tp, twin, TRUE, count);
11203 else if (STRCMP(endp, "l") == 0)
11204 twin = win_horz_neighbor(tp, twin, FALSE, count);
11205 else
11206 invalid_arg = TRUE;
11207 }
11208 else
11209 invalid_arg = TRUE;
11210 }
11211
11212 if (invalid_arg)
11213 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011214 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011215 nr = 0;
11216 }
11217 }
11218
11219 if (nr > 0)
11220 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11221 wp != twin; wp = wp->w_next)
11222 {
11223 if (wp == NULL)
11224 {
11225 /* didn't find it in this tabpage */
11226 nr = 0;
11227 break;
11228 }
11229 ++nr;
11230 }
11231 return nr;
11232}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011233
11234/*
11235 * "tabpagewinnr()" function
11236 */
11237 static void
11238f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11239{
11240 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011241 tabpage_T *tp;
11242
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011243 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011244 if (tp == NULL)
11245 nr = 0;
11246 else
11247 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011248 rettv->vval.v_number = nr;
11249}
11250
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011251/*
11252 * "tagfiles()" function
11253 */
11254 static void
11255f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11256{
11257 char_u *fname;
11258 tagname_T tn;
11259 int first;
11260
11261 if (rettv_list_alloc(rettv) == FAIL)
11262 return;
11263 fname = alloc(MAXPATHL);
11264 if (fname == NULL)
11265 return;
11266
11267 for (first = TRUE; ; first = FALSE)
11268 if (get_tagfname(&tn, first, fname) == FAIL
11269 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11270 break;
11271 tagname_free(&tn);
11272 vim_free(fname);
11273}
11274
11275/*
11276 * "taglist()" function
11277 */
11278 static void
11279f_taglist(typval_T *argvars, typval_T *rettv)
11280{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011281 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011282 char_u *tag_pattern;
11283
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011284 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011285
11286 rettv->vval.v_number = FALSE;
11287 if (*tag_pattern == NUL)
11288 return;
11289
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011290 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011291 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011292 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011293 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011294}
11295
11296/*
11297 * "tempname()" function
11298 */
11299 static void
11300f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11301{
11302 static int x = 'A';
11303
11304 rettv->v_type = VAR_STRING;
11305 rettv->vval.v_string = vim_tempname(x, FALSE);
11306
11307 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11308 * names. Skip 'I' and 'O', they are used for shell redirection. */
11309 do
11310 {
11311 if (x == 'Z')
11312 x = '0';
11313 else if (x == '9')
11314 x = 'A';
11315 else
11316 {
11317#ifdef EBCDIC
11318 if (x == 'I')
11319 x = 'J';
11320 else if (x == 'R')
11321 x = 'S';
11322 else
11323#endif
11324 ++x;
11325 }
11326 } while (x == 'I' || x == 'O');
11327}
11328
11329#ifdef FEAT_FLOAT
11330/*
11331 * "tan()" function
11332 */
11333 static void
11334f_tan(typval_T *argvars, typval_T *rettv)
11335{
11336 float_T f = 0.0;
11337
11338 rettv->v_type = VAR_FLOAT;
11339 if (get_float_arg(argvars, &f) == OK)
11340 rettv->vval.v_float = tan(f);
11341 else
11342 rettv->vval.v_float = 0.0;
11343}
11344
11345/*
11346 * "tanh()" function
11347 */
11348 static void
11349f_tanh(typval_T *argvars, typval_T *rettv)
11350{
11351 float_T f = 0.0;
11352
11353 rettv->v_type = VAR_FLOAT;
11354 if (get_float_arg(argvars, &f) == OK)
11355 rettv->vval.v_float = tanh(f);
11356 else
11357 rettv->vval.v_float = 0.0;
11358}
11359#endif
11360
11361/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011362 * Get a callback from "arg". It can be a Funcref or a function name.
11363 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011364 * "cb_name" is not allocated.
11365 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011366 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011367 callback_T
11368get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011369{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011370 callback_T res;
11371
11372 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011373 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11374 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011375 res.cb_partial = arg->vval.v_partial;
11376 ++res.cb_partial->pt_refcount;
11377 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011378 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011379 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011380 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011381 res.cb_partial = NULL;
11382 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
11383 {
11384 // Note that we don't make a copy of the string.
11385 res.cb_name = arg->vval.v_string;
11386 func_ref(res.cb_name);
11387 }
11388 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11389 {
11390 res.cb_name = (char_u *)"";
11391 }
11392 else
11393 {
11394 emsg(_("E921: Invalid callback argument"));
11395 res.cb_name = NULL;
11396 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011397 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011398 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011399}
11400
11401/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011402 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011403 */
11404 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011405put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011406{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011407 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011408 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011409 tv->v_type = VAR_PARTIAL;
11410 tv->vval.v_partial = cb->cb_partial;
11411 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011412 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011413 else
11414 {
11415 tv->v_type = VAR_FUNC;
11416 tv->vval.v_string = vim_strsave(cb->cb_name);
11417 func_ref(cb->cb_name);
11418 }
11419}
11420
11421/*
11422 * Make a copy of "src" into "dest", allocating the function name if needed,
11423 * without incrementing the refcount.
11424 */
11425 void
11426set_callback(callback_T *dest, callback_T *src)
11427{
11428 if (src->cb_partial == NULL)
11429 {
11430 // just a function name, make a copy
11431 dest->cb_name = vim_strsave(src->cb_name);
11432 dest->cb_free_name = TRUE;
11433 }
11434 else
11435 {
11436 // cb_name is a pointer into cb_partial
11437 dest->cb_name = src->cb_name;
11438 dest->cb_free_name = FALSE;
11439 }
11440 dest->cb_partial = src->cb_partial;
11441}
11442
11443/*
11444 * Unref/free "callback" returned by get_callback() or set_callback().
11445 */
11446 void
11447free_callback(callback_T *callback)
11448{
11449 if (callback->cb_partial != NULL)
11450 {
11451 partial_unref(callback->cb_partial);
11452 callback->cb_partial = NULL;
11453 }
11454 else if (callback->cb_name != NULL)
11455 func_unref(callback->cb_name);
11456 if (callback->cb_free_name)
11457 {
11458 vim_free(callback->cb_name);
11459 callback->cb_free_name = FALSE;
11460 }
11461 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011462}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011463
11464#ifdef FEAT_TIMERS
11465/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020011466 * "timer_info([timer])" function
11467 */
11468 static void
11469f_timer_info(typval_T *argvars, typval_T *rettv)
11470{
11471 timer_T *timer = NULL;
11472
11473 if (rettv_list_alloc(rettv) != OK)
11474 return;
11475 if (argvars[0].v_type != VAR_UNKNOWN)
11476 {
11477 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011478 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020011479 else
11480 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011481 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020011482 if (timer != NULL)
11483 add_timer_info(rettv, timer);
11484 }
11485 }
11486 else
11487 add_timer_info_all(rettv);
11488}
11489
11490/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011491 * "timer_pause(timer, paused)" function
11492 */
11493 static void
11494f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
11495{
11496 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011497 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011498
11499 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011500 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011501 else
11502 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011503 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011504 if (timer != NULL)
11505 timer->tr_paused = paused;
11506 }
11507}
11508
11509/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011510 * "timer_start(time, callback [, options])" function
11511 */
11512 static void
11513f_timer_start(typval_T *argvars, typval_T *rettv)
11514{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011515 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020011516 timer_T *timer;
11517 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011518 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020011519 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011520
Bram Moolenaar75537a92016-09-05 22:45:28 +020011521 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011522 if (check_secure())
11523 return;
11524 if (argvars[2].v_type != VAR_UNKNOWN)
11525 {
11526 if (argvars[2].v_type != VAR_DICT
11527 || (dict = argvars[2].vval.v_dict) == NULL)
11528 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011529 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011530 return;
11531 }
11532 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010011533 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011534 }
11535
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011536 callback = get_callback(&argvars[1]);
11537 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020011538 return;
11539
11540 timer = create_timer(msec, repeat);
11541 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011542 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011543 else
11544 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011545 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020011546 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011547 }
11548}
11549
11550/*
11551 * "timer_stop(timer)" function
11552 */
11553 static void
11554f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
11555{
11556 timer_T *timer;
11557
11558 if (argvars[0].v_type != VAR_NUMBER)
11559 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011560 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011561 return;
11562 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011563 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011564 if (timer != NULL)
11565 stop_timer(timer);
11566}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020011567
11568/*
11569 * "timer_stopall()" function
11570 */
11571 static void
11572f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11573{
11574 stop_all_timers();
11575}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011576#endif
11577
11578/*
11579 * "tolower(string)" function
11580 */
11581 static void
11582f_tolower(typval_T *argvars, typval_T *rettv)
11583{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011584 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011585 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011586}
11587
11588/*
11589 * "toupper(string)" function
11590 */
11591 static void
11592f_toupper(typval_T *argvars, typval_T *rettv)
11593{
11594 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011595 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011596}
11597
11598/*
11599 * "tr(string, fromstr, tostr)" function
11600 */
11601 static void
11602f_tr(typval_T *argvars, typval_T *rettv)
11603{
11604 char_u *in_str;
11605 char_u *fromstr;
11606 char_u *tostr;
11607 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011608 int inlen;
11609 int fromlen;
11610 int tolen;
11611 int idx;
11612 char_u *cpstr;
11613 int cplen;
11614 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011615 char_u buf[NUMBUFLEN];
11616 char_u buf2[NUMBUFLEN];
11617 garray_T ga;
11618
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011619 in_str = tv_get_string(&argvars[0]);
11620 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
11621 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011622
11623 /* Default return value: empty string. */
11624 rettv->v_type = VAR_STRING;
11625 rettv->vval.v_string = NULL;
11626 if (fromstr == NULL || tostr == NULL)
11627 return; /* type error; errmsg already given */
11628 ga_init2(&ga, (int)sizeof(char), 80);
11629
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011630 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011631 /* not multi-byte: fromstr and tostr must be the same length */
11632 if (STRLEN(fromstr) != STRLEN(tostr))
11633 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011634error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011635 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011636 ga_clear(&ga);
11637 return;
11638 }
11639
11640 /* fromstr and tostr have to contain the same number of chars */
11641 while (*in_str != NUL)
11642 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011643 if (has_mbyte)
11644 {
11645 inlen = (*mb_ptr2len)(in_str);
11646 cpstr = in_str;
11647 cplen = inlen;
11648 idx = 0;
11649 for (p = fromstr; *p != NUL; p += fromlen)
11650 {
11651 fromlen = (*mb_ptr2len)(p);
11652 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
11653 {
11654 for (p = tostr; *p != NUL; p += tolen)
11655 {
11656 tolen = (*mb_ptr2len)(p);
11657 if (idx-- == 0)
11658 {
11659 cplen = tolen;
11660 cpstr = p;
11661 break;
11662 }
11663 }
11664 if (*p == NUL) /* tostr is shorter than fromstr */
11665 goto error;
11666 break;
11667 }
11668 ++idx;
11669 }
11670
11671 if (first && cpstr == in_str)
11672 {
11673 /* Check that fromstr and tostr have the same number of
11674 * (multi-byte) characters. Done only once when a character
11675 * of in_str doesn't appear in fromstr. */
11676 first = FALSE;
11677 for (p = tostr; *p != NUL; p += tolen)
11678 {
11679 tolen = (*mb_ptr2len)(p);
11680 --idx;
11681 }
11682 if (idx != 0)
11683 goto error;
11684 }
11685
11686 (void)ga_grow(&ga, cplen);
11687 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
11688 ga.ga_len += cplen;
11689
11690 in_str += inlen;
11691 }
11692 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011693 {
11694 /* When not using multi-byte chars we can do it faster. */
11695 p = vim_strchr(fromstr, *in_str);
11696 if (p != NULL)
11697 ga_append(&ga, tostr[p - fromstr]);
11698 else
11699 ga_append(&ga, *in_str);
11700 ++in_str;
11701 }
11702 }
11703
11704 /* add a terminating NUL */
11705 (void)ga_grow(&ga, 1);
11706 ga_append(&ga, NUL);
11707
11708 rettv->vval.v_string = ga.ga_data;
11709}
11710
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010011711/*
11712 * "trim({expr})" function
11713 */
11714 static void
11715f_trim(typval_T *argvars, typval_T *rettv)
11716{
11717 char_u buf1[NUMBUFLEN];
11718 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011719 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010011720 char_u *mask = NULL;
11721 char_u *tail;
11722 char_u *prev;
11723 char_u *p;
11724 int c1;
11725
11726 rettv->v_type = VAR_STRING;
11727 if (head == NULL)
11728 {
11729 rettv->vval.v_string = NULL;
11730 return;
11731 }
11732
11733 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011734 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010011735
11736 while (*head != NUL)
11737 {
11738 c1 = PTR2CHAR(head);
11739 if (mask == NULL)
11740 {
11741 if (c1 > ' ' && c1 != 0xa0)
11742 break;
11743 }
11744 else
11745 {
11746 for (p = mask; *p != NUL; MB_PTR_ADV(p))
11747 if (c1 == PTR2CHAR(p))
11748 break;
11749 if (*p == NUL)
11750 break;
11751 }
11752 MB_PTR_ADV(head);
11753 }
11754
11755 for (tail = head + STRLEN(head); tail > head; tail = prev)
11756 {
11757 prev = tail;
11758 MB_PTR_BACK(head, prev);
11759 c1 = PTR2CHAR(prev);
11760 if (mask == NULL)
11761 {
11762 if (c1 > ' ' && c1 != 0xa0)
11763 break;
11764 }
11765 else
11766 {
11767 for (p = mask; *p != NUL; MB_PTR_ADV(p))
11768 if (c1 == PTR2CHAR(p))
11769 break;
11770 if (*p == NUL)
11771 break;
11772 }
11773 }
11774 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
11775}
11776
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011777#ifdef FEAT_FLOAT
11778/*
11779 * "trunc({float})" function
11780 */
11781 static void
11782f_trunc(typval_T *argvars, typval_T *rettv)
11783{
11784 float_T f = 0.0;
11785
11786 rettv->v_type = VAR_FLOAT;
11787 if (get_float_arg(argvars, &f) == OK)
11788 /* trunc() is not in C90, use floor() or ceil() instead. */
11789 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
11790 else
11791 rettv->vval.v_float = 0.0;
11792}
11793#endif
11794
11795/*
11796 * "type(expr)" function
11797 */
11798 static void
11799f_type(typval_T *argvars, typval_T *rettv)
11800{
11801 int n = -1;
11802
11803 switch (argvars[0].v_type)
11804 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020011805 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
11806 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011807 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020011808 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
11809 case VAR_LIST: n = VAR_TYPE_LIST; break;
11810 case VAR_DICT: n = VAR_TYPE_DICT; break;
11811 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011812 case VAR_SPECIAL:
11813 if (argvars[0].vval.v_number == VVAL_FALSE
11814 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020011815 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011816 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020011817 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011818 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020011819 case VAR_JOB: n = VAR_TYPE_JOB; break;
11820 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010011821 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011822 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010011823 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011824 n = -1;
11825 break;
11826 }
11827 rettv->vval.v_number = n;
11828}
11829
11830/*
11831 * "undofile(name)" function
11832 */
11833 static void
11834f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
11835{
11836 rettv->v_type = VAR_STRING;
11837#ifdef FEAT_PERSISTENT_UNDO
11838 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011839 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011840
11841 if (*fname == NUL)
11842 {
11843 /* If there is no file name there will be no undo file. */
11844 rettv->vval.v_string = NULL;
11845 }
11846 else
11847 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020011848 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011849
11850 if (ffname != NULL)
11851 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
11852 vim_free(ffname);
11853 }
11854 }
11855#else
11856 rettv->vval.v_string = NULL;
11857#endif
11858}
11859
11860/*
11861 * "undotree()" function
11862 */
11863 static void
11864f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
11865{
11866 if (rettv_dict_alloc(rettv) == OK)
11867 {
11868 dict_T *dict = rettv->vval.v_dict;
11869 list_T *list;
11870
Bram Moolenaare0be1672018-07-08 16:50:37 +020011871 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
11872 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
11873 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
11874 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
11875 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
11876 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011877
11878 list = list_alloc();
11879 if (list != NULL)
11880 {
11881 u_eval_tree(curbuf->b_u_oldhead, list);
11882 dict_add_list(dict, "entries", list);
11883 }
11884 }
11885}
11886
11887/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011888 * "virtcol(string)" function
11889 */
11890 static void
11891f_virtcol(typval_T *argvars, typval_T *rettv)
11892{
11893 colnr_T vcol = 0;
11894 pos_T *fp;
11895 int fnum = curbuf->b_fnum;
11896
11897 fp = var2fpos(&argvars[0], FALSE, &fnum);
11898 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
11899 && fnum == curbuf->b_fnum)
11900 {
11901 getvvcol(curwin, fp, NULL, NULL, &vcol);
11902 ++vcol;
11903 }
11904
11905 rettv->vval.v_number = vcol;
11906}
11907
11908/*
11909 * "visualmode()" function
11910 */
11911 static void
11912f_visualmode(typval_T *argvars, typval_T *rettv)
11913{
11914 char_u str[2];
11915
11916 rettv->v_type = VAR_STRING;
11917 str[0] = curbuf->b_visual_mode_eval;
11918 str[1] = NUL;
11919 rettv->vval.v_string = vim_strsave(str);
11920
11921 /* A non-zero number or non-empty string argument: reset mode. */
11922 if (non_zero_arg(&argvars[0]))
11923 curbuf->b_visual_mode_eval = NUL;
11924}
11925
11926/*
11927 * "wildmenumode()" function
11928 */
11929 static void
11930f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11931{
11932#ifdef FEAT_WILDMENU
11933 if (wild_menu_showing)
11934 rettv->vval.v_number = 1;
11935#endif
11936}
11937
11938/*
11939 * "winbufnr(nr)" function
11940 */
11941 static void
11942f_winbufnr(typval_T *argvars, typval_T *rettv)
11943{
11944 win_T *wp;
11945
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011946 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011947 if (wp == NULL)
11948 rettv->vval.v_number = -1;
11949 else
11950 rettv->vval.v_number = wp->w_buffer->b_fnum;
11951}
11952
11953/*
11954 * "wincol()" function
11955 */
11956 static void
11957f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
11958{
11959 validate_cursor();
11960 rettv->vval.v_number = curwin->w_wcol + 1;
11961}
11962
11963/*
11964 * "winheight(nr)" function
11965 */
11966 static void
11967f_winheight(typval_T *argvars, typval_T *rettv)
11968{
11969 win_T *wp;
11970
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011971 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011972 if (wp == NULL)
11973 rettv->vval.v_number = -1;
11974 else
11975 rettv->vval.v_number = wp->w_height;
11976}
11977
11978/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020011979 * "winlayout()" function
11980 */
11981 static void
11982f_winlayout(typval_T *argvars, typval_T *rettv)
11983{
11984 tabpage_T *tp;
11985
11986 if (rettv_list_alloc(rettv) != OK)
11987 return;
11988
11989 if (argvars[0].v_type == VAR_UNKNOWN)
11990 tp = curtab;
11991 else
11992 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011993 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020011994 if (tp == NULL)
11995 return;
11996 }
11997
11998 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
11999}
12000
12001/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012002 * "winline()" function
12003 */
12004 static void
12005f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12006{
12007 validate_cursor();
12008 rettv->vval.v_number = curwin->w_wrow + 1;
12009}
12010
12011/*
12012 * "winnr()" function
12013 */
12014 static void
12015f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12016{
12017 int nr = 1;
12018
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012019 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012020 rettv->vval.v_number = nr;
12021}
12022
12023/*
12024 * "winrestcmd()" function
12025 */
12026 static void
12027f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12028{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012029 win_T *wp;
12030 int winnr = 1;
12031 garray_T ga;
12032 char_u buf[50];
12033
12034 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012035 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012036 {
12037 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12038 ga_concat(&ga, buf);
12039 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12040 ga_concat(&ga, buf);
12041 ++winnr;
12042 }
12043 ga_append(&ga, NUL);
12044
12045 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012046 rettv->v_type = VAR_STRING;
12047}
12048
12049/*
12050 * "winrestview()" function
12051 */
12052 static void
12053f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12054{
12055 dict_T *dict;
12056
12057 if (argvars[0].v_type != VAR_DICT
12058 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012059 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012060 else
12061 {
12062 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012063 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012064 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012065 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012066 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012067 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012068 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12069 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012070 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012071 curwin->w_set_curswant = FALSE;
12072 }
12073
12074 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012075 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012076#ifdef FEAT_DIFF
12077 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012078 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012079#endif
12080 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012081 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012082 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012083 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012084
12085 check_cursor();
12086 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012087 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012088 changed_window_setting();
12089
12090 if (curwin->w_topline <= 0)
12091 curwin->w_topline = 1;
12092 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12093 curwin->w_topline = curbuf->b_ml.ml_line_count;
12094#ifdef FEAT_DIFF
12095 check_topfill(curwin, TRUE);
12096#endif
12097 }
12098}
12099
12100/*
12101 * "winsaveview()" function
12102 */
12103 static void
12104f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12105{
12106 dict_T *dict;
12107
12108 if (rettv_dict_alloc(rettv) == FAIL)
12109 return;
12110 dict = rettv->vval.v_dict;
12111
Bram Moolenaare0be1672018-07-08 16:50:37 +020012112 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12113 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012114 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012115 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012116 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012117
Bram Moolenaare0be1672018-07-08 16:50:37 +020012118 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012119#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012120 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012121#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012122 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12123 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012124}
12125
12126/*
12127 * "winwidth(nr)" function
12128 */
12129 static void
12130f_winwidth(typval_T *argvars, typval_T *rettv)
12131{
12132 win_T *wp;
12133
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012134 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012135 if (wp == NULL)
12136 rettv->vval.v_number = -1;
12137 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012138 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012139}
12140
12141/*
12142 * "wordcount()" function
12143 */
12144 static void
12145f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12146{
12147 if (rettv_dict_alloc(rettv) == FAIL)
12148 return;
12149 cursor_pos_info(rettv->vval.v_dict);
12150}
12151
12152/*
12153 * "writefile()" function
12154 */
12155 static void
12156f_writefile(typval_T *argvars, typval_T *rettv)
12157{
12158 int binary = FALSE;
12159 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012160#ifdef HAVE_FSYNC
12161 int do_fsync = p_fs;
12162#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012163 char_u *fname;
12164 FILE *fd;
12165 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012166 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012167 list_T *list = NULL;
12168 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012169
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012170 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012171 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012172 return;
12173
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012174 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012175 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012176 list = argvars[0].vval.v_list;
12177 if (list == NULL)
12178 return;
12179 for (li = list->lv_first; li != NULL; li = li->li_next)
12180 if (tv_get_string_chk(&li->li_tv) == NULL)
12181 return;
12182 }
12183 else if (argvars[0].v_type == VAR_BLOB)
12184 {
12185 blob = argvars[0].vval.v_blob;
12186 if (blob == NULL)
12187 return;
12188 }
12189 else
12190 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012191 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012192 return;
12193 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012194
12195 if (argvars[2].v_type != VAR_UNKNOWN)
12196 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012197 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012198
12199 if (arg2 == NULL)
12200 return;
12201 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012202 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012203 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012204 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012205#ifdef HAVE_FSYNC
12206 if (vim_strchr(arg2, 's') != NULL)
12207 do_fsync = TRUE;
12208 else if (vim_strchr(arg2, 'S') != NULL)
12209 do_fsync = FALSE;
12210#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012211 }
12212
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012213 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012214 if (fname == NULL)
12215 return;
12216
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012217 /* Always open the file in binary mode, library functions have a mind of
12218 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012219 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12220 append ? APPENDBIN : WRITEBIN)) == NULL)
12221 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012222 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012223 ret = -1;
12224 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012225 else if (blob)
12226 {
12227 if (write_blob(fd, blob) == FAIL)
12228 ret = -1;
12229#ifdef HAVE_FSYNC
12230 else if (do_fsync)
12231 // Ignore the error, the user wouldn't know what to do about it.
12232 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012233 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012234#endif
12235 fclose(fd);
12236 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012237 else
12238 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012239 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012240 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012241#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012242 else if (do_fsync)
12243 /* Ignore the error, the user wouldn't know what to do about it.
12244 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012245 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012246#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012247 fclose(fd);
12248 }
12249
12250 rettv->vval.v_number = ret;
12251}
12252
12253/*
12254 * "xor(expr, expr)" function
12255 */
12256 static void
12257f_xor(typval_T *argvars, typval_T *rettv)
12258{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012259 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
12260 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012261}
12262
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012263#endif /* FEAT_EVAL */