blob: c5ec21dd6aeea28e5861d23c9f2adc200d03840c [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 Moolenaar73dad1e2016-07-17 22:13:49 +020024# include <time.h> /* for time_t */
25#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 +020028static char *e_stringreq = N_("E928: String required");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020029
30#ifdef FEAT_FLOAT
31static void f_abs(typval_T *argvars, typval_T *rettv);
32static void f_acos(typval_T *argvars, typval_T *rettv);
33#endif
34static void f_add(typval_T *argvars, typval_T *rettv);
35static void f_and(typval_T *argvars, typval_T *rettv);
36static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020037static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020038#ifdef FEAT_FLOAT
39static void f_asin(typval_T *argvars, typval_T *rettv);
40static void f_atan(typval_T *argvars, typval_T *rettv);
41static void f_atan2(typval_T *argvars, typval_T *rettv);
42#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010043#ifdef FEAT_BEVAL
Bram Moolenaarbe0a2592019-05-09 13:50:16 +020044static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
Bram Moolenaar59716a22017-03-01 20:32:44 +010045static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010046# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010047static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010048# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010049#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020050static void f_browse(typval_T *argvars, typval_T *rettv);
51static void f_browsedir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020052static void f_bufadd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020053static void f_bufexists(typval_T *argvars, typval_T *rettv);
54static void f_buflisted(typval_T *argvars, typval_T *rettv);
Bram Moolenaar15e248e2019-06-30 20:21:37 +020055static void f_bufload(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020056static void f_bufloaded(typval_T *argvars, typval_T *rettv);
57static void f_bufname(typval_T *argvars, typval_T *rettv);
58static void f_bufnr(typval_T *argvars, typval_T *rettv);
59static void f_bufwinid(typval_T *argvars, typval_T *rettv);
60static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
61static void f_byte2line(typval_T *argvars, typval_T *rettv);
62static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
63static void f_byteidx(typval_T *argvars, typval_T *rettv);
64static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
65static void f_call(typval_T *argvars, typval_T *rettv);
66#ifdef FEAT_FLOAT
67static void f_ceil(typval_T *argvars, typval_T *rettv);
68#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020069static void f_changenr(typval_T *argvars, typval_T *rettv);
70static void f_char2nr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar1063f3d2019-05-07 22:06:52 +020071static void f_chdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020072static void f_cindent(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020073static void f_col(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020074static void f_confirm(typval_T *argvars, typval_T *rettv);
75static void f_copy(typval_T *argvars, typval_T *rettv);
76#ifdef FEAT_FLOAT
77static void f_cos(typval_T *argvars, typval_T *rettv);
78static void f_cosh(typval_T *argvars, typval_T *rettv);
79#endif
80static void f_count(typval_T *argvars, typval_T *rettv);
81static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
82static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +010083#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +020084static void f_debugbreak(typval_T *argvars, typval_T *rettv);
85#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020086static void f_deepcopy(typval_T *argvars, typval_T *rettv);
87static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +020088static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020089static void f_did_filetype(typval_T *argvars, typval_T *rettv);
90static void f_diff_filler(typval_T *argvars, typval_T *rettv);
91static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
92static void f_empty(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +020093static void f_environ(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020094static void f_escape(typval_T *argvars, typval_T *rettv);
95static void f_eval(typval_T *argvars, typval_T *rettv);
96static void f_eventhandler(typval_T *argvars, typval_T *rettv);
97static void f_executable(typval_T *argvars, typval_T *rettv);
98static void f_execute(typval_T *argvars, typval_T *rettv);
99static void f_exepath(typval_T *argvars, typval_T *rettv);
100static void f_exists(typval_T *argvars, typval_T *rettv);
101#ifdef FEAT_FLOAT
102static void f_exp(typval_T *argvars, typval_T *rettv);
103#endif
104static void f_expand(typval_T *argvars, typval_T *rettv);
Bram Moolenaar80dad482019-06-09 17:22:31 +0200105static void f_expandcmd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200106static void f_extend(typval_T *argvars, typval_T *rettv);
107static void f_feedkeys(typval_T *argvars, typval_T *rettv);
108static void f_filereadable(typval_T *argvars, typval_T *rettv);
109static void f_filewritable(typval_T *argvars, typval_T *rettv);
110static void f_filter(typval_T *argvars, typval_T *rettv);
111static void f_finddir(typval_T *argvars, typval_T *rettv);
112static void f_findfile(typval_T *argvars, typval_T *rettv);
113#ifdef FEAT_FLOAT
114static void f_float2nr(typval_T *argvars, typval_T *rettv);
115static void f_floor(typval_T *argvars, typval_T *rettv);
116static void f_fmod(typval_T *argvars, typval_T *rettv);
117#endif
118static void f_fnameescape(typval_T *argvars, typval_T *rettv);
119static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
120static void f_foldclosed(typval_T *argvars, typval_T *rettv);
121static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
122static void f_foldlevel(typval_T *argvars, typval_T *rettv);
123static void f_foldtext(typval_T *argvars, typval_T *rettv);
124static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
125static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200126static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200127static void f_function(typval_T *argvars, typval_T *rettv);
128static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
129static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200130static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200131static void f_getbufline(typval_T *argvars, typval_T *rettv);
132static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100133static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200134static void f_getchar(typval_T *argvars, typval_T *rettv);
135static void f_getcharmod(typval_T *argvars, typval_T *rettv);
136static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
137static void f_getcmdline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200138static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
139static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
140static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
141static void f_getcwd(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200142static void f_getenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200143static void f_getfontname(typval_T *argvars, typval_T *rettv);
144static void f_getfperm(typval_T *argvars, typval_T *rettv);
145static void f_getfsize(typval_T *argvars, typval_T *rettv);
146static void f_getftime(typval_T *argvars, typval_T *rettv);
147static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100148static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200149static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200150static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200151static void f_getpid(typval_T *argvars, typval_T *rettv);
152static void f_getcurpos(typval_T *argvars, typval_T *rettv);
153static void f_getpos(typval_T *argvars, typval_T *rettv);
154static void f_getqflist(typval_T *argvars, typval_T *rettv);
155static void f_getreg(typval_T *argvars, typval_T *rettv);
156static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200157static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200158static void f_gettabvar(typval_T *argvars, typval_T *rettv);
159static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100160static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200161static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100162static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200163static void f_getwinposx(typval_T *argvars, typval_T *rettv);
164static void f_getwinposy(typval_T *argvars, typval_T *rettv);
165static void f_getwinvar(typval_T *argvars, typval_T *rettv);
166static void f_glob(typval_T *argvars, typval_T *rettv);
167static void f_globpath(typval_T *argvars, typval_T *rettv);
168static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
169static void f_has(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
171static void f_hasmapto(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200172static void f_hlID(typval_T *argvars, typval_T *rettv);
173static void f_hlexists(typval_T *argvars, typval_T *rettv);
174static void f_hostname(typval_T *argvars, typval_T *rettv);
175static void f_iconv(typval_T *argvars, typval_T *rettv);
176static void f_indent(typval_T *argvars, typval_T *rettv);
177static void f_index(typval_T *argvars, typval_T *rettv);
178static void f_input(typval_T *argvars, typval_T *rettv);
179static void f_inputdialog(typval_T *argvars, typval_T *rettv);
180static void f_inputlist(typval_T *argvars, typval_T *rettv);
181static void f_inputrestore(typval_T *argvars, typval_T *rettv);
182static void f_inputsave(typval_T *argvars, typval_T *rettv);
183static void f_inputsecret(typval_T *argvars, typval_T *rettv);
184static void f_insert(typval_T *argvars, typval_T *rettv);
185static void f_invert(typval_T *argvars, typval_T *rettv);
186static void f_isdirectory(typval_T *argvars, typval_T *rettv);
187static void f_islocked(typval_T *argvars, typval_T *rettv);
188#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200189static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200190static void f_isnan(typval_T *argvars, typval_T *rettv);
191#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200192static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
193static void f_len(typval_T *argvars, typval_T *rettv);
194static void f_libcall(typval_T *argvars, typval_T *rettv);
195static void f_libcallnr(typval_T *argvars, typval_T *rettv);
196static void f_line(typval_T *argvars, typval_T *rettv);
197static void f_line2byte(typval_T *argvars, typval_T *rettv);
198static void f_lispindent(typval_T *argvars, typval_T *rettv);
199static void f_localtime(typval_T *argvars, typval_T *rettv);
200#ifdef FEAT_FLOAT
201static void f_log(typval_T *argvars, typval_T *rettv);
202static void f_log10(typval_T *argvars, typval_T *rettv);
203#endif
204#ifdef FEAT_LUA
205static void f_luaeval(typval_T *argvars, typval_T *rettv);
206#endif
207static void f_map(typval_T *argvars, typval_T *rettv);
208static void f_maparg(typval_T *argvars, typval_T *rettv);
209static void f_mapcheck(typval_T *argvars, typval_T *rettv);
210static void f_match(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200211static void f_matchend(typval_T *argvars, typval_T *rettv);
212static void f_matchlist(typval_T *argvars, typval_T *rettv);
213static void f_matchstr(typval_T *argvars, typval_T *rettv);
214static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
215static void f_max(typval_T *argvars, typval_T *rettv);
216static void f_min(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200217static void f_mkdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200218static void f_mode(typval_T *argvars, typval_T *rettv);
219#ifdef FEAT_MZSCHEME
220static void f_mzeval(typval_T *argvars, typval_T *rettv);
221#endif
222static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
223static void f_nr2char(typval_T *argvars, typval_T *rettv);
224static void f_or(typval_T *argvars, typval_T *rettv);
225static void f_pathshorten(typval_T *argvars, typval_T *rettv);
226#ifdef FEAT_PERL
227static void f_perleval(typval_T *argvars, typval_T *rettv);
228#endif
229#ifdef FEAT_FLOAT
230static void f_pow(typval_T *argvars, typval_T *rettv);
231#endif
232static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
233static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200234static void f_pum_getpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200235static void f_pumvisible(typval_T *argvars, typval_T *rettv);
236#ifdef FEAT_PYTHON3
237static void f_py3eval(typval_T *argvars, typval_T *rettv);
238#endif
239#ifdef FEAT_PYTHON
240static void f_pyeval(typval_T *argvars, typval_T *rettv);
241#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100242#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
243static void f_pyxeval(typval_T *argvars, typval_T *rettv);
244#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200245static void f_range(typval_T *argvars, typval_T *rettv);
Bram Moolenaar543c9b12019-04-05 22:50:40 +0200246static void f_readdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200247static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200248static void f_reg_executing(typval_T *argvars, typval_T *rettv);
249static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200250static void f_reltime(typval_T *argvars, typval_T *rettv);
251#ifdef FEAT_FLOAT
252static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
253#endif
254static void f_reltimestr(typval_T *argvars, typval_T *rettv);
255static void f_remote_expr(typval_T *argvars, typval_T *rettv);
256static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
257static void f_remote_peek(typval_T *argvars, typval_T *rettv);
258static void f_remote_read(typval_T *argvars, typval_T *rettv);
259static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100260static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200261static void f_remove(typval_T *argvars, typval_T *rettv);
262static void f_rename(typval_T *argvars, typval_T *rettv);
263static void f_repeat(typval_T *argvars, typval_T *rettv);
264static void f_resolve(typval_T *argvars, typval_T *rettv);
265static void f_reverse(typval_T *argvars, typval_T *rettv);
266#ifdef FEAT_FLOAT
267static void f_round(typval_T *argvars, typval_T *rettv);
268#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100269#ifdef FEAT_RUBY
270static void f_rubyeval(typval_T *argvars, typval_T *rettv);
271#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200272static void f_screenattr(typval_T *argvars, typval_T *rettv);
273static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100274static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200275static void f_screencol(typval_T *argvars, typval_T *rettv);
276static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100277static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200278static void f_search(typval_T *argvars, typval_T *rettv);
279static void f_searchdecl(typval_T *argvars, typval_T *rettv);
280static void f_searchpair(typval_T *argvars, typval_T *rettv);
281static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
282static void f_searchpos(typval_T *argvars, typval_T *rettv);
283static void f_server2client(typval_T *argvars, typval_T *rettv);
284static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200285static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200286static void f_setbufvar(typval_T *argvars, typval_T *rettv);
287static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
288static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar691ddee2019-05-09 14:52:41 +0200289static void f_setenv(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200290static void f_setfperm(typval_T *argvars, typval_T *rettv);
291static void f_setline(typval_T *argvars, typval_T *rettv);
292static void f_setloclist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200293static void f_setpos(typval_T *argvars, typval_T *rettv);
294static void f_setqflist(typval_T *argvars, typval_T *rettv);
295static void f_setreg(typval_T *argvars, typval_T *rettv);
296static void f_settabvar(typval_T *argvars, typval_T *rettv);
297static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100298static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200299static void f_setwinvar(typval_T *argvars, typval_T *rettv);
300#ifdef FEAT_CRYPT
301static void f_sha256(typval_T *argvars, typval_T *rettv);
302#endif /* FEAT_CRYPT */
303static void f_shellescape(typval_T *argvars, typval_T *rettv);
304static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
305static void f_simplify(typval_T *argvars, typval_T *rettv);
306#ifdef FEAT_FLOAT
307static void f_sin(typval_T *argvars, typval_T *rettv);
308static void f_sinh(typval_T *argvars, typval_T *rettv);
309#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200310static void f_soundfold(typval_T *argvars, typval_T *rettv);
311static void f_spellbadword(typval_T *argvars, typval_T *rettv);
312static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
313static void f_split(typval_T *argvars, typval_T *rettv);
314#ifdef FEAT_FLOAT
315static void f_sqrt(typval_T *argvars, typval_T *rettv);
316static void f_str2float(typval_T *argvars, typval_T *rettv);
317#endif
Bram Moolenaar9d401282019-04-06 13:18:12 +0200318static void f_str2list(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200319static void f_str2nr(typval_T *argvars, typval_T *rettv);
320static void f_strchars(typval_T *argvars, typval_T *rettv);
321#ifdef HAVE_STRFTIME
322static void f_strftime(typval_T *argvars, typval_T *rettv);
323#endif
324static void f_strgetchar(typval_T *argvars, typval_T *rettv);
325static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200326static void f_strlen(typval_T *argvars, typval_T *rettv);
327static void f_strcharpart(typval_T *argvars, typval_T *rettv);
328static void f_strpart(typval_T *argvars, typval_T *rettv);
329static void f_strridx(typval_T *argvars, typval_T *rettv);
330static void f_strtrans(typval_T *argvars, typval_T *rettv);
331static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
332static void f_strwidth(typval_T *argvars, typval_T *rettv);
333static void f_submatch(typval_T *argvars, typval_T *rettv);
334static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200335static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200336static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200337static void f_synID(typval_T *argvars, typval_T *rettv);
338static void f_synIDattr(typval_T *argvars, typval_T *rettv);
339static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
340static void f_synstack(typval_T *argvars, typval_T *rettv);
341static void f_synconcealed(typval_T *argvars, typval_T *rettv);
342static void f_system(typval_T *argvars, typval_T *rettv);
343static void f_systemlist(typval_T *argvars, typval_T *rettv);
344static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
345static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
346static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
347static void f_taglist(typval_T *argvars, typval_T *rettv);
348static void f_tagfiles(typval_T *argvars, typval_T *rettv);
349static void f_tempname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200350#ifdef FEAT_FLOAT
351static void f_tan(typval_T *argvars, typval_T *rettv);
352static void f_tanh(typval_T *argvars, typval_T *rettv);
353#endif
354#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200355static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200356static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200357static void f_timer_start(typval_T *argvars, typval_T *rettv);
358static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200359static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200360#endif
361static void f_tolower(typval_T *argvars, typval_T *rettv);
362static void f_toupper(typval_T *argvars, typval_T *rettv);
363static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100364static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200365#ifdef FEAT_FLOAT
366static void f_trunc(typval_T *argvars, typval_T *rettv);
367#endif
368static void f_type(typval_T *argvars, typval_T *rettv);
369static void f_undofile(typval_T *argvars, typval_T *rettv);
370static void f_undotree(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200371static void f_virtcol(typval_T *argvars, typval_T *rettv);
372static void f_visualmode(typval_T *argvars, typval_T *rettv);
373static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
Bram Moolenaar868b7b62019-05-29 21:44:40 +0200374static void f_win_execute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200375static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
376static void f_win_getid(typval_T *argvars, typval_T *rettv);
377static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
378static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
379static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100380static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200381static void f_winbufnr(typval_T *argvars, typval_T *rettv);
382static void f_wincol(typval_T *argvars, typval_T *rettv);
383static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200384static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200385static void f_winline(typval_T *argvars, typval_T *rettv);
386static void f_winnr(typval_T *argvars, typval_T *rettv);
387static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
388static void f_winrestview(typval_T *argvars, typval_T *rettv);
389static void f_winsaveview(typval_T *argvars, typval_T *rettv);
390static void f_winwidth(typval_T *argvars, typval_T *rettv);
391static void f_writefile(typval_T *argvars, typval_T *rettv);
392static void f_wordcount(typval_T *argvars, typval_T *rettv);
393static void f_xor(typval_T *argvars, typval_T *rettv);
394
395/*
396 * Array with names and number of arguments of all internal functions
397 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
398 */
Bram Moolenaarac92e252019-08-03 21:58:38 +0200399typedef struct
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200400{
Bram Moolenaar25e42232019-08-04 15:04:10 +0200401 char *f_name; // function name
402 char f_min_argc; // minimal number of arguments
403 char f_max_argc; // maximal number of arguments
404 char f_argtype; // for method: FEARG_ values
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200405 void (*f_func)(typval_T *args, typval_T *rvar);
Bram Moolenaar25e42232019-08-04 15:04:10 +0200406 // implementation of function
Bram Moolenaarac92e252019-08-03 21:58:38 +0200407} funcentry_T;
408
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200409// values for f_argtype; zero means it cannot be used as a method
410#define FEARG_1 1 // base is the first argument
411#define FEARG_2 2 // base is the second argument
Bram Moolenaar24278d22019-08-16 21:49:22 +0200412#define FEARG_3 3 // base is the third argument
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200413#define FEARG_LAST 9 // base is the last argument
414
Bram Moolenaarac92e252019-08-03 21:58:38 +0200415static funcentry_T global_functions[] =
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200416{
417#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200418 {"abs", 1, 1, FEARG_1, f_abs},
419 {"acos", 1, 1, FEARG_1, f_acos}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200420#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200421 {"add", 2, 2, FEARG_1, f_add},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200422 {"and", 2, 2, FEARG_1, f_and},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200423 {"append", 2, 2, FEARG_LAST, f_append},
424 {"appendbufline", 3, 3, FEARG_LAST, f_appendbufline},
425 {"argc", 0, 1, 0, f_argc},
426 {"argidx", 0, 0, 0, f_argidx},
427 {"arglistid", 0, 2, 0, f_arglistid},
428 {"argv", 0, 2, 0, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200429#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200430 {"asin", 1, 1, FEARG_1, f_asin}, // WJMc
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200431#endif
Bram Moolenaar24278d22019-08-16 21:49:22 +0200432 {"assert_beeps", 1, 2, FEARG_1, f_assert_beeps},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200433 {"assert_equal", 2, 3, FEARG_2, f_assert_equal},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200434 {"assert_equalfile", 2, 2, FEARG_1, f_assert_equalfile},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200435 {"assert_exception", 1, 2, 0, f_assert_exception},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200436 {"assert_fails", 1, 3, FEARG_1, f_assert_fails},
437 {"assert_false", 1, 2, FEARG_1, f_assert_false},
438 {"assert_inrange", 3, 4, FEARG_3, f_assert_inrange},
439 {"assert_match", 2, 3, FEARG_2, f_assert_match},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200440 {"assert_notequal", 2, 3, FEARG_2, f_assert_notequal},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200441 {"assert_notmatch", 2, 3, FEARG_2, f_assert_notmatch},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200442 {"assert_report", 1, 1, FEARG_1, f_assert_report},
Bram Moolenaar24278d22019-08-16 21:49:22 +0200443 {"assert_true", 1, 2, FEARG_1, f_assert_true},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200444#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200445 {"atan", 1, 1, FEARG_1, f_atan},
446 {"atan2", 2, 2, FEARG_1, f_atan2},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200447#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100448#ifdef FEAT_BEVAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200449 {"balloon_gettext", 0, 0, 0, f_balloon_gettext},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200450 {"balloon_show", 1, 1, FEARG_1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100451# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200452 {"balloon_split", 1, 1, FEARG_1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100453# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100454#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200455 {"browse", 4, 4, 0, f_browse},
456 {"browsedir", 2, 2, 0, f_browsedir},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200457 {"bufadd", 1, 1, FEARG_1, f_bufadd},
458 {"bufexists", 1, 1, FEARG_1, f_bufexists},
459 {"buffer_exists", 1, 1, FEARG_1, f_bufexists}, // obsolete
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200460 {"buffer_name", 1, 1, 0, f_bufname}, // obsolete
461 {"buffer_number", 1, 1, 0, f_bufnr}, // obsolete
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200462 {"buflisted", 1, 1, FEARG_1, f_buflisted},
463 {"bufload", 1, 1, FEARG_1, f_bufload},
464 {"bufloaded", 1, 1, FEARG_1, f_bufloaded},
465 {"bufname", 1, 1, FEARG_1, f_bufname},
466 {"bufnr", 1, 2, FEARG_1, f_bufnr},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200467 {"bufwinid", 1, 1, FEARG_1, f_bufwinid},
468 {"bufwinnr", 1, 1, FEARG_1, f_bufwinnr},
Bram Moolenaar64b4d732019-08-22 22:18:17 +0200469 {"byte2line", 1, 1, FEARG_1, f_byte2line},
470 {"byteidx", 2, 2, FEARG_1, f_byteidx},
471 {"byteidxcomp", 2, 2, FEARG_1, f_byteidxcomp},
472 {"call", 2, 3, FEARG_1, f_call},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200473#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200474 {"ceil", 1, 1, FEARG_1, f_ceil},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200475#endif
476#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200477 {"ch_canread", 1, 1, FEARG_1, f_ch_canread},
478 {"ch_close", 1, 1, FEARG_1, f_ch_close},
479 {"ch_close_in", 1, 1, FEARG_1, f_ch_close_in},
480 {"ch_evalexpr", 2, 3, FEARG_1, f_ch_evalexpr},
481 {"ch_evalraw", 2, 3, FEARG_1, f_ch_evalraw},
482 {"ch_getbufnr", 2, 2, FEARG_1, f_ch_getbufnr},
483 {"ch_getjob", 1, 1, FEARG_1, f_ch_getjob},
484 {"ch_info", 1, 1, FEARG_1, f_ch_info},
485 {"ch_log", 1, 2, FEARG_1, f_ch_log},
486 {"ch_logfile", 1, 2, FEARG_1, f_ch_logfile},
487 {"ch_open", 1, 2, FEARG_1, f_ch_open},
488 {"ch_read", 1, 2, FEARG_1, f_ch_read},
489 {"ch_readblob", 1, 2, FEARG_1, f_ch_readblob},
490 {"ch_readraw", 1, 2, FEARG_1, f_ch_readraw},
491 {"ch_sendexpr", 2, 3, FEARG_1, f_ch_sendexpr},
492 {"ch_sendraw", 2, 3, FEARG_1, f_ch_sendraw},
493 {"ch_setoptions", 2, 2, FEARG_1, f_ch_setoptions},
494 {"ch_status", 1, 2, FEARG_1, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200495#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200496 {"changenr", 0, 0, 0, f_changenr},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200497 {"char2nr", 1, 2, FEARG_1, f_char2nr},
498 {"chdir", 1, 1, FEARG_1, f_chdir},
499 {"cindent", 1, 1, FEARG_1, f_cindent},
500 {"clearmatches", 0, 1, FEARG_1, f_clearmatches},
501 {"col", 1, 1, FEARG_1, f_col},
502 {"complete", 2, 2, FEARG_2, f_complete},
503 {"complete_add", 1, 1, FEARG_1, f_complete_add},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200504 {"complete_check", 0, 0, 0, f_complete_check},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200505 {"complete_info", 0, 1, FEARG_1, f_complete_info},
506 {"confirm", 1, 4, FEARG_1, f_confirm},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200507 {"copy", 1, 1, FEARG_1, f_copy},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200508#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200509 {"cos", 1, 1, FEARG_1, f_cos},
510 {"cosh", 1, 1, FEARG_1, f_cosh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200511#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200512 {"count", 2, 4, FEARG_1, f_count},
513 {"cscope_connection",0,3, 0, f_cscope_connection},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200514 {"cursor", 1, 3, FEARG_1, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100515#ifdef MSWIN
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200516 {"debugbreak", 1, 1, FEARG_1, f_debugbreak},
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200517#endif
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200518 {"deepcopy", 1, 2, FEARG_1, f_deepcopy},
519 {"delete", 1, 2, FEARG_1, f_delete},
520 {"deletebufline", 2, 3, FEARG_1, f_deletebufline},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200521 {"did_filetype", 0, 0, 0, f_did_filetype},
Bram Moolenaar1a3a8912019-08-23 22:31:37 +0200522 {"diff_filler", 1, 1, FEARG_1, f_diff_filler},
523 {"diff_hlID", 2, 2, FEARG_1, f_diff_hlID},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200524 {"empty", 1, 1, FEARG_1, f_empty},
525 {"environ", 0, 0, 0, f_environ},
Bram Moolenaara4208962019-08-24 20:50:19 +0200526 {"escape", 2, 2, FEARG_1, f_escape},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200527 {"eval", 1, 1, FEARG_1, f_eval},
528 {"eventhandler", 0, 0, 0, f_eventhandler},
Bram Moolenaara4208962019-08-24 20:50:19 +0200529 {"executable", 1, 1, FEARG_1, f_executable},
530 {"execute", 1, 2, FEARG_1, f_execute},
531 {"exepath", 1, 1, FEARG_1, f_exepath},
532 {"exists", 1, 1, FEARG_1, f_exists},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200534 {"exp", 1, 1, FEARG_1, f_exp},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200535#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200536 {"expand", 1, 3, FEARG_1, f_expand},
537 {"expandcmd", 1, 1, FEARG_1, f_expandcmd},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200538 {"extend", 2, 3, FEARG_1, f_extend},
Bram Moolenaara4208962019-08-24 20:50:19 +0200539 {"feedkeys", 1, 2, FEARG_1, f_feedkeys},
540 {"file_readable", 1, 1, FEARG_1, f_filereadable}, // obsolete
541 {"filereadable", 1, 1, FEARG_1, f_filereadable},
542 {"filewritable", 1, 1, FEARG_1, f_filewritable},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200543 {"filter", 2, 2, FEARG_1, f_filter},
Bram Moolenaara4208962019-08-24 20:50:19 +0200544 {"finddir", 1, 3, FEARG_1, f_finddir},
545 {"findfile", 1, 3, FEARG_1, f_findfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200546#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200547 {"float2nr", 1, 1, FEARG_1, f_float2nr},
548 {"floor", 1, 1, FEARG_1, f_floor},
549 {"fmod", 2, 2, FEARG_1, f_fmod},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200550#endif
Bram Moolenaara4208962019-08-24 20:50:19 +0200551 {"fnameescape", 1, 1, FEARG_1, f_fnameescape},
552 {"fnamemodify", 2, 2, FEARG_1, f_fnamemodify},
553 {"foldclosed", 1, 1, FEARG_1, f_foldclosed},
554 {"foldclosedend", 1, 1, FEARG_1, f_foldclosedend},
555 {"foldlevel", 1, 1, FEARG_1, f_foldlevel},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200556 {"foldtext", 0, 0, 0, f_foldtext},
Bram Moolenaara4208962019-08-24 20:50:19 +0200557 {"foldtextresult", 1, 1, FEARG_1, f_foldtextresult},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200558 {"foreground", 0, 0, 0, f_foreground},
Bram Moolenaara4208962019-08-24 20:50:19 +0200559 {"funcref", 1, 3, FEARG_1, f_funcref},
560 {"function", 1, 3, FEARG_1, f_function},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200561 {"garbagecollect", 0, 1, 0, f_garbagecollect},
562 {"get", 2, 3, FEARG_1, f_get},
563 {"getbufinfo", 0, 1, 0, f_getbufinfo},
564 {"getbufline", 2, 3, 0, f_getbufline},
565 {"getbufvar", 2, 3, 0, f_getbufvar},
566 {"getchangelist", 1, 1, 0, f_getchangelist},
567 {"getchar", 0, 1, 0, f_getchar},
568 {"getcharmod", 0, 0, 0, f_getcharmod},
569 {"getcharsearch", 0, 0, 0, f_getcharsearch},
570 {"getcmdline", 0, 0, 0, f_getcmdline},
571 {"getcmdpos", 0, 0, 0, f_getcmdpos},
572 {"getcmdtype", 0, 0, 0, f_getcmdtype},
573 {"getcmdwintype", 0, 0, 0, f_getcmdwintype},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200574 {"getcompletion", 2, 3, 0, f_getcompletion},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200575 {"getcurpos", 0, 0, 0, f_getcurpos},
576 {"getcwd", 0, 2, 0, f_getcwd},
577 {"getenv", 1, 1, 0, f_getenv},
578 {"getfontname", 0, 1, 0, f_getfontname},
579 {"getfperm", 1, 1, 0, f_getfperm},
580 {"getfsize", 1, 1, 0, f_getfsize},
581 {"getftime", 1, 1, 0, f_getftime},
582 {"getftype", 1, 1, 0, f_getftype},
583 {"getjumplist", 0, 2, 0, f_getjumplist},
584 {"getline", 1, 2, 0, f_getline},
585 {"getloclist", 1, 2, 0, f_getloclist},
586 {"getmatches", 0, 1, 0, f_getmatches},
587 {"getpid", 0, 0, 0, f_getpid},
588 {"getpos", 1, 1, 0, f_getpos},
589 {"getqflist", 0, 1, 0, f_getqflist},
590 {"getreg", 0, 3, 0, f_getreg},
591 {"getregtype", 0, 1, 0, f_getregtype},
592 {"gettabinfo", 0, 1, 0, f_gettabinfo},
593 {"gettabvar", 2, 3, 0, f_gettabvar},
594 {"gettabwinvar", 3, 4, 0, f_gettabwinvar},
595 {"gettagstack", 0, 1, 0, f_gettagstack},
596 {"getwininfo", 0, 1, 0, f_getwininfo},
597 {"getwinpos", 0, 1, 0, f_getwinpos},
598 {"getwinposx", 0, 0, 0, f_getwinposx},
599 {"getwinposy", 0, 0, 0, f_getwinposy},
600 {"getwinvar", 2, 3, 0, f_getwinvar},
601 {"glob", 1, 4, 0, f_glob},
602 {"glob2regpat", 1, 1, 0, f_glob2regpat},
603 {"globpath", 2, 5, 0, f_globpath},
604 {"has", 1, 1, 0, f_has},
605 {"has_key", 2, 2, FEARG_1, f_has_key},
606 {"haslocaldir", 0, 2, 0, f_haslocaldir},
607 {"hasmapto", 1, 3, 0, f_hasmapto},
608 {"highlightID", 1, 1, 0, f_hlID}, // obsolete
609 {"highlight_exists",1, 1, 0, f_hlexists}, // obsolete
610 {"histadd", 2, 2, 0, f_histadd},
611 {"histdel", 1, 2, 0, f_histdel},
612 {"histget", 1, 2, 0, f_histget},
613 {"histnr", 1, 1, 0, f_histnr},
614 {"hlID", 1, 1, 0, f_hlID},
615 {"hlexists", 1, 1, 0, f_hlexists},
616 {"hostname", 0, 0, 0, f_hostname},
617 {"iconv", 3, 3, 0, f_iconv},
618 {"indent", 1, 1, 0, f_indent},
619 {"index", 2, 4, FEARG_1, f_index},
620 {"input", 1, 3, 0, f_input},
621 {"inputdialog", 1, 3, 0, f_inputdialog},
622 {"inputlist", 1, 1, 0, f_inputlist},
623 {"inputrestore", 0, 0, 0, f_inputrestore},
624 {"inputsave", 0, 0, 0, f_inputsave},
625 {"inputsecret", 1, 2, 0, f_inputsecret},
626 {"insert", 2, 3, FEARG_1, f_insert},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200627 {"invert", 1, 1, FEARG_1, f_invert},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200628 {"isdirectory", 1, 1, 0, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200629#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200630 {"isinf", 1, 1, FEARG_1, f_isinf},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200631#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200632 {"islocked", 1, 1, 0, f_islocked},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200633#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200634 {"isnan", 1, 1, FEARG_1, f_isnan},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200635#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200636 {"items", 1, 1, FEARG_1, f_items},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200637#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar570497a2019-08-22 22:55:13 +0200638 {"job_getchannel", 1, 1, FEARG_1, f_job_getchannel},
639 {"job_info", 0, 1, FEARG_1, f_job_info},
640 {"job_setoptions", 2, 2, FEARG_1, f_job_setoptions},
641 {"job_start", 1, 2, FEARG_1, f_job_start},
642 {"job_status", 1, 1, FEARG_1, f_job_status},
643 {"job_stop", 1, 2, FEARG_1, f_job_stop},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200644#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200645 {"join", 1, 2, FEARG_1, f_join},
646 {"js_decode", 1, 1, 0, f_js_decode},
647 {"js_encode", 1, 1, 0, f_js_encode},
648 {"json_decode", 1, 1, 0, f_json_decode},
649 {"json_encode", 1, 1, 0, f_json_encode},
650 {"keys", 1, 1, FEARG_1, f_keys},
651 {"last_buffer_nr", 0, 0, 0, f_last_buffer_nr}, // obsolete
652 {"len", 1, 1, FEARG_1, f_len},
653 {"libcall", 3, 3, 0, f_libcall},
654 {"libcallnr", 3, 3, 0, f_libcallnr},
655 {"line", 1, 1, 0, f_line},
656 {"line2byte", 1, 1, 0, f_line2byte},
657 {"lispindent", 1, 1, 0, f_lispindent},
658 {"list2str", 1, 2, 0, f_list2str},
659 {"listener_add", 1, 2, 0, f_listener_add},
660 {"listener_flush", 0, 1, 0, f_listener_flush},
661 {"listener_remove", 1, 1, 0, f_listener_remove},
662 {"localtime", 0, 0, 0, f_localtime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200663#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200664 {"log", 1, 1, FEARG_1, f_log},
665 {"log10", 1, 1, FEARG_1, f_log10},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200666#endif
667#ifdef FEAT_LUA
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200668 {"luaeval", 1, 2, 0, f_luaeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200669#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200670 {"map", 2, 2, FEARG_1, f_map},
671 {"maparg", 1, 4, 0, f_maparg},
672 {"mapcheck", 1, 3, 0, f_mapcheck},
673 {"match", 2, 4, 0, f_match},
674 {"matchadd", 2, 5, 0, f_matchadd},
675 {"matchaddpos", 2, 5, 0, f_matchaddpos},
676 {"matcharg", 1, 1, 0, f_matcharg},
677 {"matchdelete", 1, 2, 0, f_matchdelete},
678 {"matchend", 2, 4, 0, f_matchend},
679 {"matchlist", 2, 4, 0, f_matchlist},
680 {"matchstr", 2, 4, 0, f_matchstr},
681 {"matchstrpos", 2, 4, 0, f_matchstrpos},
682 {"max", 1, 1, FEARG_1, f_max},
683 {"min", 1, 1, FEARG_1, f_min},
684 {"mkdir", 1, 3, 0, f_mkdir},
685 {"mode", 0, 1, 0, f_mode},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200686#ifdef FEAT_MZSCHEME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200687 {"mzeval", 1, 1, 0, f_mzeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200689 {"nextnonblank", 1, 1, 0, f_nextnonblank},
690 {"nr2char", 1, 2, 0, f_nr2char},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200691 {"or", 2, 2, FEARG_1, f_or},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200692 {"pathshorten", 1, 1, 0, f_pathshorten},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693#ifdef FEAT_PERL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200694 {"perleval", 1, 1, 0, f_perleval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200695#endif
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200696#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200697 {"popup_atcursor", 2, 2, 0, f_popup_atcursor},
698 {"popup_beval", 2, 2, 0, f_popup_beval},
699 {"popup_clear", 0, 0, 0, f_popup_clear},
700 {"popup_close", 1, 2, 0, f_popup_close},
701 {"popup_create", 2, 2, 0, f_popup_create},
702 {"popup_dialog", 2, 2, 0, f_popup_dialog},
703 {"popup_filter_menu", 2, 2, 0, f_popup_filter_menu},
704 {"popup_filter_yesno", 2, 2, 0, f_popup_filter_yesno},
Bram Moolenaarc7c5f102019-08-21 18:31:03 +0200705 {"popup_findinfo", 0, 0, 0, f_popup_findinfo},
706 {"popup_findpreview", 0, 0, 0, f_popup_findpreview},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200707 {"popup_getoptions", 1, 1, 0, f_popup_getoptions},
708 {"popup_getpos", 1, 1, 0, f_popup_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200709 {"popup_hide", 1, 1, 0, f_popup_hide},
710 {"popup_locate", 2, 2, 0, f_popup_locate},
711 {"popup_menu", 2, 2, 0, f_popup_menu},
712 {"popup_move", 2, 2, 0, f_popup_move},
713 {"popup_notification", 2, 2, 0, f_popup_notification},
714 {"popup_setoptions", 2, 2, 0, f_popup_setoptions},
715 {"popup_settext", 2, 2, 0, f_popup_settext},
716 {"popup_show", 1, 1, 0, f_popup_show},
Bram Moolenaar4d784b22019-05-25 19:51:39 +0200717#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200718#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200719 {"pow", 2, 2, FEARG_1, f_pow},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200720#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200721 {"prevnonblank", 1, 1, 0, f_prevnonblank},
Bram Moolenaarfd8ca212019-08-10 00:13:30 +0200722 {"printf", 1, 19, FEARG_2, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200723#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200724 {"prompt_setcallback", 2, 2, 0, f_prompt_setcallback},
725 {"prompt_setinterrupt", 2, 2, 0, f_prompt_setinterrupt},
726 {"prompt_setprompt", 2, 2, 0, f_prompt_setprompt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200727#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100728#ifdef FEAT_TEXT_PROP
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200729 {"prop_add", 3, 3, 0, f_prop_add},
730 {"prop_clear", 1, 3, 0, f_prop_clear},
731 {"prop_list", 1, 2, 0, f_prop_list},
732 {"prop_remove", 1, 3, 0, f_prop_remove},
733 {"prop_type_add", 2, 2, 0, f_prop_type_add},
734 {"prop_type_change", 2, 2, 0, f_prop_type_change},
735 {"prop_type_delete", 1, 2, 0, f_prop_type_delete},
736 {"prop_type_get", 1, 2, 0, f_prop_type_get},
737 {"prop_type_list", 0, 1, 0, f_prop_type_list},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100738#endif
Bram Moolenaare9bd5722019-08-17 19:36:06 +0200739 {"pum_getpos", 0, 0, 0, f_pum_getpos},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200740 {"pumvisible", 0, 0, 0, f_pumvisible},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200741#ifdef FEAT_PYTHON3
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200742 {"py3eval", 1, 1, 0, f_py3eval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200743#endif
744#ifdef FEAT_PYTHON
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200745 {"pyeval", 1, 1, 0, f_pyeval},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200746#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100747#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200748 {"pyxeval", 1, 1, 0, f_pyxeval},
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100749#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200750 {"range", 1, 3, 0, f_range},
751 {"readdir", 1, 2, 0, f_readdir},
752 {"readfile", 1, 3, 0, f_readfile},
753 {"reg_executing", 0, 0, 0, f_reg_executing},
754 {"reg_recording", 0, 0, 0, f_reg_recording},
755 {"reltime", 0, 2, 0, f_reltime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200756#ifdef FEAT_FLOAT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200757 {"reltimefloat", 1, 1, 0, f_reltimefloat},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200758#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200759 {"reltimestr", 1, 1, 0, f_reltimestr},
760 {"remote_expr", 2, 4, 0, f_remote_expr},
761 {"remote_foreground", 1, 1, 0, f_remote_foreground},
762 {"remote_peek", 1, 2, 0, f_remote_peek},
763 {"remote_read", 1, 2, 0, f_remote_read},
764 {"remote_send", 2, 3, 0, f_remote_send},
765 {"remote_startserver", 1, 1, 0, f_remote_startserver},
766 {"remove", 2, 3, FEARG_1, f_remove},
767 {"rename", 2, 2, 0, f_rename},
768 {"repeat", 2, 2, FEARG_1, f_repeat},
769 {"resolve", 1, 1, 0, f_resolve},
770 {"reverse", 1, 1, FEARG_1, f_reverse},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200771#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200772 {"round", 1, 1, FEARG_1, f_round},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200773#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100774#ifdef FEAT_RUBY
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200775 {"rubyeval", 1, 1, 0, f_rubyeval},
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100776#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200777 {"screenattr", 2, 2, 0, f_screenattr},
778 {"screenchar", 2, 2, 0, f_screenchar},
779 {"screenchars", 2, 2, 0, f_screenchars},
780 {"screencol", 0, 0, 0, f_screencol},
781 {"screenpos", 3, 3, 0, f_screenpos},
782 {"screenrow", 0, 0, 0, f_screenrow},
783 {"screenstring", 2, 2, 0, f_screenstring},
784 {"search", 1, 4, 0, f_search},
785 {"searchdecl", 1, 3, 0, f_searchdecl},
786 {"searchpair", 3, 7, 0, f_searchpair},
787 {"searchpairpos", 3, 7, 0, f_searchpairpos},
788 {"searchpos", 1, 4, 0, f_searchpos},
789 {"server2client", 2, 2, 0, f_server2client},
790 {"serverlist", 0, 0, 0, f_serverlist},
791 {"setbufline", 3, 3, 0, f_setbufline},
792 {"setbufvar", 3, 3, 0, f_setbufvar},
793 {"setcharsearch", 1, 1, 0, f_setcharsearch},
794 {"setcmdpos", 1, 1, 0, f_setcmdpos},
795 {"setenv", 2, 2, 0, f_setenv},
796 {"setfperm", 2, 2, 0, f_setfperm},
797 {"setline", 2, 2, 0, f_setline},
798 {"setloclist", 2, 4, 0, f_setloclist},
799 {"setmatches", 1, 2, 0, f_setmatches},
800 {"setpos", 2, 2, 0, f_setpos},
801 {"setqflist", 1, 3, 0, f_setqflist},
802 {"setreg", 2, 3, 0, f_setreg},
803 {"settabvar", 3, 3, 0, f_settabvar},
804 {"settabwinvar", 4, 4, 0, f_settabwinvar},
805 {"settagstack", 2, 3, 0, f_settagstack},
806 {"setwinvar", 3, 3, 0, f_setwinvar},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807#ifdef FEAT_CRYPT
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200808 {"sha256", 1, 1, 0, f_sha256},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200809#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200810 {"shellescape", 1, 2, 0, f_shellescape},
811 {"shiftwidth", 0, 1, 0, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100812#ifdef FEAT_SIGNS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200813 {"sign_define", 1, 2, 0, f_sign_define},
814 {"sign_getdefined", 0, 1, 0, f_sign_getdefined},
815 {"sign_getplaced", 0, 2, 0, f_sign_getplaced},
816 {"sign_jump", 3, 3, 0, f_sign_jump},
817 {"sign_place", 4, 5, 0, f_sign_place},
818 {"sign_placelist", 1, 1, 0, f_sign_placelist},
819 {"sign_undefine", 0, 1, 0, f_sign_undefine},
820 {"sign_unplace", 1, 2, 0, f_sign_unplace},
821 {"sign_unplacelist", 1, 2, 0, f_sign_unplacelist},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100822#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200823 {"simplify", 1, 1, 0, f_simplify},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200824#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200825 {"sin", 1, 1, FEARG_1, f_sin},
826 {"sinh", 1, 1, FEARG_1, f_sinh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200828 {"sort", 1, 3, FEARG_1, f_sort},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200829#ifdef FEAT_SOUND
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200830 {"sound_clear", 0, 0, 0, f_sound_clear},
831 {"sound_playevent", 1, 2, 0, f_sound_playevent},
832 {"sound_playfile", 1, 2, 0, f_sound_playfile},
833 {"sound_stop", 1, 1, 0, f_sound_stop},
Bram Moolenaar427f5b62019-06-09 13:43:51 +0200834#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200835 {"soundfold", 1, 1, 0, f_soundfold},
836 {"spellbadword", 0, 1, 0, f_spellbadword},
837 {"spellsuggest", 1, 3, 0, f_spellsuggest},
838 {"split", 1, 3, FEARG_1, f_split},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200839#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200840 {"sqrt", 1, 1, FEARG_1, f_sqrt},
841 {"str2float", 1, 1, FEARG_1, f_str2float},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200842#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200843 {"str2list", 1, 2, FEARG_1, f_str2list},
844 {"str2nr", 1, 2, 0, f_str2nr},
845 {"strcharpart", 2, 3, 0, f_strcharpart},
846 {"strchars", 1, 2, 0, f_strchars},
847 {"strdisplaywidth", 1, 2, 0, f_strdisplaywidth},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200848#ifdef HAVE_STRFTIME
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200849 {"strftime", 1, 2, 0, f_strftime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200851 {"strgetchar", 2, 2, 0, f_strgetchar},
852 {"stridx", 2, 3, 0, f_stridx},
853 {"string", 1, 1, FEARG_1, f_string},
854 {"strlen", 1, 1, FEARG_1, f_strlen},
855 {"strpart", 2, 3, 0, f_strpart},
856 {"strridx", 2, 3, 0, f_strridx},
857 {"strtrans", 1, 1, FEARG_1, f_strtrans},
858 {"strwidth", 1, 1, FEARG_1, f_strwidth},
859 {"submatch", 1, 2, 0, f_submatch},
860 {"substitute", 4, 4, FEARG_1, f_substitute},
861 {"swapinfo", 1, 1, 0, f_swapinfo},
862 {"swapname", 1, 1, 0, f_swapname},
863 {"synID", 3, 3, 0, f_synID},
864 {"synIDattr", 2, 3, FEARG_1, f_synIDattr},
865 {"synIDtrans", 1, 1, FEARG_1, f_synIDtrans},
866 {"synconcealed", 2, 2, 0, f_synconcealed},
867 {"synstack", 2, 2, 0, f_synstack},
868 {"system", 1, 2, FEARG_1, f_system},
869 {"systemlist", 1, 2, FEARG_1, f_systemlist},
870 {"tabpagebuflist", 0, 1, 0, f_tabpagebuflist},
871 {"tabpagenr", 0, 1, 0, f_tabpagenr},
872 {"tabpagewinnr", 1, 2, 0, f_tabpagewinnr},
873 {"tagfiles", 0, 0, 0, f_tagfiles},
874 {"taglist", 1, 2, 0, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200875#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200876 {"tan", 1, 1, FEARG_1, f_tan},
877 {"tanh", 1, 1, FEARG_1, f_tanh},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200878#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200879 {"tempname", 0, 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200880#ifdef FEAT_TERMINAL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200881 {"term_dumpdiff", 2, 3, 0, f_term_dumpdiff},
882 {"term_dumpload", 1, 2, 0, f_term_dumpload},
883 {"term_dumpwrite", 2, 3, 0, f_term_dumpwrite},
884 {"term_getaltscreen", 1, 1, 0, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200885# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200886 {"term_getansicolors", 1, 1, 0, f_term_getansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200887# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200888 {"term_getattr", 2, 2, 0, f_term_getattr},
889 {"term_getcursor", 1, 1, 0, f_term_getcursor},
890 {"term_getjob", 1, 1, 0, f_term_getjob},
891 {"term_getline", 2, 2, 0, f_term_getline},
892 {"term_getscrolled", 1, 1, 0, f_term_getscrolled},
893 {"term_getsize", 1, 1, 0, f_term_getsize},
894 {"term_getstatus", 1, 1, 0, f_term_getstatus},
895 {"term_gettitle", 1, 1, 0, f_term_gettitle},
896 {"term_gettty", 1, 2, 0, f_term_gettty},
897 {"term_list", 0, 0, 0, f_term_list},
898 {"term_scrape", 2, 2, 0, f_term_scrape},
899 {"term_sendkeys", 2, 2, 0, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200900# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200901 {"term_setansicolors", 2, 2, 0, f_term_setansicolors},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200902# endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200903 {"term_setkill", 2, 2, 0, f_term_setkill},
904 {"term_setrestore", 2, 2, 0, f_term_setrestore},
905 {"term_setsize", 3, 3, 0, f_term_setsize},
906 {"term_start", 1, 2, 0, f_term_start},
907 {"term_wait", 1, 2, 0, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200908#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200909 {"test_alloc_fail", 3, 3, 0, f_test_alloc_fail},
910 {"test_autochdir", 0, 0, 0, f_test_autochdir},
911 {"test_feedinput", 1, 1, 0, f_test_feedinput},
912 {"test_garbagecollect_now", 0, 0, 0, f_test_garbagecollect_now},
913 {"test_garbagecollect_soon", 0, 0, 0, f_test_garbagecollect_soon},
914 {"test_getvalue", 1, 1, 0, f_test_getvalue},
915 {"test_ignore_error", 1, 1, 0, f_test_ignore_error},
916 {"test_null_blob", 0, 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200917#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200918 {"test_null_channel", 0, 0, 0, f_test_null_channel},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200919#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200920 {"test_null_dict", 0, 0, 0, f_test_null_dict},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200921#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200922 {"test_null_job", 0, 0, 0, f_test_null_job},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200923#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200924 {"test_null_list", 0, 0, 0, f_test_null_list},
925 {"test_null_partial", 0, 0, 0, f_test_null_partial},
926 {"test_null_string", 0, 0, 0, f_test_null_string},
927 {"test_option_not_set", 1, 1, 0, f_test_option_not_set},
928 {"test_override", 2, 2, 0, f_test_override},
929 {"test_refcount", 1, 1, 0, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200930#ifdef FEAT_GUI
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200931 {"test_scrollbar", 3, 3, 0, f_test_scrollbar},
Bram Moolenaarab186732018-09-14 21:27:06 +0200932#endif
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200933#ifdef FEAT_MOUSE
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200934 {"test_setmouse", 2, 2, 0, f_test_setmouse},
Bram Moolenaar7e1a5af2019-05-07 16:28:13 +0200935#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200936 {"test_settime", 1, 1, 0, f_test_settime},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200937#ifdef FEAT_TIMERS
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200938 {"timer_info", 0, 1, 0, f_timer_info},
939 {"timer_pause", 2, 2, 0, f_timer_pause},
940 {"timer_start", 2, 3, 0, f_timer_start},
941 {"timer_stop", 1, 1, 0, f_timer_stop},
942 {"timer_stopall", 0, 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200943#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200944 {"tolower", 1, 1, 0, f_tolower},
945 {"toupper", 1, 1, 0, f_toupper},
946 {"tr", 3, 3, 0, f_tr},
947 {"trim", 1, 2, 0, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200948#ifdef FEAT_FLOAT
Bram Moolenaar93cf85f2019-08-17 21:36:28 +0200949 {"trunc", 1, 1, FEARG_1, f_trunc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200950#endif
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200951 {"type", 1, 1, FEARG_1, f_type},
952 {"undofile", 1, 1, 0, f_undofile},
953 {"undotree", 0, 0, 0, f_undotree},
954 {"uniq", 1, 3, FEARG_1, f_uniq},
955 {"values", 1, 1, FEARG_1, f_values},
956 {"virtcol", 1, 1, 0, f_virtcol},
957 {"visualmode", 0, 1, 0, f_visualmode},
958 {"wildmenumode", 0, 0, 0, f_wildmenumode},
959 {"win_execute", 2, 3, 0, f_win_execute},
960 {"win_findbuf", 1, 1, 0, f_win_findbuf},
961 {"win_getid", 0, 2, 0, f_win_getid},
962 {"win_gotoid", 1, 1, 0, f_win_gotoid},
963 {"win_id2tabwin", 1, 1, 0, f_win_id2tabwin},
964 {"win_id2win", 1, 1, 0, f_win_id2win},
965 {"win_screenpos", 1, 1, 0, f_win_screenpos},
Bram Moolenaare49fbff2019-08-21 22:50:07 +0200966 {"winbufnr", 1, 1, FEARG_1, f_winbufnr},
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +0200967 {"wincol", 0, 0, 0, f_wincol},
968 {"winheight", 1, 1, 0, f_winheight},
969 {"winlayout", 0, 1, 0, f_winlayout},
970 {"winline", 0, 0, 0, f_winline},
971 {"winnr", 0, 1, 0, f_winnr},
972 {"winrestcmd", 0, 0, 0, f_winrestcmd},
973 {"winrestview", 1, 1, 0, f_winrestview},
974 {"winsaveview", 0, 0, 0, f_winsaveview},
975 {"winwidth", 1, 1, 0, f_winwidth},
976 {"wordcount", 0, 0, 0, f_wordcount},
977 {"writefile", 2, 3, 0, f_writefile},
Bram Moolenaar073e4b92019-08-18 23:01:56 +0200978 {"xor", 2, 2, FEARG_1, f_xor},
Bram Moolenaarac92e252019-08-03 21:58:38 +0200979};
980
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200981/*
982 * Function given to ExpandGeneric() to obtain the list of internal
983 * or user defined function names.
984 */
985 char_u *
986get_function_name(expand_T *xp, int idx)
987{
988 static int intidx = -1;
989 char_u *name;
990
991 if (idx == 0)
992 intidx = -1;
993 if (intidx < 0)
994 {
995 name = get_user_func_name(xp, idx);
996 if (name != NULL)
997 return name;
998 }
Bram Moolenaarac92e252019-08-03 21:58:38 +0200999 if (++intidx < (int)(sizeof(global_functions) / sizeof(funcentry_T)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001000 {
Bram Moolenaarac92e252019-08-03 21:58:38 +02001001 STRCPY(IObuff, global_functions[intidx].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001002 STRCAT(IObuff, "(");
Bram Moolenaarac92e252019-08-03 21:58:38 +02001003 if (global_functions[intidx].f_max_argc == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001004 STRCAT(IObuff, ")");
1005 return IObuff;
1006 }
1007
1008 return NULL;
1009}
1010
1011/*
1012 * Function given to ExpandGeneric() to obtain the list of internal or
1013 * user defined variable or function names.
1014 */
1015 char_u *
1016get_expr_name(expand_T *xp, int idx)
1017{
1018 static int intidx = -1;
1019 char_u *name;
1020
1021 if (idx == 0)
1022 intidx = -1;
1023 if (intidx < 0)
1024 {
1025 name = get_function_name(xp, idx);
1026 if (name != NULL)
1027 return name;
1028 }
1029 return get_user_var_name(xp, ++intidx);
1030}
1031
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001032/*
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001033 * Find internal function "name" in table "global_functions".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001034 * Return index, or -1 if not found
1035 */
Bram Moolenaarac92e252019-08-03 21:58:38 +02001036 static int
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001037find_internal_func(char_u *name)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001038{
1039 int first = 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001040 int last;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001041 int cmp;
1042 int x;
1043
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001044 last = (int)(sizeof(global_functions) / sizeof(funcentry_T)) - 1;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001045
1046 // Find the function name in the table. Binary search.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001047 while (first <= last)
1048 {
1049 x = first + ((unsigned)(last - first) >> 1);
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001050 cmp = STRCMP(name, global_functions[x].f_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001051 if (cmp < 0)
1052 last = x - 1;
1053 else if (cmp > 0)
1054 first = x + 1;
1055 else
1056 return x;
1057 }
1058 return -1;
1059}
1060
1061 int
Bram Moolenaarac92e252019-08-03 21:58:38 +02001062has_internal_func(char_u *name)
1063{
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001064 return find_internal_func(name) >= 0;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001065}
1066
1067 int
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001068call_internal_func(
1069 char_u *name,
1070 int argcount,
1071 typval_T *argvars,
1072 typval_T *rettv)
1073{
1074 int i;
1075
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001076 i = find_internal_func(name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001077 if (i < 0)
1078 return ERROR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001079 if (argcount < global_functions[i].f_min_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001080 return ERROR_TOOFEW;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001081 if (argcount > global_functions[i].f_max_argc)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001082 return ERROR_TOOMANY;
1083 argvars[argcount].v_type = VAR_UNKNOWN;
Bram Moolenaarac92e252019-08-03 21:58:38 +02001084 global_functions[i].f_func(argvars, rettv);
1085 return ERROR_NONE;
1086}
1087
1088/*
1089 * Invoke a method for base->method().
1090 */
1091 int
1092call_internal_method(
1093 char_u *name,
1094 int argcount,
1095 typval_T *argvars,
1096 typval_T *rettv,
1097 typval_T *basetv)
1098{
1099 int i;
1100 int fi;
1101 typval_T argv[MAX_FUNC_ARGS + 1];
1102
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001103 fi = find_internal_func(name);
Bram Moolenaar91746392019-08-16 22:22:31 +02001104 if (fi < 0)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001105 return ERROR_UNKNOWN;
Bram Moolenaar91746392019-08-16 22:22:31 +02001106 if (global_functions[fi].f_argtype == 0)
1107 return ERROR_NOTMETHOD;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001108 if (argcount + 1 < global_functions[fi].f_min_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001109 return ERROR_TOOFEW;
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001110 if (argcount + 1 > global_functions[fi].f_max_argc)
Bram Moolenaarac92e252019-08-03 21:58:38 +02001111 return ERROR_TOOMANY;
1112
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001113 if (global_functions[fi].f_argtype == FEARG_LAST)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001114 {
1115 // base value goes last
1116 for (i = 0; i < argcount; ++i)
1117 argv[i] = argvars[i];
1118 argv[argcount] = *basetv;
1119 }
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001120 else if (global_functions[fi].f_argtype == FEARG_2)
Bram Moolenaar25e42232019-08-04 15:04:10 +02001121 {
1122 // base value goes second
1123 argv[0] = argvars[0];
1124 argv[1] = *basetv;
1125 for (i = 1; i < argcount; ++i)
1126 argv[i + 1] = argvars[i];
1127 }
Bram Moolenaar24278d22019-08-16 21:49:22 +02001128 else if (global_functions[fi].f_argtype == FEARG_3)
1129 {
1130 // base value goes third
1131 argv[0] = argvars[0];
1132 argv[1] = argvars[1];
1133 argv[2] = *basetv;
1134 for (i = 2; i < argcount; ++i)
1135 argv[i + 1] = argvars[i];
1136 }
Bram Moolenaar25e42232019-08-04 15:04:10 +02001137 else
1138 {
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001139 // FEARG_1: base value goes first
Bram Moolenaar25e42232019-08-04 15:04:10 +02001140 argv[0] = *basetv;
1141 for (i = 0; i < argcount; ++i)
1142 argv[i + 1] = argvars[i];
1143 }
Bram Moolenaarac92e252019-08-03 21:58:38 +02001144 argv[argcount + 1].v_type = VAR_UNKNOWN;
1145
Bram Moolenaar7a4ea1d2019-08-04 21:35:12 +02001146 global_functions[fi].f_func(argv, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001147 return ERROR_NONE;
1148}
1149
1150/*
1151 * Return TRUE for a non-zero Number and a non-empty String.
1152 */
1153 static int
1154non_zero_arg(typval_T *argvars)
1155{
1156 return ((argvars[0].v_type == VAR_NUMBER
1157 && argvars[0].vval.v_number != 0)
1158 || (argvars[0].v_type == VAR_SPECIAL
1159 && argvars[0].vval.v_number == VVAL_TRUE)
1160 || (argvars[0].v_type == VAR_STRING
1161 && argvars[0].vval.v_string != NULL
1162 && *argvars[0].vval.v_string != NUL));
1163}
1164
1165/*
1166 * Get the lnum from the first argument.
1167 * Also accepts ".", "$", etc., but that only works for the current buffer.
1168 * Returns -1 on error.
1169 */
Bram Moolenaarb60d8512019-06-29 07:59:04 +02001170 linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001171tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001172{
1173 typval_T rettv;
1174 linenr_T lnum;
1175
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001176 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001177 if (lnum == 0) /* no valid number, try using line() */
1178 {
1179 rettv.v_type = VAR_NUMBER;
1180 f_line(argvars, &rettv);
1181 lnum = (linenr_T)rettv.vval.v_number;
1182 clear_tv(&rettv);
1183 }
1184 return lnum;
1185}
1186
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001187/*
1188 * Get the lnum from the first argument.
1189 * Also accepts "$", then "buf" is used.
1190 * Returns 0 on error.
1191 */
1192 static linenr_T
1193tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1194{
1195 if (argvars[0].v_type == VAR_STRING
1196 && argvars[0].vval.v_string != NULL
1197 && argvars[0].vval.v_string[0] == '$'
1198 && buf != NULL)
1199 return buf->b_ml.ml_line_count;
1200 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1201}
1202
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001203#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001204/*
1205 * Get the float value of "argvars[0]" into "f".
1206 * Returns FAIL when the argument is not a Number or Float.
1207 */
1208 static int
1209get_float_arg(typval_T *argvars, float_T *f)
1210{
1211 if (argvars[0].v_type == VAR_FLOAT)
1212 {
1213 *f = argvars[0].vval.v_float;
1214 return OK;
1215 }
1216 if (argvars[0].v_type == VAR_NUMBER)
1217 {
1218 *f = (float_T)argvars[0].vval.v_number;
1219 return OK;
1220 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001221 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001222 return FAIL;
1223}
1224
1225/*
1226 * "abs(expr)" function
1227 */
1228 static void
1229f_abs(typval_T *argvars, typval_T *rettv)
1230{
1231 if (argvars[0].v_type == VAR_FLOAT)
1232 {
1233 rettv->v_type = VAR_FLOAT;
1234 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1235 }
1236 else
1237 {
1238 varnumber_T n;
1239 int error = FALSE;
1240
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001241 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001242 if (error)
1243 rettv->vval.v_number = -1;
1244 else if (n > 0)
1245 rettv->vval.v_number = n;
1246 else
1247 rettv->vval.v_number = -n;
1248 }
1249}
1250
1251/*
1252 * "acos()" function
1253 */
1254 static void
1255f_acos(typval_T *argvars, typval_T *rettv)
1256{
1257 float_T f = 0.0;
1258
1259 rettv->v_type = VAR_FLOAT;
1260 if (get_float_arg(argvars, &f) == OK)
1261 rettv->vval.v_float = acos(f);
1262 else
1263 rettv->vval.v_float = 0.0;
1264}
1265#endif
1266
1267/*
1268 * "add(list, item)" function
1269 */
1270 static void
1271f_add(typval_T *argvars, typval_T *rettv)
1272{
1273 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001274 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001275
1276 rettv->vval.v_number = 1; /* Default: Failed */
1277 if (argvars[0].v_type == VAR_LIST)
1278 {
1279 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001280 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001281 (char_u *)N_("add() argument"), TRUE)
1282 && list_append_tv(l, &argvars[1]) == OK)
1283 copy_tv(&argvars[0], rettv);
1284 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001285 else if (argvars[0].v_type == VAR_BLOB)
1286 {
1287 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001288 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001289 (char_u *)N_("add() argument"), TRUE))
1290 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001291 int error = FALSE;
1292 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1293
1294 if (!error)
1295 {
1296 ga_append(&b->bv_ga, (int)n);
1297 copy_tv(&argvars[0], rettv);
1298 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001299 }
1300 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001301 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001302 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001303}
1304
1305/*
1306 * "and(expr, expr)" function
1307 */
1308 static void
1309f_and(typval_T *argvars, typval_T *rettv)
1310{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001311 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1312 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001313}
1314
1315/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001316 * If there is a window for "curbuf", make it the current window.
1317 */
1318 static void
1319find_win_for_curbuf(void)
1320{
1321 wininfo_T *wip;
1322
1323 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1324 {
1325 if (wip->wi_win != NULL)
1326 {
1327 curwin = wip->wi_win;
1328 break;
1329 }
1330 }
1331}
1332
1333/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001334 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001335 */
1336 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001337set_buffer_lines(
1338 buf_T *buf,
1339 linenr_T lnum_arg,
1340 int append,
1341 typval_T *lines,
1342 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343{
Bram Moolenaarca851592018-06-06 21:04:07 +02001344 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1345 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001346 list_T *l = NULL;
1347 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001348 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001349 linenr_T append_lnum;
1350 buf_T *curbuf_save = NULL;
1351 win_T *curwin_save = NULL;
1352 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001353
Bram Moolenaarca851592018-06-06 21:04:07 +02001354 /* When using the current buffer ml_mfp will be set if needed. Useful when
1355 * setline() is used on startup. For other buffers the buffer must be
1356 * loaded. */
1357 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001358 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001359 rettv->vval.v_number = 1; /* FAIL */
1360 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001361 }
1362
Bram Moolenaarca851592018-06-06 21:04:07 +02001363 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001364 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001365 curbuf_save = curbuf;
1366 curwin_save = curwin;
1367 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001368 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001369 }
1370
1371 if (append)
1372 // appendbufline() uses the line number below which we insert
1373 append_lnum = lnum - 1;
1374 else
1375 // setbufline() uses the line number above which we insert, we only
1376 // append if it's below the last line
1377 append_lnum = curbuf->b_ml.ml_line_count;
1378
1379 if (lines->v_type == VAR_LIST)
1380 {
1381 l = lines->vval.v_list;
1382 li = l->lv_first;
1383 }
1384 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001385 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001386
1387 /* default result is zero == OK */
1388 for (;;)
1389 {
1390 if (l != NULL)
1391 {
1392 /* list argument, get next string */
1393 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001394 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001395 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001396 li = li->li_next;
1397 }
1398
Bram Moolenaarca851592018-06-06 21:04:07 +02001399 rettv->vval.v_number = 1; /* FAIL */
1400 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1401 break;
1402
1403 /* When coming here from Insert mode, sync undo, so that this can be
1404 * undone separately from what was previously inserted. */
1405 if (u_sync_once == 2)
1406 {
1407 u_sync_once = 1; /* notify that u_sync() was called */
1408 u_sync(TRUE);
1409 }
1410
1411 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1412 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001413 // Existing line, replace it.
1414 // Removes any existing text properties.
1415 if (u_savesub(lnum) == OK && ml_replace_len(
1416 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001417 {
1418 changed_bytes(lnum, 0);
1419 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1420 check_cursor_col();
1421 rettv->vval.v_number = 0; /* OK */
1422 }
1423 }
1424 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1425 {
1426 /* append the line */
1427 ++added;
1428 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1429 rettv->vval.v_number = 0; /* OK */
1430 }
1431
1432 if (l == NULL) /* only one string argument */
1433 break;
1434 ++lnum;
1435 }
1436
1437 if (added > 0)
1438 {
1439 win_T *wp;
1440 tabpage_T *tp;
1441
1442 appended_lines_mark(append_lnum, added);
1443 FOR_ALL_TAB_WINDOWS(tp, wp)
1444 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1445 wp->w_cursor.lnum += added;
1446 check_cursor_col();
Bram Moolenaar29846662019-07-27 17:39:15 +02001447 update_topline();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001448 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001449
1450 if (!is_curbuf)
1451 {
1452 curbuf = curbuf_save;
1453 curwin = curwin_save;
1454 }
1455}
1456
1457/*
1458 * "append(lnum, string/list)" function
1459 */
1460 static void
1461f_append(typval_T *argvars, typval_T *rettv)
1462{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001463 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001464
1465 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1466}
1467
1468/*
1469 * "appendbufline(buf, lnum, string/list)" function
1470 */
1471 static void
1472f_appendbufline(typval_T *argvars, typval_T *rettv)
1473{
1474 linenr_T lnum;
1475 buf_T *buf;
1476
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001477 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001478 if (buf == NULL)
1479 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001481 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001482 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001483 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1484 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001485}
1486
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001487#ifdef FEAT_FLOAT
1488/*
1489 * "asin()" function
1490 */
1491 static void
1492f_asin(typval_T *argvars, typval_T *rettv)
1493{
1494 float_T f = 0.0;
1495
1496 rettv->v_type = VAR_FLOAT;
1497 if (get_float_arg(argvars, &f) == OK)
1498 rettv->vval.v_float = asin(f);
1499 else
1500 rettv->vval.v_float = 0.0;
1501}
1502
1503/*
1504 * "atan()" function
1505 */
1506 static void
1507f_atan(typval_T *argvars, typval_T *rettv)
1508{
1509 float_T f = 0.0;
1510
1511 rettv->v_type = VAR_FLOAT;
1512 if (get_float_arg(argvars, &f) == OK)
1513 rettv->vval.v_float = atan(f);
1514 else
1515 rettv->vval.v_float = 0.0;
1516}
1517
1518/*
1519 * "atan2()" function
1520 */
1521 static void
1522f_atan2(typval_T *argvars, typval_T *rettv)
1523{
1524 float_T fx = 0.0, fy = 0.0;
1525
1526 rettv->v_type = VAR_FLOAT;
1527 if (get_float_arg(argvars, &fx) == OK
1528 && get_float_arg(&argvars[1], &fy) == OK)
1529 rettv->vval.v_float = atan2(fx, fy);
1530 else
1531 rettv->vval.v_float = 0.0;
1532}
1533#endif
1534
1535/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001536 * "balloon_show()" function
1537 */
1538#ifdef FEAT_BEVAL
1539 static void
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001540f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
1541{
1542 rettv->v_type = VAR_STRING;
1543 if (balloonEval != NULL)
1544 {
1545 if (balloonEval->msg == NULL)
1546 rettv->vval.v_string = NULL;
1547 else
1548 rettv->vval.v_string = vim_strsave(balloonEval->msg);
1549 }
1550}
1551
1552 static void
Bram Moolenaar59716a22017-03-01 20:32:44 +01001553f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1554{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001555 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001556 {
1557 if (argvars[0].v_type == VAR_LIST
1558# ifdef FEAT_GUI
1559 && !gui.in_use
1560# endif
1561 )
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001562 {
1563 list_T *l = argvars[0].vval.v_list;
1564
1565 // empty list removes the balloon
1566 post_balloon(balloonEval, NULL,
1567 l == NULL || l->lv_len == 0 ? NULL : l);
1568 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001569 else
Bram Moolenaarbe0a2592019-05-09 13:50:16 +02001570 {
1571 char_u *mesg = tv_get_string_chk(&argvars[0]);
1572
1573 if (mesg != NULL)
1574 // empty string removes the balloon
1575 post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
1576 }
Bram Moolenaar246fe032017-11-19 19:56:27 +01001577 }
1578}
1579
Bram Moolenaar669a8282017-11-19 20:13:05 +01001580# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001581 static void
1582f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1583{
1584 if (rettv_list_alloc(rettv) == OK)
1585 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001586 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001587
1588 if (msg != NULL)
1589 {
1590 pumitem_T *array;
1591 int size = split_message(msg, &array);
1592 int i;
1593
1594 /* Skip the first and last item, they are always empty. */
1595 for (i = 1; i < size - 1; ++i)
1596 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001597 while (size > 0)
1598 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001599 vim_free(array);
1600 }
1601 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001602}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001603# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001604#endif
1605
1606/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001607 * "browse(save, title, initdir, default)" function
1608 */
1609 static void
1610f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1611{
1612#ifdef FEAT_BROWSE
1613 int save;
1614 char_u *title;
1615 char_u *initdir;
1616 char_u *defname;
1617 char_u buf[NUMBUFLEN];
1618 char_u buf2[NUMBUFLEN];
1619 int error = FALSE;
1620
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001621 save = (int)tv_get_number_chk(&argvars[0], &error);
1622 title = tv_get_string_chk(&argvars[1]);
1623 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1624 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001625
1626 if (error || title == NULL || initdir == NULL || defname == NULL)
1627 rettv->vval.v_string = NULL;
1628 else
1629 rettv->vval.v_string =
1630 do_browse(save ? BROWSE_SAVE : 0,
1631 title, defname, NULL, initdir, NULL, curbuf);
1632#else
1633 rettv->vval.v_string = NULL;
1634#endif
1635 rettv->v_type = VAR_STRING;
1636}
1637
1638/*
1639 * "browsedir(title, initdir)" function
1640 */
1641 static void
1642f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1643{
1644#ifdef FEAT_BROWSE
1645 char_u *title;
1646 char_u *initdir;
1647 char_u buf[NUMBUFLEN];
1648
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001649 title = tv_get_string_chk(&argvars[0]);
1650 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651
1652 if (title == NULL || initdir == NULL)
1653 rettv->vval.v_string = NULL;
1654 else
1655 rettv->vval.v_string = do_browse(BROWSE_DIR,
1656 title, NULL, NULL, initdir, NULL, curbuf);
1657#else
1658 rettv->vval.v_string = NULL;
1659#endif
1660 rettv->v_type = VAR_STRING;
1661}
1662
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001663/*
1664 * Find a buffer by number or exact name.
1665 */
1666 static buf_T *
1667find_buffer(typval_T *avar)
1668{
1669 buf_T *buf = NULL;
1670
1671 if (avar->v_type == VAR_NUMBER)
1672 buf = buflist_findnr((int)avar->vval.v_number);
1673 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1674 {
1675 buf = buflist_findname_exp(avar->vval.v_string);
1676 if (buf == NULL)
1677 {
1678 /* No full path name match, try a match with a URL or a "nofile"
1679 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001680 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001681 if (buf->b_fname != NULL
1682 && (path_with_url(buf->b_fname)
1683#ifdef FEAT_QUICKFIX
Bram Moolenaar26910de2019-06-15 19:37:15 +02001684 || bt_nofilename(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001685#endif
1686 )
1687 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1688 break;
1689 }
1690 }
1691 return buf;
1692}
1693
1694/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001695 * "bufadd(expr)" function
1696 */
1697 static void
1698f_bufadd(typval_T *argvars, typval_T *rettv)
1699{
Bram Moolenaar892ae722019-06-30 20:33:01 +02001700 char_u *name = tv_get_string(&argvars[0]);
1701
1702 rettv->vval.v_number = buflist_add(*name == NUL ? NULL : name, 0);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001703}
1704
1705/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001706 * "bufexists(expr)" function
1707 */
1708 static void
1709f_bufexists(typval_T *argvars, typval_T *rettv)
1710{
1711 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1712}
1713
1714/*
1715 * "buflisted(expr)" function
1716 */
1717 static void
1718f_buflisted(typval_T *argvars, typval_T *rettv)
1719{
1720 buf_T *buf;
1721
1722 buf = find_buffer(&argvars[0]);
1723 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1724}
1725
1726/*
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001727 * "bufload(expr)" function
1728 */
1729 static void
1730f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
1731{
1732 buf_T *buf = get_buf_arg(&argvars[0]);
1733
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02001734 if (buf != NULL)
1735 buffer_ensure_loaded(buf);
Bram Moolenaar15e248e2019-06-30 20:21:37 +02001736}
1737
1738/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001739 * "bufloaded(expr)" function
1740 */
1741 static void
1742f_bufloaded(typval_T *argvars, typval_T *rettv)
1743{
1744 buf_T *buf;
1745
1746 buf = find_buffer(&argvars[0]);
1747 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1748}
1749
1750 buf_T *
1751buflist_find_by_name(char_u *name, int curtab_only)
1752{
1753 int save_magic;
1754 char_u *save_cpo;
1755 buf_T *buf;
1756
1757 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1758 save_magic = p_magic;
1759 p_magic = TRUE;
1760 save_cpo = p_cpo;
1761 p_cpo = (char_u *)"";
1762
1763 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1764 TRUE, FALSE, curtab_only));
1765
1766 p_magic = save_magic;
1767 p_cpo = save_cpo;
1768 return buf;
1769}
1770
1771/*
1772 * Get buffer by number or pattern.
1773 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001774 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001775tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001776{
1777 char_u *name = tv->vval.v_string;
1778 buf_T *buf;
1779
1780 if (tv->v_type == VAR_NUMBER)
1781 return buflist_findnr((int)tv->vval.v_number);
1782 if (tv->v_type != VAR_STRING)
1783 return NULL;
1784 if (name == NULL || *name == NUL)
1785 return curbuf;
1786 if (name[0] == '$' && name[1] == NUL)
1787 return lastbuf;
1788
1789 buf = buflist_find_by_name(name, curtab_only);
1790
1791 /* If not found, try expanding the name, like done for bufexists(). */
1792 if (buf == NULL)
1793 buf = find_buffer(tv);
1794
1795 return buf;
1796}
1797
1798/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001799 * Get the buffer from "arg" and give an error and return NULL if it is not
1800 * valid.
1801 */
Bram Moolenaara3347722019-05-11 21:14:24 +02001802 buf_T *
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001803get_buf_arg(typval_T *arg)
1804{
1805 buf_T *buf;
1806
1807 ++emsg_off;
1808 buf = tv_get_buf(arg, FALSE);
1809 --emsg_off;
1810 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001811 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001812 return buf;
1813}
1814
1815/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001816 * "bufname(expr)" function
1817 */
1818 static void
1819f_bufname(typval_T *argvars, typval_T *rettv)
1820{
1821 buf_T *buf;
1822
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001823 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001824 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001825 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001826 rettv->v_type = VAR_STRING;
1827 if (buf != NULL && buf->b_fname != NULL)
1828 rettv->vval.v_string = vim_strsave(buf->b_fname);
1829 else
1830 rettv->vval.v_string = NULL;
1831 --emsg_off;
1832}
1833
1834/*
1835 * "bufnr(expr)" function
1836 */
1837 static void
1838f_bufnr(typval_T *argvars, typval_T *rettv)
1839{
1840 buf_T *buf;
1841 int error = FALSE;
1842 char_u *name;
1843
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001844 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001845 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001846 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001847 --emsg_off;
1848
1849 /* If the buffer isn't found and the second argument is not zero create a
1850 * new buffer. */
1851 if (buf == NULL
1852 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001853 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001854 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001855 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001856 && !error)
1857 buf = buflist_new(name, NULL, (linenr_T)1, 0);
1858
1859 if (buf != NULL)
1860 rettv->vval.v_number = buf->b_fnum;
1861 else
1862 rettv->vval.v_number = -1;
1863}
1864
1865 static void
1866buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
1867{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001868 win_T *wp;
1869 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001870 buf_T *buf;
1871
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001872 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001873 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001874 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02001875 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001876 {
1877 ++winnr;
1878 if (wp->w_buffer == buf)
1879 break;
1880 }
1881 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001882 --emsg_off;
1883}
1884
1885/*
1886 * "bufwinid(nr)" function
1887 */
1888 static void
1889f_bufwinid(typval_T *argvars, typval_T *rettv)
1890{
1891 buf_win_common(argvars, rettv, FALSE);
1892}
1893
1894/*
1895 * "bufwinnr(nr)" function
1896 */
1897 static void
1898f_bufwinnr(typval_T *argvars, typval_T *rettv)
1899{
1900 buf_win_common(argvars, rettv, TRUE);
1901}
1902
1903/*
1904 * "byte2line(byte)" function
1905 */
1906 static void
1907f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
1908{
1909#ifndef FEAT_BYTEOFF
1910 rettv->vval.v_number = -1;
1911#else
1912 long boff = 0;
1913
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001914 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001915 if (boff < 0)
1916 rettv->vval.v_number = -1;
1917 else
1918 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
1919 (linenr_T)0, &boff);
1920#endif
1921}
1922
1923 static void
1924byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
1925{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001926 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001927 char_u *str;
1928 varnumber_T idx;
1929
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001930 str = tv_get_string_chk(&argvars[0]);
1931 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001932 rettv->vval.v_number = -1;
1933 if (str == NULL || idx < 0)
1934 return;
1935
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001936 t = str;
1937 for ( ; idx > 0; idx--)
1938 {
1939 if (*t == NUL) /* EOL reached */
1940 return;
1941 if (enc_utf8 && comp)
1942 t += utf_ptr2len(t);
1943 else
1944 t += (*mb_ptr2len)(t);
1945 }
1946 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001947}
1948
1949/*
1950 * "byteidx()" function
1951 */
1952 static void
1953f_byteidx(typval_T *argvars, typval_T *rettv)
1954{
1955 byteidx(argvars, rettv, FALSE);
1956}
1957
1958/*
1959 * "byteidxcomp()" function
1960 */
1961 static void
1962f_byteidxcomp(typval_T *argvars, typval_T *rettv)
1963{
1964 byteidx(argvars, rettv, TRUE);
1965}
1966
1967/*
1968 * "call(func, arglist [, dict])" function
1969 */
1970 static void
1971f_call(typval_T *argvars, typval_T *rettv)
1972{
1973 char_u *func;
1974 partial_T *partial = NULL;
1975 dict_T *selfdict = NULL;
1976
1977 if (argvars[1].v_type != VAR_LIST)
1978 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001979 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001980 return;
1981 }
1982 if (argvars[1].vval.v_list == NULL)
1983 return;
1984
1985 if (argvars[0].v_type == VAR_FUNC)
1986 func = argvars[0].vval.v_string;
1987 else if (argvars[0].v_type == VAR_PARTIAL)
1988 {
1989 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02001990 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991 }
1992 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001993 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001994 if (*func == NUL)
1995 return; /* type error or empty name */
1996
1997 if (argvars[2].v_type != VAR_UNKNOWN)
1998 {
1999 if (argvars[2].v_type != VAR_DICT)
2000 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002001 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002002 return;
2003 }
2004 selfdict = argvars[2].vval.v_dict;
2005 }
2006
2007 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2008}
2009
2010#ifdef FEAT_FLOAT
2011/*
2012 * "ceil({float})" function
2013 */
2014 static void
2015f_ceil(typval_T *argvars, typval_T *rettv)
2016{
2017 float_T f = 0.0;
2018
2019 rettv->v_type = VAR_FLOAT;
2020 if (get_float_arg(argvars, &f) == OK)
2021 rettv->vval.v_float = ceil(f);
2022 else
2023 rettv->vval.v_float = 0.0;
2024}
2025#endif
2026
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002027/*
2028 * "changenr()" function
2029 */
2030 static void
2031f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2032{
2033 rettv->vval.v_number = curbuf->b_u_seq_cur;
2034}
2035
2036/*
2037 * "char2nr(string)" function
2038 */
2039 static void
2040f_char2nr(typval_T *argvars, typval_T *rettv)
2041{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002042 if (has_mbyte)
2043 {
2044 int utf8 = 0;
2045
2046 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002047 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002048
2049 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002050 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002051 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002052 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002053 }
2054 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002055 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002056}
2057
2058/*
Bram Moolenaar1063f3d2019-05-07 22:06:52 +02002059 * "chdir(dir)" function
2060 */
2061 static void
2062f_chdir(typval_T *argvars, typval_T *rettv)
2063{
2064 char_u *cwd;
2065 cdscope_T scope = CDSCOPE_GLOBAL;
2066
2067 rettv->v_type = VAR_STRING;
2068 rettv->vval.v_string = NULL;
2069
2070 if (argvars[0].v_type != VAR_STRING)
2071 return;
2072
2073 // Return the current directory
2074 cwd = alloc(MAXPATHL);
2075 if (cwd != NULL)
2076 {
2077 if (mch_dirname(cwd, MAXPATHL) != FAIL)
2078 {
2079#ifdef BACKSLASH_IN_FILENAME
2080 slash_adjust(cwd);
2081#endif
2082 rettv->vval.v_string = vim_strsave(cwd);
2083 }
2084 vim_free(cwd);
2085 }
2086
2087 if (curwin->w_localdir != NULL)
2088 scope = CDSCOPE_WINDOW;
2089 else if (curtab->tp_localdir != NULL)
2090 scope = CDSCOPE_TABPAGE;
2091
2092 if (!changedir_func(argvars[0].vval.v_string, TRUE, scope))
2093 // Directory change failed
2094 VIM_CLEAR(rettv->vval.v_string);
2095}
2096
2097/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002098 * "cindent(lnum)" function
2099 */
2100 static void
2101f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2102{
2103#ifdef FEAT_CINDENT
2104 pos_T pos;
2105 linenr_T lnum;
2106
2107 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002108 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002109 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2110 {
2111 curwin->w_cursor.lnum = lnum;
2112 rettv->vval.v_number = get_c_indent();
2113 curwin->w_cursor = pos;
2114 }
2115 else
2116#endif
2117 rettv->vval.v_number = -1;
2118}
2119
Bram Moolenaar29b7d7a2019-07-22 23:03:57 +02002120 win_T *
Bram Moolenaaraff74912019-03-30 18:11:49 +01002121get_optional_window(typval_T *argvars, int idx)
2122{
2123 win_T *win = curwin;
2124
2125 if (argvars[idx].v_type != VAR_UNKNOWN)
2126 {
2127 win = find_win_by_nr_or_id(&argvars[idx]);
2128 if (win == NULL)
2129 {
2130 emsg(_(e_invalwindow));
2131 return NULL;
2132 }
2133 }
2134 return win;
2135}
2136
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002137/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002138 * "col(string)" function
2139 */
2140 static void
2141f_col(typval_T *argvars, typval_T *rettv)
2142{
2143 colnr_T col = 0;
2144 pos_T *fp;
2145 int fnum = curbuf->b_fnum;
2146
2147 fp = var2fpos(&argvars[0], FALSE, &fnum);
2148 if (fp != NULL && fnum == curbuf->b_fnum)
2149 {
2150 if (fp->col == MAXCOL)
2151 {
2152 /* '> can be MAXCOL, get the length of the line then */
2153 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2154 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2155 else
2156 col = MAXCOL;
2157 }
2158 else
2159 {
2160 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161 /* col(".") when the cursor is on the NUL at the end of the line
2162 * because of "coladd" can be seen as an extra column. */
2163 if (virtual_active() && fp == &curwin->w_cursor)
2164 {
2165 char_u *p = ml_get_cursor();
2166
2167 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2168 curwin->w_virtcol - curwin->w_cursor.coladd))
2169 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002170 int l;
2171
2172 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2173 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002174 }
2175 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002176 }
2177 }
2178 rettv->vval.v_number = col;
2179}
2180
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002181/*
2182 * "confirm(message, buttons[, default [, type]])" function
2183 */
2184 static void
2185f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2186{
2187#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2188 char_u *message;
2189 char_u *buttons = NULL;
2190 char_u buf[NUMBUFLEN];
2191 char_u buf2[NUMBUFLEN];
2192 int def = 1;
2193 int type = VIM_GENERIC;
2194 char_u *typestr;
2195 int error = FALSE;
2196
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002197 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002198 if (message == NULL)
2199 error = TRUE;
2200 if (argvars[1].v_type != VAR_UNKNOWN)
2201 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002202 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002203 if (buttons == NULL)
2204 error = TRUE;
2205 if (argvars[2].v_type != VAR_UNKNOWN)
2206 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002207 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002208 if (argvars[3].v_type != VAR_UNKNOWN)
2209 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002210 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002211 if (typestr == NULL)
2212 error = TRUE;
2213 else
2214 {
2215 switch (TOUPPER_ASC(*typestr))
2216 {
2217 case 'E': type = VIM_ERROR; break;
2218 case 'Q': type = VIM_QUESTION; break;
2219 case 'I': type = VIM_INFO; break;
2220 case 'W': type = VIM_WARNING; break;
2221 case 'G': type = VIM_GENERIC; break;
2222 }
2223 }
2224 }
2225 }
2226 }
2227
2228 if (buttons == NULL || *buttons == NUL)
2229 buttons = (char_u *)_("&Ok");
2230
2231 if (!error)
2232 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2233 def, NULL, FALSE);
2234#endif
2235}
2236
2237/*
2238 * "copy()" function
2239 */
2240 static void
2241f_copy(typval_T *argvars, typval_T *rettv)
2242{
2243 item_copy(&argvars[0], rettv, FALSE, 0);
2244}
2245
2246#ifdef FEAT_FLOAT
2247/*
2248 * "cos()" function
2249 */
2250 static void
2251f_cos(typval_T *argvars, typval_T *rettv)
2252{
2253 float_T f = 0.0;
2254
2255 rettv->v_type = VAR_FLOAT;
2256 if (get_float_arg(argvars, &f) == OK)
2257 rettv->vval.v_float = cos(f);
2258 else
2259 rettv->vval.v_float = 0.0;
2260}
2261
2262/*
2263 * "cosh()" function
2264 */
2265 static void
2266f_cosh(typval_T *argvars, typval_T *rettv)
2267{
2268 float_T f = 0.0;
2269
2270 rettv->v_type = VAR_FLOAT;
2271 if (get_float_arg(argvars, &f) == OK)
2272 rettv->vval.v_float = cosh(f);
2273 else
2274 rettv->vval.v_float = 0.0;
2275}
2276#endif
2277
2278/*
2279 * "count()" function
2280 */
2281 static void
2282f_count(typval_T *argvars, typval_T *rettv)
2283{
2284 long n = 0;
2285 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002286 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002287
Bram Moolenaar9966b212017-07-28 16:46:57 +02002288 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002289 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002290
2291 if (argvars[0].v_type == VAR_STRING)
2292 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002293 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002294 char_u *p = argvars[0].vval.v_string;
2295 char_u *next;
2296
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002297 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002298 {
2299 if (ic)
2300 {
2301 size_t len = STRLEN(expr);
2302
2303 while (*p != NUL)
2304 {
2305 if (MB_STRNICMP(p, expr, len) == 0)
2306 {
2307 ++n;
2308 p += len;
2309 }
2310 else
2311 MB_PTR_ADV(p);
2312 }
2313 }
2314 else
2315 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2316 != NULL)
2317 {
2318 ++n;
2319 p = next + STRLEN(expr);
2320 }
2321 }
2322
2323 }
2324 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002325 {
2326 listitem_T *li;
2327 list_T *l;
2328 long idx;
2329
2330 if ((l = argvars[0].vval.v_list) != NULL)
2331 {
2332 li = l->lv_first;
2333 if (argvars[2].v_type != VAR_UNKNOWN)
2334 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002335 if (argvars[3].v_type != VAR_UNKNOWN)
2336 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002337 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002338 if (!error)
2339 {
2340 li = list_find(l, idx);
2341 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002342 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002343 }
2344 }
2345 if (error)
2346 li = NULL;
2347 }
2348
2349 for ( ; li != NULL; li = li->li_next)
2350 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2351 ++n;
2352 }
2353 }
2354 else if (argvars[0].v_type == VAR_DICT)
2355 {
2356 int todo;
2357 dict_T *d;
2358 hashitem_T *hi;
2359
2360 if ((d = argvars[0].vval.v_dict) != NULL)
2361 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002362 if (argvars[2].v_type != VAR_UNKNOWN)
2363 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002364 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002365 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002366 }
2367
2368 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2369 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2370 {
2371 if (!HASHITEM_EMPTY(hi))
2372 {
2373 --todo;
2374 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2375 ++n;
2376 }
2377 }
2378 }
2379 }
2380 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002381 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002382 rettv->vval.v_number = n;
2383}
2384
2385/*
2386 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2387 *
2388 * Checks the existence of a cscope connection.
2389 */
2390 static void
2391f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2392{
2393#ifdef FEAT_CSCOPE
2394 int num = 0;
2395 char_u *dbpath = NULL;
2396 char_u *prepend = NULL;
2397 char_u buf[NUMBUFLEN];
2398
2399 if (argvars[0].v_type != VAR_UNKNOWN
2400 && argvars[1].v_type != VAR_UNKNOWN)
2401 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002402 num = (int)tv_get_number(&argvars[0]);
2403 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002404 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002405 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002406 }
2407
2408 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2409#endif
2410}
2411
2412/*
2413 * "cursor(lnum, col)" function, or
2414 * "cursor(list)"
2415 *
2416 * Moves the cursor to the specified line and column.
2417 * Returns 0 when the position could be set, -1 otherwise.
2418 */
2419 static void
2420f_cursor(typval_T *argvars, typval_T *rettv)
2421{
2422 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002423 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002424 int set_curswant = TRUE;
2425
2426 rettv->vval.v_number = -1;
2427 if (argvars[1].v_type == VAR_UNKNOWN)
2428 {
2429 pos_T pos;
2430 colnr_T curswant = -1;
2431
2432 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2433 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002434 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002435 return;
2436 }
2437 line = pos.lnum;
2438 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002439 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002440 if (curswant >= 0)
2441 {
2442 curwin->w_curswant = curswant - 1;
2443 set_curswant = FALSE;
2444 }
2445 }
2446 else
2447 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002448 line = tv_get_lnum(argvars);
2449 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002450 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002451 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002452 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002453 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002454 return; /* type error; errmsg already given */
2455 if (line > 0)
2456 curwin->w_cursor.lnum = line;
2457 if (col > 0)
2458 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002459 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002460
2461 /* Make sure the cursor is in a valid position. */
2462 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002463 /* Correct cursor for multi-byte character. */
2464 if (has_mbyte)
2465 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002466
2467 curwin->w_set_curswant = set_curswant;
2468 rettv->vval.v_number = 0;
2469}
2470
Bram Moolenaar4f974752019-02-17 17:44:42 +01002471#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002472/*
2473 * "debugbreak()" function
2474 */
2475 static void
2476f_debugbreak(typval_T *argvars, typval_T *rettv)
2477{
2478 int pid;
2479
2480 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002481 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002482 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002483 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002484 else
2485 {
2486 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2487
2488 if (hProcess != NULL)
2489 {
2490 DebugBreakProcess(hProcess);
2491 CloseHandle(hProcess);
2492 rettv->vval.v_number = OK;
2493 }
2494 }
2495}
2496#endif
2497
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002498/*
2499 * "deepcopy()" function
2500 */
2501 static void
2502f_deepcopy(typval_T *argvars, typval_T *rettv)
2503{
2504 int noref = 0;
2505 int copyID;
2506
2507 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002508 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002509 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002510 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002511 else
2512 {
2513 copyID = get_copyID();
2514 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2515 }
2516}
2517
2518/*
2519 * "delete()" function
2520 */
2521 static void
2522f_delete(typval_T *argvars, typval_T *rettv)
2523{
2524 char_u nbuf[NUMBUFLEN];
2525 char_u *name;
2526 char_u *flags;
2527
2528 rettv->vval.v_number = -1;
2529 if (check_restricted() || check_secure())
2530 return;
2531
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002532 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002533 if (name == NULL || *name == NUL)
2534 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002535 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002536 return;
2537 }
2538
2539 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002540 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002541 else
2542 flags = (char_u *)"";
2543
2544 if (*flags == NUL)
2545 /* delete a file */
2546 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
2547 else if (STRCMP(flags, "d") == 0)
2548 /* delete an empty directory */
2549 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
2550 else if (STRCMP(flags, "rf") == 0)
2551 /* delete a directory recursively */
2552 rettv->vval.v_number = delete_recursive(name);
2553 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002554 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002555}
2556
2557/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02002558 * "deletebufline()" function
2559 */
2560 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02002561f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02002562{
2563 buf_T *buf;
2564 linenr_T first, last;
2565 linenr_T lnum;
2566 long count;
2567 int is_curbuf;
2568 buf_T *curbuf_save = NULL;
2569 win_T *curwin_save = NULL;
2570 tabpage_T *tp;
2571 win_T *wp;
2572
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002573 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002574 if (buf == NULL)
2575 {
2576 rettv->vval.v_number = 1; /* FAIL */
2577 return;
2578 }
2579 is_curbuf = buf == curbuf;
2580
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002581 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002582 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002583 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02002584 else
2585 last = first;
2586
2587 if (buf->b_ml.ml_mfp == NULL || first < 1
2588 || first > buf->b_ml.ml_line_count || last < first)
2589 {
2590 rettv->vval.v_number = 1; /* FAIL */
2591 return;
2592 }
2593
2594 if (!is_curbuf)
2595 {
2596 curbuf_save = curbuf;
2597 curwin_save = curwin;
2598 curbuf = buf;
2599 find_win_for_curbuf();
2600 }
2601 if (last > curbuf->b_ml.ml_line_count)
2602 last = curbuf->b_ml.ml_line_count;
2603 count = last - first + 1;
2604
2605 // When coming here from Insert mode, sync undo, so that this can be
2606 // undone separately from what was previously inserted.
2607 if (u_sync_once == 2)
2608 {
2609 u_sync_once = 1; // notify that u_sync() was called
2610 u_sync(TRUE);
2611 }
2612
2613 if (u_save(first - 1, last + 1) == FAIL)
2614 {
2615 rettv->vval.v_number = 1; /* FAIL */
2616 return;
2617 }
2618
2619 for (lnum = first; lnum <= last; ++lnum)
2620 ml_delete(first, TRUE);
2621
2622 FOR_ALL_TAB_WINDOWS(tp, wp)
2623 if (wp->w_buffer == buf)
2624 {
2625 if (wp->w_cursor.lnum > last)
2626 wp->w_cursor.lnum -= count;
2627 else if (wp->w_cursor.lnum> first)
2628 wp->w_cursor.lnum = first;
2629 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
2630 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
2631 }
2632 check_cursor_col();
2633 deleted_lines_mark(first, count);
2634
2635 if (!is_curbuf)
2636 {
2637 curbuf = curbuf_save;
2638 curwin = curwin_save;
2639 }
2640}
2641
2642/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002643 * "did_filetype()" function
2644 */
2645 static void
2646f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2647{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002648 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002649}
2650
2651/*
2652 * "diff_filler()" function
2653 */
2654 static void
2655f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2656{
2657#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002658 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002659#endif
2660}
2661
2662/*
2663 * "diff_hlID()" function
2664 */
2665 static void
2666f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2667{
2668#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002669 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002670 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01002671 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002672 static int fnum = 0;
2673 static int change_start = 0;
2674 static int change_end = 0;
2675 static hlf_T hlID = (hlf_T)0;
2676 int filler_lines;
2677 int col;
2678
2679 if (lnum < 0) /* ignore type error in {lnum} arg */
2680 lnum = 0;
2681 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002682 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002683 || fnum != curbuf->b_fnum)
2684 {
2685 /* New line, buffer, change: need to get the values. */
2686 filler_lines = diff_check(curwin, lnum);
2687 if (filler_lines < 0)
2688 {
2689 if (filler_lines == -1)
2690 {
2691 change_start = MAXCOL;
2692 change_end = -1;
2693 if (diff_find_change(curwin, lnum, &change_start, &change_end))
2694 hlID = HLF_ADD; /* added line */
2695 else
2696 hlID = HLF_CHD; /* changed line */
2697 }
2698 else
2699 hlID = HLF_ADD; /* added line */
2700 }
2701 else
2702 hlID = (hlf_T)0;
2703 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01002704 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002705 fnum = curbuf->b_fnum;
2706 }
2707
2708 if (hlID == HLF_CHD || hlID == HLF_TXD)
2709 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002710 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002711 if (col >= change_start && col <= change_end)
2712 hlID = HLF_TXD; /* changed text */
2713 else
2714 hlID = HLF_CHD; /* changed line */
2715 }
2716 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
2717#endif
2718}
2719
2720/*
2721 * "empty({expr})" function
2722 */
2723 static void
2724f_empty(typval_T *argvars, typval_T *rettv)
2725{
2726 int n = FALSE;
2727
2728 switch (argvars[0].v_type)
2729 {
2730 case VAR_STRING:
2731 case VAR_FUNC:
2732 n = argvars[0].vval.v_string == NULL
2733 || *argvars[0].vval.v_string == NUL;
2734 break;
2735 case VAR_PARTIAL:
2736 n = FALSE;
2737 break;
2738 case VAR_NUMBER:
2739 n = argvars[0].vval.v_number == 0;
2740 break;
2741 case VAR_FLOAT:
2742#ifdef FEAT_FLOAT
2743 n = argvars[0].vval.v_float == 0.0;
2744 break;
2745#endif
2746 case VAR_LIST:
2747 n = argvars[0].vval.v_list == NULL
2748 || argvars[0].vval.v_list->lv_first == NULL;
2749 break;
2750 case VAR_DICT:
2751 n = argvars[0].vval.v_dict == NULL
2752 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
2753 break;
2754 case VAR_SPECIAL:
2755 n = argvars[0].vval.v_number != VVAL_TRUE;
2756 break;
2757
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002758 case VAR_BLOB:
2759 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002760 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
2761 break;
2762
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002763 case VAR_JOB:
2764#ifdef FEAT_JOB_CHANNEL
2765 n = argvars[0].vval.v_job == NULL
2766 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
2767 break;
2768#endif
2769 case VAR_CHANNEL:
2770#ifdef FEAT_JOB_CHANNEL
2771 n = argvars[0].vval.v_channel == NULL
2772 || !channel_is_open(argvars[0].vval.v_channel);
2773 break;
2774#endif
2775 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01002776 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002777 n = TRUE;
2778 break;
2779 }
2780
2781 rettv->vval.v_number = n;
2782}
2783
2784/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02002785 * "environ()" function
2786 */
2787 static void
2788f_environ(typval_T *argvars UNUSED, typval_T *rettv)
2789{
2790#if !defined(AMIGA)
2791 int i = 0;
2792 char_u *entry, *value;
2793# ifdef MSWIN
2794 extern wchar_t **_wenviron;
2795# else
2796 extern char **environ;
2797# endif
2798
2799 if (rettv_dict_alloc(rettv) != OK)
2800 return;
2801
2802# ifdef MSWIN
2803 if (*_wenviron == NULL)
2804 return;
2805# else
2806 if (*environ == NULL)
2807 return;
2808# endif
2809
2810 for (i = 0; ; ++i)
2811 {
2812# ifdef MSWIN
2813 short_u *p;
2814
2815 if ((p = (short_u *)_wenviron[i]) == NULL)
2816 return;
2817 entry = utf16_to_enc(p, NULL);
2818# else
2819 if ((entry = (char_u *)environ[i]) == NULL)
2820 return;
2821 entry = vim_strsave(entry);
2822# endif
2823 if (entry == NULL) // out of memory
2824 return;
2825 if ((value = vim_strchr(entry, '=')) == NULL)
2826 {
2827 vim_free(entry);
2828 continue;
2829 }
2830 *value++ = NUL;
2831 dict_add_string(rettv->vval.v_dict, (char *)entry, value);
2832 vim_free(entry);
2833 }
2834#endif
2835}
2836
2837/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002838 * "escape({string}, {chars})" function
2839 */
2840 static void
2841f_escape(typval_T *argvars, typval_T *rettv)
2842{
2843 char_u buf[NUMBUFLEN];
2844
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002845 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
2846 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002847 rettv->v_type = VAR_STRING;
2848}
2849
2850/*
2851 * "eval()" function
2852 */
2853 static void
2854f_eval(typval_T *argvars, typval_T *rettv)
2855{
2856 char_u *s, *p;
2857
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002858 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002859 if (s != NULL)
2860 s = skipwhite(s);
2861
2862 p = s;
2863 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
2864 {
2865 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002866 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002867 need_clr_eos = FALSE;
2868 rettv->v_type = VAR_NUMBER;
2869 rettv->vval.v_number = 0;
2870 }
2871 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002872 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002873}
2874
2875/*
2876 * "eventhandler()" function
2877 */
2878 static void
2879f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
2880{
2881 rettv->vval.v_number = vgetc_busy;
2882}
2883
2884/*
2885 * "executable()" function
2886 */
2887 static void
2888f_executable(typval_T *argvars, typval_T *rettv)
2889{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002890 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002891
2892 /* Check in $PATH and also check directly if there is a directory name. */
Bram Moolenaard08b8c42019-07-24 14:59:45 +02002893 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002894}
2895
2896static garray_T redir_execute_ga;
2897
2898/*
2899 * Append "value[value_len]" to the execute() output.
2900 */
2901 void
2902execute_redir_str(char_u *value, int value_len)
2903{
2904 int len;
2905
2906 if (value_len == -1)
2907 len = (int)STRLEN(value); /* Append the entire string */
2908 else
2909 len = value_len; /* Append only "value_len" characters */
2910 if (ga_grow(&redir_execute_ga, len) == OK)
2911 {
2912 mch_memmove((char *)redir_execute_ga.ga_data
2913 + redir_execute_ga.ga_len, value, len);
2914 redir_execute_ga.ga_len += len;
2915 }
2916}
2917
2918/*
2919 * Get next line from a list.
2920 * Called by do_cmdline() to get the next line.
2921 * Returns allocated string, or NULL for end of function.
2922 */
2923
2924 static char_u *
2925get_list_line(
2926 int c UNUSED,
2927 void *cookie,
Bram Moolenaare96a2492019-06-25 04:12:16 +02002928 int indent UNUSED,
2929 int do_concat UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002930{
2931 listitem_T **p = (listitem_T **)cookie;
2932 listitem_T *item = *p;
2933 char_u buf[NUMBUFLEN];
2934 char_u *s;
2935
2936 if (item == NULL)
2937 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002938 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002939 *p = item->li_next;
2940 return s == NULL ? NULL : vim_strsave(s);
2941}
2942
2943/*
2944 * "execute()" function
2945 */
2946 static void
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002947execute_common(typval_T *argvars, typval_T *rettv, int arg_off)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002948{
2949 char_u *cmd = NULL;
2950 list_T *list = NULL;
2951 int save_msg_silent = msg_silent;
2952 int save_emsg_silent = emsg_silent;
2953 int save_emsg_noredir = emsg_noredir;
2954 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01002955 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002956 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01002957 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002958 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002959
2960 rettv->vval.v_string = NULL;
2961 rettv->v_type = VAR_STRING;
2962
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002963 if (argvars[arg_off].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002964 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002965 list = argvars[arg_off].vval.v_list;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002966 if (list == NULL || list->lv_first == NULL)
2967 /* empty list, no commands, empty output */
2968 return;
2969 ++list->lv_refcount;
2970 }
2971 else
2972 {
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002973 cmd = tv_get_string_chk(&argvars[arg_off]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002974 if (cmd == NULL)
2975 return;
2976 }
2977
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002978 if (argvars[arg_off + 1].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002979 {
2980 char_u buf[NUMBUFLEN];
Bram Moolenaar868b7b62019-05-29 21:44:40 +02002981 char_u *s = tv_get_string_buf_chk(&argvars[arg_off + 1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002982
2983 if (s == NULL)
2984 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01002985 if (*s == NUL)
2986 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002987 if (STRNCMP(s, "silent", 6) == 0)
2988 ++msg_silent;
2989 if (STRCMP(s, "silent!") == 0)
2990 {
2991 emsg_silent = TRUE;
2992 emsg_noredir = TRUE;
2993 }
2994 }
2995 else
2996 ++msg_silent;
2997
2998 if (redir_execute)
2999 save_ga = redir_execute_ga;
3000 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3001 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003002 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003003 if (!echo_output)
3004 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003005
3006 if (cmd != NULL)
3007 do_cmdline_cmd(cmd);
3008 else
3009 {
3010 listitem_T *item = list->lv_first;
3011
3012 do_cmdline(NULL, get_list_line, (void *)&item,
3013 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3014 --list->lv_refcount;
3015 }
3016
Bram Moolenaard297f352017-01-29 20:31:21 +01003017 /* Need to append a NUL to the result. */
3018 if (ga_grow(&redir_execute_ga, 1) == OK)
3019 {
3020 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3021 rettv->vval.v_string = redir_execute_ga.ga_data;
3022 }
3023 else
3024 {
3025 ga_clear(&redir_execute_ga);
3026 rettv->vval.v_string = NULL;
3027 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003028 msg_silent = save_msg_silent;
3029 emsg_silent = save_emsg_silent;
3030 emsg_noredir = save_emsg_noredir;
3031
3032 redir_execute = save_redir_execute;
3033 if (redir_execute)
3034 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003035 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003036
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003037 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003038 if (echo_output)
3039 // When not working silently: put it in column zero. A following
3040 // "echon" will overwrite the message, unavoidably.
3041 msg_col = 0;
3042 else
3043 // When working silently: Put it back where it was, since nothing
3044 // should have been written.
3045 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003046}
3047
3048/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02003049 * "execute()" function
3050 */
3051 static void
3052f_execute(typval_T *argvars, typval_T *rettv)
3053{
3054 execute_common(argvars, rettv, 0);
3055}
3056
3057/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003058 * "exepath()" function
3059 */
3060 static void
3061f_exepath(typval_T *argvars, typval_T *rettv)
3062{
3063 char_u *p = NULL;
3064
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003065 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003066 rettv->v_type = VAR_STRING;
3067 rettv->vval.v_string = p;
3068}
3069
3070/*
3071 * "exists()" function
3072 */
3073 static void
3074f_exists(typval_T *argvars, typval_T *rettv)
3075{
3076 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003077 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003078
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003079 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003080 if (*p == '$') /* environment variable */
3081 {
3082 /* first try "normal" environment variables (fast) */
3083 if (mch_getenv(p + 1) != NULL)
3084 n = TRUE;
3085 else
3086 {
3087 /* try expanding things like $VIM and ${HOME} */
3088 p = expand_env_save(p);
3089 if (p != NULL && *p != '$')
3090 n = TRUE;
3091 vim_free(p);
3092 }
3093 }
3094 else if (*p == '&' || *p == '+') /* option */
3095 {
3096 n = (get_option_tv(&p, NULL, TRUE) == OK);
3097 if (*skipwhite(p) != NUL)
3098 n = FALSE; /* trailing garbage */
3099 }
3100 else if (*p == '*') /* internal or user defined function */
3101 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003102 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003103 }
3104 else if (*p == ':')
3105 {
3106 n = cmd_exists(p + 1);
3107 }
3108 else if (*p == '#')
3109 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003110 if (p[1] == '#')
3111 n = autocmd_supported(p + 2);
3112 else
3113 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003114 }
3115 else /* internal variable */
3116 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003117 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003118 }
3119
3120 rettv->vval.v_number = n;
3121}
3122
3123#ifdef FEAT_FLOAT
3124/*
3125 * "exp()" function
3126 */
3127 static void
3128f_exp(typval_T *argvars, typval_T *rettv)
3129{
3130 float_T f = 0.0;
3131
3132 rettv->v_type = VAR_FLOAT;
3133 if (get_float_arg(argvars, &f) == OK)
3134 rettv->vval.v_float = exp(f);
3135 else
3136 rettv->vval.v_float = 0.0;
3137}
3138#endif
3139
3140/*
3141 * "expand()" function
3142 */
3143 static void
3144f_expand(typval_T *argvars, typval_T *rettv)
3145{
3146 char_u *s;
3147 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003148 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003149 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3150 expand_T xpc;
3151 int error = FALSE;
3152 char_u *result;
3153
3154 rettv->v_type = VAR_STRING;
3155 if (argvars[1].v_type != VAR_UNKNOWN
3156 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003157 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003158 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003159 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003160
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003161 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003162 if (*s == '%' || *s == '#' || *s == '<')
3163 {
3164 ++emsg_off;
3165 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3166 --emsg_off;
3167 if (rettv->v_type == VAR_LIST)
3168 {
3169 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3170 list_append_string(rettv->vval.v_list, result, -1);
3171 else
3172 vim_free(result);
3173 }
3174 else
3175 rettv->vval.v_string = result;
3176 }
3177 else
3178 {
3179 /* When the optional second argument is non-zero, don't remove matches
3180 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3181 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003182 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003183 options |= WILD_KEEP_ALL;
3184 if (!error)
3185 {
3186 ExpandInit(&xpc);
3187 xpc.xp_context = EXPAND_FILES;
3188 if (p_wic)
3189 options += WILD_ICASE;
3190 if (rettv->v_type == VAR_STRING)
3191 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3192 options, WILD_ALL);
3193 else if (rettv_list_alloc(rettv) != FAIL)
3194 {
3195 int i;
3196
3197 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3198 for (i = 0; i < xpc.xp_numfiles; i++)
3199 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3200 ExpandCleanup(&xpc);
3201 }
3202 }
3203 else
3204 rettv->vval.v_string = NULL;
3205 }
3206}
3207
3208/*
Bram Moolenaar80dad482019-06-09 17:22:31 +02003209 * "expandcmd()" function
3210 * Expand all the special characters in a command string.
3211 */
3212 static void
3213f_expandcmd(typval_T *argvars, typval_T *rettv)
3214{
3215 exarg_T eap;
3216 char_u *cmdstr;
3217 char *errormsg = NULL;
3218
3219 rettv->v_type = VAR_STRING;
3220 cmdstr = vim_strsave(tv_get_string(&argvars[0]));
3221
3222 memset(&eap, 0, sizeof(eap));
3223 eap.cmd = cmdstr;
3224 eap.arg = cmdstr;
Bram Moolenaar8071cb22019-07-12 17:58:01 +02003225 eap.argt |= EX_NOSPC;
Bram Moolenaar80dad482019-06-09 17:22:31 +02003226 eap.usefilter = FALSE;
3227 eap.nextcmd = NULL;
3228 eap.cmdidx = CMD_USER;
3229
3230 expand_filename(&eap, &cmdstr, &errormsg);
3231 if (errormsg != NULL && *errormsg != NUL)
3232 emsg(errormsg);
3233
3234 rettv->vval.v_string = cmdstr;
3235}
3236
3237/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003238 * "extend(list, list [, idx])" function
3239 * "extend(dict, dict [, action])" function
3240 */
3241 static void
3242f_extend(typval_T *argvars, typval_T *rettv)
3243{
3244 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3245
3246 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3247 {
3248 list_T *l1, *l2;
3249 listitem_T *item;
3250 long before;
3251 int error = FALSE;
3252
3253 l1 = argvars[0].vval.v_list;
3254 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003255 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003256 && l2 != NULL)
3257 {
3258 if (argvars[2].v_type != VAR_UNKNOWN)
3259 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003260 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003261 if (error)
3262 return; /* type error; errmsg already given */
3263
3264 if (before == l1->lv_len)
3265 item = NULL;
3266 else
3267 {
3268 item = list_find(l1, before);
3269 if (item == NULL)
3270 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003271 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003272 return;
3273 }
3274 }
3275 }
3276 else
3277 item = NULL;
3278 list_extend(l1, l2, item);
3279
3280 copy_tv(&argvars[0], rettv);
3281 }
3282 }
3283 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3284 {
3285 dict_T *d1, *d2;
3286 char_u *action;
3287 int i;
3288
3289 d1 = argvars[0].vval.v_dict;
3290 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003291 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003292 && d2 != NULL)
3293 {
3294 /* Check the third argument. */
3295 if (argvars[2].v_type != VAR_UNKNOWN)
3296 {
3297 static char *(av[]) = {"keep", "force", "error"};
3298
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003299 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003300 if (action == NULL)
3301 return; /* type error; errmsg already given */
3302 for (i = 0; i < 3; ++i)
3303 if (STRCMP(action, av[i]) == 0)
3304 break;
3305 if (i == 3)
3306 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003307 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003308 return;
3309 }
3310 }
3311 else
3312 action = (char_u *)"force";
3313
3314 dict_extend(d1, d2, action);
3315
3316 copy_tv(&argvars[0], rettv);
3317 }
3318 }
3319 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003320 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003321}
3322
3323/*
3324 * "feedkeys()" function
3325 */
3326 static void
3327f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3328{
3329 int remap = TRUE;
3330 int insert = FALSE;
3331 char_u *keys, *flags;
3332 char_u nbuf[NUMBUFLEN];
3333 int typed = FALSE;
3334 int execute = FALSE;
3335 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003336 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003337 char_u *keys_esc;
3338
3339 /* This is not allowed in the sandbox. If the commands would still be
3340 * executed in the sandbox it would be OK, but it probably happens later,
3341 * when "sandbox" is no longer set. */
3342 if (check_secure())
3343 return;
3344
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003345 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003346
3347 if (argvars[1].v_type != VAR_UNKNOWN)
3348 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003349 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003350 for ( ; *flags != NUL; ++flags)
3351 {
3352 switch (*flags)
3353 {
3354 case 'n': remap = FALSE; break;
3355 case 'm': remap = TRUE; break;
3356 case 't': typed = TRUE; break;
3357 case 'i': insert = TRUE; break;
3358 case 'x': execute = TRUE; break;
3359 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003360 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003361 }
3362 }
3363 }
3364
3365 if (*keys != NUL || execute)
3366 {
3367 /* Need to escape K_SPECIAL and CSI before putting the string in the
3368 * typeahead buffer. */
3369 keys_esc = vim_strsave_escape_csi(keys);
3370 if (keys_esc != NULL)
3371 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003372 if (lowlevel)
3373 {
3374#ifdef USE_INPUT_BUF
3375 add_to_input_buf(keys, (int)STRLEN(keys));
3376#else
3377 emsg(_("E980: lowlevel input not supported"));
3378#endif
3379 }
3380 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003381 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003382 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003383 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003384 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003385#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003386 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003387#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003388 )
3389 typebuf_was_filled = TRUE;
3390 }
3391 vim_free(keys_esc);
3392
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003393 if (execute)
3394 {
3395 int save_msg_scroll = msg_scroll;
3396
3397 /* Avoid a 1 second delay when the keys start Insert mode. */
3398 msg_scroll = FALSE;
3399
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003400 if (!dangerous)
3401 ++ex_normal_busy;
Bram Moolenaar905dd902019-04-07 14:21:47 +02003402 exec_normal(TRUE, lowlevel, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003403 if (!dangerous)
3404 --ex_normal_busy;
3405
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003406 msg_scroll |= save_msg_scroll;
3407 }
3408 }
3409 }
3410}
3411
3412/*
3413 * "filereadable()" function
3414 */
3415 static void
3416f_filereadable(typval_T *argvars, typval_T *rettv)
3417{
3418 int fd;
3419 char_u *p;
3420 int n;
3421
3422#ifndef O_NONBLOCK
3423# define O_NONBLOCK 0
3424#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003425 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003426 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3427 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3428 {
3429 n = TRUE;
3430 close(fd);
3431 }
3432 else
3433 n = FALSE;
3434
3435 rettv->vval.v_number = n;
3436}
3437
3438/*
3439 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3440 * rights to write into.
3441 */
3442 static void
3443f_filewritable(typval_T *argvars, typval_T *rettv)
3444{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003445 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003446}
3447
3448 static void
3449findfilendir(
3450 typval_T *argvars UNUSED,
3451 typval_T *rettv,
3452 int find_what UNUSED)
3453{
3454#ifdef FEAT_SEARCHPATH
3455 char_u *fname;
3456 char_u *fresult = NULL;
3457 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3458 char_u *p;
3459 char_u pathbuf[NUMBUFLEN];
3460 int count = 1;
3461 int first = TRUE;
3462 int error = FALSE;
3463#endif
3464
3465 rettv->vval.v_string = NULL;
3466 rettv->v_type = VAR_STRING;
3467
3468#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003469 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003470
3471 if (argvars[1].v_type != VAR_UNKNOWN)
3472 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003473 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003474 if (p == NULL)
3475 error = TRUE;
3476 else
3477 {
3478 if (*p != NUL)
3479 path = p;
3480
3481 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003482 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003483 }
3484 }
3485
3486 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3487 error = TRUE;
3488
3489 if (*fname != NUL && !error)
3490 {
3491 do
3492 {
3493 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3494 vim_free(fresult);
3495 fresult = find_file_in_path_option(first ? fname : NULL,
3496 first ? (int)STRLEN(fname) : 0,
3497 0, first, path,
3498 find_what,
3499 curbuf->b_ffname,
3500 find_what == FINDFILE_DIR
3501 ? (char_u *)"" : curbuf->b_p_sua);
3502 first = FALSE;
3503
3504 if (fresult != NULL && rettv->v_type == VAR_LIST)
3505 list_append_string(rettv->vval.v_list, fresult, -1);
3506
3507 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3508 }
3509
3510 if (rettv->v_type == VAR_STRING)
3511 rettv->vval.v_string = fresult;
3512#endif
3513}
3514
3515/*
3516 * "filter()" function
3517 */
3518 static void
3519f_filter(typval_T *argvars, typval_T *rettv)
3520{
3521 filter_map(argvars, rettv, FALSE);
3522}
3523
3524/*
3525 * "finddir({fname}[, {path}[, {count}]])" function
3526 */
3527 static void
3528f_finddir(typval_T *argvars, typval_T *rettv)
3529{
3530 findfilendir(argvars, rettv, FINDFILE_DIR);
3531}
3532
3533/*
3534 * "findfile({fname}[, {path}[, {count}]])" function
3535 */
3536 static void
3537f_findfile(typval_T *argvars, typval_T *rettv)
3538{
3539 findfilendir(argvars, rettv, FINDFILE_FILE);
3540}
3541
3542#ifdef FEAT_FLOAT
3543/*
3544 * "float2nr({float})" function
3545 */
3546 static void
3547f_float2nr(typval_T *argvars, typval_T *rettv)
3548{
3549 float_T f = 0.0;
3550
3551 if (get_float_arg(argvars, &f) == OK)
3552 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003553 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003554 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003555 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003556 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003557 else
3558 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003559 }
3560}
3561
3562/*
3563 * "floor({float})" function
3564 */
3565 static void
3566f_floor(typval_T *argvars, typval_T *rettv)
3567{
3568 float_T f = 0.0;
3569
3570 rettv->v_type = VAR_FLOAT;
3571 if (get_float_arg(argvars, &f) == OK)
3572 rettv->vval.v_float = floor(f);
3573 else
3574 rettv->vval.v_float = 0.0;
3575}
3576
3577/*
3578 * "fmod()" function
3579 */
3580 static void
3581f_fmod(typval_T *argvars, typval_T *rettv)
3582{
3583 float_T fx = 0.0, fy = 0.0;
3584
3585 rettv->v_type = VAR_FLOAT;
3586 if (get_float_arg(argvars, &fx) == OK
3587 && get_float_arg(&argvars[1], &fy) == OK)
3588 rettv->vval.v_float = fmod(fx, fy);
3589 else
3590 rettv->vval.v_float = 0.0;
3591}
3592#endif
3593
3594/*
3595 * "fnameescape({string})" function
3596 */
3597 static void
3598f_fnameescape(typval_T *argvars, typval_T *rettv)
3599{
3600 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003601 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003602 rettv->v_type = VAR_STRING;
3603}
3604
3605/*
3606 * "fnamemodify({fname}, {mods})" function
3607 */
3608 static void
3609f_fnamemodify(typval_T *argvars, typval_T *rettv)
3610{
3611 char_u *fname;
3612 char_u *mods;
3613 int usedlen = 0;
3614 int len;
3615 char_u *fbuf = NULL;
3616 char_u buf[NUMBUFLEN];
3617
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003618 fname = tv_get_string_chk(&argvars[0]);
3619 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003620 if (fname == NULL || mods == NULL)
3621 fname = NULL;
3622 else
3623 {
3624 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02003625 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003626 }
3627
3628 rettv->v_type = VAR_STRING;
3629 if (fname == NULL)
3630 rettv->vval.v_string = NULL;
3631 else
3632 rettv->vval.v_string = vim_strnsave(fname, len);
3633 vim_free(fbuf);
3634}
3635
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003636/*
3637 * "foldclosed()" function
3638 */
3639 static void
3640foldclosed_both(
3641 typval_T *argvars UNUSED,
3642 typval_T *rettv,
3643 int end UNUSED)
3644{
3645#ifdef FEAT_FOLDING
3646 linenr_T lnum;
3647 linenr_T first, last;
3648
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003649 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003650 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3651 {
3652 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
3653 {
3654 if (end)
3655 rettv->vval.v_number = (varnumber_T)last;
3656 else
3657 rettv->vval.v_number = (varnumber_T)first;
3658 return;
3659 }
3660 }
3661#endif
3662 rettv->vval.v_number = -1;
3663}
3664
3665/*
3666 * "foldclosed()" function
3667 */
3668 static void
3669f_foldclosed(typval_T *argvars, typval_T *rettv)
3670{
3671 foldclosed_both(argvars, rettv, FALSE);
3672}
3673
3674/*
3675 * "foldclosedend()" function
3676 */
3677 static void
3678f_foldclosedend(typval_T *argvars, typval_T *rettv)
3679{
3680 foldclosed_both(argvars, rettv, TRUE);
3681}
3682
3683/*
3684 * "foldlevel()" function
3685 */
3686 static void
3687f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3688{
3689#ifdef FEAT_FOLDING
3690 linenr_T lnum;
3691
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003692 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003693 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3694 rettv->vval.v_number = foldLevel(lnum);
3695#endif
3696}
3697
3698/*
3699 * "foldtext()" function
3700 */
3701 static void
3702f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
3703{
3704#ifdef FEAT_FOLDING
3705 linenr_T foldstart;
3706 linenr_T foldend;
3707 char_u *dashes;
3708 linenr_T lnum;
3709 char_u *s;
3710 char_u *r;
3711 int len;
3712 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003713 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003714#endif
3715
3716 rettv->v_type = VAR_STRING;
3717 rettv->vval.v_string = NULL;
3718#ifdef FEAT_FOLDING
3719 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
3720 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
3721 dashes = get_vim_var_str(VV_FOLDDASHES);
3722 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
3723 && dashes != NULL)
3724 {
3725 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02003726 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003727 if (!linewhite(lnum))
3728 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003729
3730 /* Find interesting text in this line. */
3731 s = skipwhite(ml_get(lnum));
3732 /* skip C comment-start */
3733 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
3734 {
3735 s = skipwhite(s + 2);
3736 if (*skipwhite(s) == NUL
3737 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
3738 {
3739 s = skipwhite(ml_get(lnum + 1));
3740 if (*s == '*')
3741 s = skipwhite(s + 1);
3742 }
3743 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02003744 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01003745 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar964b3742019-05-24 18:54:09 +02003746 r = alloc(STRLEN(txt)
3747 + STRLEN(dashes) // for %s
3748 + 20 // for %3ld
3749 + STRLEN(s)); // concatenated
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003750 if (r != NULL)
3751 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02003752 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003753 len = (int)STRLEN(r);
3754 STRCAT(r, s);
3755 /* remove 'foldmarker' and 'commentstring' */
3756 foldtext_cleanup(r + len);
3757 rettv->vval.v_string = r;
3758 }
3759 }
3760#endif
3761}
3762
3763/*
3764 * "foldtextresult(lnum)" function
3765 */
3766 static void
3767f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
3768{
3769#ifdef FEAT_FOLDING
3770 linenr_T lnum;
3771 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02003772 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003773 foldinfo_T foldinfo;
3774 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003775 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003776#endif
3777
3778 rettv->v_type = VAR_STRING;
3779 rettv->vval.v_string = NULL;
3780#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003781 if (entered)
3782 return; /* reject recursive use */
3783 entered = TRUE;
3784
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003785 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003786 /* treat illegal types and illegal string values for {lnum} the same */
3787 if (lnum < 0)
3788 lnum = 0;
3789 fold_count = foldedCount(curwin, lnum, &foldinfo);
3790 if (fold_count > 0)
3791 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01003792 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
3793 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003794 if (text == buf)
3795 text = vim_strsave(text);
3796 rettv->vval.v_string = text;
3797 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02003798
3799 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003800#endif
3801}
3802
3803/*
3804 * "foreground()" function
3805 */
3806 static void
3807f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3808{
3809#ifdef FEAT_GUI
3810 if (gui.in_use)
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003811 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003812 gui_mch_set_foreground();
Bram Moolenaarafde13b2019-04-28 19:46:49 +02003813 return;
3814 }
3815#endif
3816#if defined(MSWIN) && (!defined(FEAT_GUI) || defined(VIMDLL))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003817 win32_set_foreground();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003818#endif
3819}
3820
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003821 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003822common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003823{
3824 char_u *s;
3825 char_u *name;
3826 int use_string = FALSE;
3827 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003828 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003829
3830 if (argvars[0].v_type == VAR_FUNC)
3831 {
3832 /* function(MyFunc, [arg], dict) */
3833 s = argvars[0].vval.v_string;
3834 }
3835 else if (argvars[0].v_type == VAR_PARTIAL
3836 && argvars[0].vval.v_partial != NULL)
3837 {
3838 /* function(dict.MyFunc, [arg]) */
3839 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003840 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003841 }
3842 else
3843 {
3844 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003845 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003846 use_string = TRUE;
3847 }
3848
Bram Moolenaar843b8842016-08-21 14:36:15 +02003849 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003850 {
3851 name = s;
3852 trans_name = trans_function_name(&name, FALSE,
3853 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
3854 if (*name != NUL)
3855 s = NULL;
3856 }
3857
Bram Moolenaar843b8842016-08-21 14:36:15 +02003858 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
3859 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003860 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003861 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003862 else if (trans_name != NULL && (is_funcref
3863 ? find_func(trans_name) == NULL
3864 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003865 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003866 else
3867 {
3868 int dict_idx = 0;
3869 int arg_idx = 0;
3870 list_T *list = NULL;
3871
3872 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
3873 {
3874 char sid_buf[25];
3875 int off = *s == 's' ? 2 : 5;
3876
3877 /* Expand s: and <SID> into <SNR>nr_, so that the function can
3878 * also be called from another script. Using trans_function_name()
3879 * would also work, but some plugins depend on the name being
3880 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02003881 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar51e14382019-05-25 20:21:28 +02003882 name = alloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003883 if (name != NULL)
3884 {
3885 STRCPY(name, sid_buf);
3886 STRCAT(name, s + off);
3887 }
3888 }
3889 else
3890 name = vim_strsave(s);
3891
3892 if (argvars[1].v_type != VAR_UNKNOWN)
3893 {
3894 if (argvars[2].v_type != VAR_UNKNOWN)
3895 {
3896 /* function(name, [args], dict) */
3897 arg_idx = 1;
3898 dict_idx = 2;
3899 }
3900 else if (argvars[1].v_type == VAR_DICT)
3901 /* function(name, dict) */
3902 dict_idx = 1;
3903 else
3904 /* function(name, [args]) */
3905 arg_idx = 1;
3906 if (dict_idx > 0)
3907 {
3908 if (argvars[dict_idx].v_type != VAR_DICT)
3909 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003910 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003911 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003912 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003913 }
3914 if (argvars[dict_idx].vval.v_dict == NULL)
3915 dict_idx = 0;
3916 }
3917 if (arg_idx > 0)
3918 {
3919 if (argvars[arg_idx].v_type != VAR_LIST)
3920 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003921 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003922 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003923 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003924 }
3925 list = argvars[arg_idx].vval.v_list;
3926 if (list == NULL || list->lv_len == 0)
3927 arg_idx = 0;
3928 }
3929 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003930 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003931 {
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003932 partial_T *pt = ALLOC_CLEAR_ONE(partial_T);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003933
3934 /* result is a VAR_PARTIAL */
3935 if (pt == NULL)
3936 vim_free(name);
3937 else
3938 {
3939 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
3940 {
3941 listitem_T *li;
3942 int i = 0;
3943 int arg_len = 0;
3944 int lv_len = 0;
3945
3946 if (arg_pt != NULL)
3947 arg_len = arg_pt->pt_argc;
3948 if (list != NULL)
3949 lv_len = list->lv_len;
3950 pt->pt_argc = arg_len + lv_len;
Bram Moolenaarc799fe22019-05-28 23:08:19 +02003951 pt->pt_argv = ALLOC_MULT(typval_T, pt->pt_argc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003952 if (pt->pt_argv == NULL)
3953 {
3954 vim_free(pt);
3955 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003956 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003957 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003958 for (i = 0; i < arg_len; i++)
3959 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
3960 if (lv_len > 0)
3961 for (li = list->lv_first; li != NULL;
3962 li = li->li_next)
3963 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003964 }
3965
3966 /* For "function(dict.func, [], dict)" and "func" is a partial
3967 * use "dict". That is backwards compatible. */
3968 if (dict_idx > 0)
3969 {
3970 /* The dict is bound explicitly, pt_auto is FALSE. */
3971 pt->pt_dict = argvars[dict_idx].vval.v_dict;
3972 ++pt->pt_dict->dv_refcount;
3973 }
3974 else if (arg_pt != NULL)
3975 {
3976 /* If the dict was bound automatically the result is also
3977 * bound automatically. */
3978 pt->pt_dict = arg_pt->pt_dict;
3979 pt->pt_auto = arg_pt->pt_auto;
3980 if (pt->pt_dict != NULL)
3981 ++pt->pt_dict->dv_refcount;
3982 }
3983
3984 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02003985 if (arg_pt != NULL && arg_pt->pt_func != NULL)
3986 {
3987 pt->pt_func = arg_pt->pt_func;
3988 func_ptr_ref(pt->pt_func);
3989 vim_free(name);
3990 }
3991 else if (is_funcref)
3992 {
3993 pt->pt_func = find_func(trans_name);
3994 func_ptr_ref(pt->pt_func);
3995 vim_free(name);
3996 }
3997 else
3998 {
3999 pt->pt_name = name;
4000 func_ref(name);
4001 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004002 }
4003 rettv->v_type = VAR_PARTIAL;
4004 rettv->vval.v_partial = pt;
4005 }
4006 else
4007 {
4008 /* result is a VAR_FUNC */
4009 rettv->v_type = VAR_FUNC;
4010 rettv->vval.v_string = name;
4011 func_ref(name);
4012 }
4013 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004014theend:
4015 vim_free(trans_name);
4016}
4017
4018/*
4019 * "funcref()" function
4020 */
4021 static void
4022f_funcref(typval_T *argvars, typval_T *rettv)
4023{
4024 common_function(argvars, rettv, TRUE);
4025}
4026
4027/*
4028 * "function()" function
4029 */
4030 static void
4031f_function(typval_T *argvars, typval_T *rettv)
4032{
4033 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004034}
4035
4036/*
4037 * "garbagecollect()" function
4038 */
4039 static void
4040f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4041{
4042 /* This is postponed until we are back at the toplevel, because we may be
4043 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4044 want_garbage_collect = TRUE;
4045
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004046 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004047 garbage_collect_at_exit = TRUE;
4048}
4049
4050/*
4051 * "get()" function
4052 */
4053 static void
4054f_get(typval_T *argvars, typval_T *rettv)
4055{
4056 listitem_T *li;
4057 list_T *l;
4058 dictitem_T *di;
4059 dict_T *d;
4060 typval_T *tv = NULL;
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004061 int what_is_dict = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004062
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004063 if (argvars[0].v_type == VAR_BLOB)
4064 {
4065 int error = FALSE;
4066 int idx = tv_get_number_chk(&argvars[1], &error);
4067
4068 if (!error)
4069 {
4070 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004071 if (idx < 0)
4072 idx = blob_len(argvars[0].vval.v_blob) + idx;
4073 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4074 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004075 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004076 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004077 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004078 tv = rettv;
4079 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004080 }
4081 }
4082 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004083 {
4084 if ((l = argvars[0].vval.v_list) != NULL)
4085 {
4086 int error = FALSE;
4087
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004088 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004089 if (!error && li != NULL)
4090 tv = &li->li_tv;
4091 }
4092 }
4093 else if (argvars[0].v_type == VAR_DICT)
4094 {
4095 if ((d = argvars[0].vval.v_dict) != NULL)
4096 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004097 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004098 if (di != NULL)
4099 tv = &di->di_tv;
4100 }
4101 }
4102 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4103 {
4104 partial_T *pt;
4105 partial_T fref_pt;
4106
4107 if (argvars[0].v_type == VAR_PARTIAL)
4108 pt = argvars[0].vval.v_partial;
4109 else
4110 {
4111 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4112 fref_pt.pt_name = argvars[0].vval.v_string;
4113 pt = &fref_pt;
4114 }
4115
4116 if (pt != NULL)
4117 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004118 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004119 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004120
4121 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4122 {
4123 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004124 n = partial_name(pt);
4125 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004126 rettv->vval.v_string = NULL;
4127 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004128 {
4129 rettv->vval.v_string = vim_strsave(n);
4130 if (rettv->v_type == VAR_FUNC)
4131 func_ref(rettv->vval.v_string);
4132 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004133 }
4134 else if (STRCMP(what, "dict") == 0)
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004135 {
4136 what_is_dict = TRUE;
4137 if (pt->pt_dict != NULL)
4138 rettv_dict_set(rettv, pt->pt_dict);
4139 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004140 else if (STRCMP(what, "args") == 0)
4141 {
4142 rettv->v_type = VAR_LIST;
4143 if (rettv_list_alloc(rettv) == OK)
4144 {
4145 int i;
4146
4147 for (i = 0; i < pt->pt_argc; ++i)
4148 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4149 }
4150 }
4151 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004152 semsg(_(e_invarg2), what);
Bram Moolenaarf91aac52019-07-28 13:21:01 +02004153
4154 // When {what} == "dict" and pt->pt_dict == NULL, evaluate the
4155 // third argument
4156 if (!what_is_dict)
4157 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004158 }
4159 }
4160 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004161 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004162
4163 if (tv == NULL)
4164 {
4165 if (argvars[2].v_type != VAR_UNKNOWN)
4166 copy_tv(&argvars[2], rettv);
4167 }
4168 else
4169 copy_tv(tv, rettv);
4170}
4171
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004172/*
4173 * Returns buffer options, variables and other attributes in a dictionary.
4174 */
4175 static dict_T *
4176get_buffer_info(buf_T *buf)
4177{
4178 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004179 tabpage_T *tp;
4180 win_T *wp;
4181 list_T *windows;
4182
4183 dict = dict_alloc();
4184 if (dict == NULL)
4185 return NULL;
4186
Bram Moolenaare0be1672018-07-08 16:50:37 +02004187 dict_add_number(dict, "bufnr", buf->b_fnum);
4188 dict_add_string(dict, "name", buf->b_ffname);
4189 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4190 : buflist_findlnum(buf));
4191 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4192 dict_add_number(dict, "listed", buf->b_p_bl);
4193 dict_add_number(dict, "changed", bufIsChanged(buf));
4194 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4195 dict_add_number(dict, "hidden",
4196 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004197
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004198 // Get a reference to buffer variables
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004199 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004200
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004201 // List of windows displaying this buffer
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004202 windows = list_alloc();
4203 if (windows != NULL)
4204 {
4205 FOR_ALL_TAB_WINDOWS(tp, wp)
4206 if (wp->w_buffer == buf)
4207 list_append_number(windows, (varnumber_T)wp->w_id);
4208 dict_add_list(dict, "windows", windows);
4209 }
4210
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02004211#ifdef FEAT_TEXT_PROP
4212 // List of popup windows displaying this buffer
4213 windows = list_alloc();
4214 if (windows != NULL)
4215 {
4216 for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
4217 if (wp->w_buffer == buf)
4218 list_append_number(windows, (varnumber_T)wp->w_id);
4219 FOR_ALL_TABPAGES(tp)
4220 for (wp = tp->tp_first_popupwin; wp != NULL; wp = wp->w_next)
4221 if (wp->w_buffer == buf)
4222 list_append_number(windows, (varnumber_T)wp->w_id);
4223
4224 dict_add_list(dict, "popups", windows);
4225 }
4226#endif
4227
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004228#ifdef FEAT_SIGNS
4229 if (buf->b_signlist != NULL)
4230 {
4231 /* List of signs placed in this buffer */
4232 list_T *signs = list_alloc();
4233 if (signs != NULL)
4234 {
4235 get_buffer_signs(buf, signs);
4236 dict_add_list(dict, "signs", signs);
4237 }
4238 }
4239#endif
4240
4241 return dict;
4242}
4243
4244/*
4245 * "getbufinfo()" function
4246 */
4247 static void
4248f_getbufinfo(typval_T *argvars, typval_T *rettv)
4249{
4250 buf_T *buf = NULL;
4251 buf_T *argbuf = NULL;
4252 dict_T *d;
4253 int filtered = FALSE;
4254 int sel_buflisted = FALSE;
4255 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004256 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004257
4258 if (rettv_list_alloc(rettv) != OK)
4259 return;
4260
4261 /* List of all the buffers or selected buffers */
4262 if (argvars[0].v_type == VAR_DICT)
4263 {
4264 dict_T *sel_d = argvars[0].vval.v_dict;
4265
4266 if (sel_d != NULL)
4267 {
4268 dictitem_T *di;
4269
4270 filtered = TRUE;
4271
4272 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004273 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004274 sel_buflisted = TRUE;
4275
4276 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004277 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004278 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004279
4280 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004281 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004282 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004283 }
4284 }
4285 else if (argvars[0].v_type != VAR_UNKNOWN)
4286 {
4287 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004288 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004289 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004290 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004291 --emsg_off;
4292 if (argbuf == NULL)
4293 return;
4294 }
4295
4296 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004297 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004298 {
4299 if (argbuf != NULL && argbuf != buf)
4300 continue;
4301 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004302 || (sel_buflisted && !buf->b_p_bl)
4303 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004304 continue;
4305
4306 d = get_buffer_info(buf);
4307 if (d != NULL)
4308 list_append_dict(rettv->vval.v_list, d);
4309 if (argbuf != NULL)
4310 return;
4311 }
4312}
4313
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004314/*
4315 * Get line or list of lines from buffer "buf" into "rettv".
4316 * Return a range (from start to end) of lines in rettv from the specified
4317 * buffer.
4318 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4319 */
4320 static void
4321get_buffer_lines(
4322 buf_T *buf,
4323 linenr_T start,
4324 linenr_T end,
4325 int retlist,
4326 typval_T *rettv)
4327{
4328 char_u *p;
4329
4330 rettv->v_type = VAR_STRING;
4331 rettv->vval.v_string = NULL;
4332 if (retlist && rettv_list_alloc(rettv) == FAIL)
4333 return;
4334
4335 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4336 return;
4337
4338 if (!retlist)
4339 {
4340 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4341 p = ml_get_buf(buf, start, FALSE);
4342 else
4343 p = (char_u *)"";
4344 rettv->vval.v_string = vim_strsave(p);
4345 }
4346 else
4347 {
4348 if (end < start)
4349 return;
4350
4351 if (start < 1)
4352 start = 1;
4353 if (end > buf->b_ml.ml_line_count)
4354 end = buf->b_ml.ml_line_count;
4355 while (start <= end)
4356 if (list_append_string(rettv->vval.v_list,
4357 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4358 break;
4359 }
4360}
4361
4362/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004363 * "getbufline()" function
4364 */
4365 static void
4366f_getbufline(typval_T *argvars, typval_T *rettv)
4367{
4368 linenr_T lnum;
4369 linenr_T end;
4370 buf_T *buf;
4371
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004372 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004373 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004374 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004375 --emsg_off;
4376
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004377 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004378 if (argvars[2].v_type == VAR_UNKNOWN)
4379 end = lnum;
4380 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004381 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004382
4383 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4384}
4385
4386/*
4387 * "getbufvar()" function
4388 */
4389 static void
4390f_getbufvar(typval_T *argvars, typval_T *rettv)
4391{
4392 buf_T *buf;
4393 buf_T *save_curbuf;
4394 char_u *varname;
4395 dictitem_T *v;
4396 int done = FALSE;
4397
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004398 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4399 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004400 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004401 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004402
4403 rettv->v_type = VAR_STRING;
4404 rettv->vval.v_string = NULL;
4405
4406 if (buf != NULL && varname != NULL)
4407 {
4408 /* set curbuf to be our buf, temporarily */
4409 save_curbuf = curbuf;
4410 curbuf = buf;
4411
Bram Moolenaar30567352016-08-27 21:25:44 +02004412 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004413 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004414 if (varname[1] == NUL)
4415 {
4416 /* get all buffer-local options in a dict */
4417 dict_T *opts = get_winbuf_options(TRUE);
4418
4419 if (opts != NULL)
4420 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004421 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004422 done = TRUE;
4423 }
4424 }
4425 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4426 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004427 done = TRUE;
4428 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004429 else
4430 {
4431 /* Look up the variable. */
4432 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4433 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4434 'b', varname, FALSE);
4435 if (v != NULL)
4436 {
4437 copy_tv(&v->di_tv, rettv);
4438 done = TRUE;
4439 }
4440 }
4441
4442 /* restore previous notion of curbuf */
4443 curbuf = save_curbuf;
4444 }
4445
4446 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4447 /* use the default value */
4448 copy_tv(&argvars[2], rettv);
4449
4450 --emsg_off;
4451}
4452
4453/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004454 * "getchangelist()" function
4455 */
4456 static void
4457f_getchangelist(typval_T *argvars, typval_T *rettv)
4458{
4459#ifdef FEAT_JUMPLIST
4460 buf_T *buf;
4461 int i;
4462 list_T *l;
4463 dict_T *d;
4464#endif
4465
4466 if (rettv_list_alloc(rettv) != OK)
4467 return;
4468
4469#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004470 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004471 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004472 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004473 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004474 if (buf == NULL)
4475 return;
4476
4477 l = list_alloc();
4478 if (l == NULL)
4479 return;
4480
4481 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4482 return;
4483 /*
4484 * The current window change list index tracks only the position in the
4485 * current buffer change list. For other buffers, use the change list
4486 * length as the current index.
4487 */
4488 list_append_number(rettv->vval.v_list,
4489 (varnumber_T)((buf == curwin->w_buffer)
4490 ? curwin->w_changelistidx : buf->b_changelistlen));
4491
4492 for (i = 0; i < buf->b_changelistlen; ++i)
4493 {
4494 if (buf->b_changelist[i].lnum == 0)
4495 continue;
4496 if ((d = dict_alloc()) == NULL)
4497 return;
4498 if (list_append_dict(l, d) == FAIL)
4499 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004500 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4501 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004502 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004503 }
4504#endif
4505}
4506/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004507 * "getchar()" function
4508 */
4509 static void
4510f_getchar(typval_T *argvars, typval_T *rettv)
4511{
4512 varnumber_T n;
4513 int error = FALSE;
4514
Bram Moolenaar84d93902018-09-11 20:10:20 +02004515#ifdef MESSAGE_QUEUE
4516 // vpeekc() used to check for messages, but that caused problems, invoking
4517 // a callback where it was not expected. Some plugins use getchar(1) in a
4518 // loop to await a message, therefore make sure we check for messages here.
4519 parse_queued_messages();
4520#endif
4521
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004522 /* Position the cursor. Needed after a message that ends in a space. */
4523 windgoto(msg_row, msg_col);
4524
4525 ++no_mapping;
4526 ++allow_keys;
4527 for (;;)
4528 {
4529 if (argvars[0].v_type == VAR_UNKNOWN)
4530 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004531 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004532 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004533 /* getchar(1): only check if char avail */
4534 n = vpeekc_any();
4535 else if (error || vpeekc_any() == NUL)
4536 /* illegal argument or getchar(0) and no char avail: return zero */
4537 n = 0;
4538 else
4539 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004540 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004541
4542 if (n == K_IGNORE)
4543 continue;
4544 break;
4545 }
4546 --no_mapping;
4547 --allow_keys;
4548
4549 set_vim_var_nr(VV_MOUSE_WIN, 0);
4550 set_vim_var_nr(VV_MOUSE_WINID, 0);
4551 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4552 set_vim_var_nr(VV_MOUSE_COL, 0);
4553
4554 rettv->vval.v_number = n;
4555 if (IS_SPECIAL(n) || mod_mask != 0)
4556 {
4557 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4558 int i = 0;
4559
4560 /* Turn a special key into three bytes, plus modifier. */
4561 if (mod_mask != 0)
4562 {
4563 temp[i++] = K_SPECIAL;
4564 temp[i++] = KS_MODIFIER;
4565 temp[i++] = mod_mask;
4566 }
4567 if (IS_SPECIAL(n))
4568 {
4569 temp[i++] = K_SPECIAL;
4570 temp[i++] = K_SECOND(n);
4571 temp[i++] = K_THIRD(n);
4572 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004573 else if (has_mbyte)
4574 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004575 else
4576 temp[i++] = n;
4577 temp[i++] = NUL;
4578 rettv->v_type = VAR_STRING;
4579 rettv->vval.v_string = vim_strsave(temp);
4580
4581#ifdef FEAT_MOUSE
4582 if (is_mouse_key(n))
4583 {
4584 int row = mouse_row;
4585 int col = mouse_col;
4586 win_T *win;
4587 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004588 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004589 int winnr = 1;
4590
4591 if (row >= 0 && col >= 0)
4592 {
4593 /* Find the window at the mouse coordinates and compute the
4594 * text position. */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004595 win = mouse_find_win(&row, &col, FIND_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004596 if (win == NULL)
4597 return;
Bram Moolenaar9d5ffce2019-07-26 21:01:29 +02004598 (void)mouse_comp_pos(win, &row, &col, &lnum, NULL);
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004599# ifdef FEAT_TEXT_PROP
Bram Moolenaar5b8cfed2019-06-30 22:16:10 +02004600 if (WIN_IS_POPUP(win))
Bram Moolenaar451d4b52019-06-12 20:22:27 +02004601 winnr = 0;
4602 else
4603# endif
4604 for (wp = firstwin; wp != win && wp != NULL;
4605 wp = wp->w_next)
4606 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004607 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4608 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4609 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4610 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4611 }
4612 }
4613#endif
4614 }
4615}
4616
4617/*
4618 * "getcharmod()" function
4619 */
4620 static void
4621f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4622{
4623 rettv->vval.v_number = mod_mask;
4624}
4625
4626/*
4627 * "getcharsearch()" function
4628 */
4629 static void
4630f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4631{
4632 if (rettv_dict_alloc(rettv) != FAIL)
4633 {
4634 dict_T *dict = rettv->vval.v_dict;
4635
Bram Moolenaare0be1672018-07-08 16:50:37 +02004636 dict_add_string(dict, "char", last_csearch());
4637 dict_add_number(dict, "forward", last_csearch_forward());
4638 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004639 }
4640}
4641
4642/*
4643 * "getcmdline()" function
4644 */
4645 static void
4646f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4647{
4648 rettv->v_type = VAR_STRING;
4649 rettv->vval.v_string = get_cmdline_str();
4650}
4651
4652/*
4653 * "getcmdpos()" function
4654 */
4655 static void
4656f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
4657{
4658 rettv->vval.v_number = get_cmdline_pos() + 1;
4659}
4660
4661/*
4662 * "getcmdtype()" function
4663 */
4664 static void
4665f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
4666{
4667 rettv->v_type = VAR_STRING;
4668 rettv->vval.v_string = alloc(2);
4669 if (rettv->vval.v_string != NULL)
4670 {
4671 rettv->vval.v_string[0] = get_cmdline_type();
4672 rettv->vval.v_string[1] = NUL;
4673 }
4674}
4675
4676/*
4677 * "getcmdwintype()" function
4678 */
4679 static void
4680f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
4681{
4682 rettv->v_type = VAR_STRING;
4683 rettv->vval.v_string = NULL;
4684#ifdef FEAT_CMDWIN
4685 rettv->vval.v_string = alloc(2);
4686 if (rettv->vval.v_string != NULL)
4687 {
4688 rettv->vval.v_string[0] = cmdwin_type;
4689 rettv->vval.v_string[1] = NUL;
4690 }
4691#endif
4692}
4693
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004694/*
4695 * "getcwd()" function
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004696 *
4697 * Return the current working directory of a window in a tab page.
4698 * First optional argument 'winnr' is the window number or -1 and the second
4699 * optional argument 'tabnr' is the tab page number.
4700 *
4701 * If no arguments are supplied, then return the directory of the current
4702 * window.
4703 * If only 'winnr' is specified and is not -1 or 0 then return the directory of
4704 * the specified window.
4705 * If 'winnr' is 0 then return the directory of the current window.
4706 * If both 'winnr and 'tabnr' are specified and 'winnr' is -1 then return the
4707 * directory of the specified tab page. Otherwise return the directory of the
4708 * specified window in the specified tab page.
4709 * If the window or the tab page doesn't exist then return NULL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004710 */
4711 static void
4712f_getcwd(typval_T *argvars, typval_T *rettv)
4713{
4714 win_T *wp = NULL;
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004715 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004716 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01004717 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004718
4719 rettv->v_type = VAR_STRING;
4720 rettv->vval.v_string = NULL;
4721
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004722 if (argvars[0].v_type == VAR_NUMBER
4723 && argvars[0].vval.v_number == -1
4724 && argvars[1].v_type == VAR_UNKNOWN)
Bram Moolenaar54591292018-02-09 20:53:59 +01004725 global = TRUE;
4726 else
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004727 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
Bram Moolenaar54591292018-02-09 20:53:59 +01004728
4729 if (wp != NULL && wp->w_localdir != NULL)
4730 rettv->vval.v_string = vim_strsave(wp->w_localdir);
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004731 else if (tp != NULL && tp->tp_localdir != NULL)
4732 rettv->vval.v_string = vim_strsave(tp->tp_localdir);
4733 else if (wp != NULL || tp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 {
Bram Moolenaar54591292018-02-09 20:53:59 +01004735 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004736 rettv->vval.v_string = vim_strsave(globaldir);
4737 else
4738 {
4739 cwd = alloc(MAXPATHL);
4740 if (cwd != NULL)
4741 {
4742 if (mch_dirname(cwd, MAXPATHL) != FAIL)
4743 rettv->vval.v_string = vim_strsave(cwd);
4744 vim_free(cwd);
4745 }
4746 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004747 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02004748#ifdef BACKSLASH_IN_FILENAME
4749 if (rettv->vval.v_string != NULL)
4750 slash_adjust(rettv->vval.v_string);
4751#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004752}
4753
4754/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02004755 * "getenv()" function
4756 */
4757 static void
4758f_getenv(typval_T *argvars, typval_T *rettv)
4759{
4760 int mustfree = FALSE;
4761 char_u *p = vim_getenv(tv_get_string(&argvars[0]), &mustfree);
4762
4763 if (p == NULL)
4764 {
4765 rettv->v_type = VAR_SPECIAL;
4766 rettv->vval.v_number = VVAL_NULL;
4767 return;
4768 }
4769 if (!mustfree)
4770 p = vim_strsave(p);
4771 rettv->vval.v_string = p;
4772 rettv->v_type = VAR_STRING;
4773}
4774
4775/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004776 * "getfontname()" function
4777 */
4778 static void
4779f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
4780{
4781 rettv->v_type = VAR_STRING;
4782 rettv->vval.v_string = NULL;
4783#ifdef FEAT_GUI
4784 if (gui.in_use)
4785 {
4786 GuiFont font;
4787 char_u *name = NULL;
4788
4789 if (argvars[0].v_type == VAR_UNKNOWN)
4790 {
4791 /* Get the "Normal" font. Either the name saved by
4792 * hl_set_font_name() or from the font ID. */
4793 font = gui.norm_font;
4794 name = hl_get_font_name();
4795 }
4796 else
4797 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004798 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004799 if (STRCMP(name, "*") == 0) /* don't use font dialog */
4800 return;
4801 font = gui_mch_get_font(name, FALSE);
4802 if (font == NOFONT)
4803 return; /* Invalid font name, return empty string. */
4804 }
4805 rettv->vval.v_string = gui_mch_get_fontname(font, name);
4806 if (argvars[0].v_type != VAR_UNKNOWN)
4807 gui_mch_free_font(font);
4808 }
4809#endif
4810}
4811
4812/*
4813 * "getfperm({fname})" function
4814 */
4815 static void
4816f_getfperm(typval_T *argvars, typval_T *rettv)
4817{
4818 char_u *fname;
4819 stat_T st;
4820 char_u *perm = NULL;
4821 char_u flags[] = "rwx";
4822 int i;
4823
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004824 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004825
4826 rettv->v_type = VAR_STRING;
4827 if (mch_stat((char *)fname, &st) >= 0)
4828 {
4829 perm = vim_strsave((char_u *)"---------");
4830 if (perm != NULL)
4831 {
4832 for (i = 0; i < 9; i++)
4833 {
4834 if (st.st_mode & (1 << (8 - i)))
4835 perm[i] = flags[i % 3];
4836 }
4837 }
4838 }
4839 rettv->vval.v_string = perm;
4840}
4841
4842/*
4843 * "getfsize({fname})" function
4844 */
4845 static void
4846f_getfsize(typval_T *argvars, typval_T *rettv)
4847{
4848 char_u *fname;
4849 stat_T st;
4850
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004851 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004852
4853 rettv->v_type = VAR_NUMBER;
4854
4855 if (mch_stat((char *)fname, &st) >= 0)
4856 {
4857 if (mch_isdir(fname))
4858 rettv->vval.v_number = 0;
4859 else
4860 {
4861 rettv->vval.v_number = (varnumber_T)st.st_size;
4862
4863 /* non-perfect check for overflow */
4864 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
4865 rettv->vval.v_number = -2;
4866 }
4867 }
4868 else
4869 rettv->vval.v_number = -1;
4870}
4871
4872/*
4873 * "getftime({fname})" function
4874 */
4875 static void
4876f_getftime(typval_T *argvars, typval_T *rettv)
4877{
4878 char_u *fname;
4879 stat_T st;
4880
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004881 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004882
4883 if (mch_stat((char *)fname, &st) >= 0)
4884 rettv->vval.v_number = (varnumber_T)st.st_mtime;
4885 else
4886 rettv->vval.v_number = -1;
4887}
4888
4889/*
4890 * "getftype({fname})" function
4891 */
4892 static void
4893f_getftype(typval_T *argvars, typval_T *rettv)
4894{
4895 char_u *fname;
4896 stat_T st;
4897 char_u *type = NULL;
4898 char *t;
4899
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004900 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004901
4902 rettv->v_type = VAR_STRING;
4903 if (mch_lstat((char *)fname, &st) >= 0)
4904 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004905 if (S_ISREG(st.st_mode))
4906 t = "file";
4907 else if (S_ISDIR(st.st_mode))
4908 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004909 else if (S_ISLNK(st.st_mode))
4910 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004911 else if (S_ISBLK(st.st_mode))
4912 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004913 else if (S_ISCHR(st.st_mode))
4914 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004915 else if (S_ISFIFO(st.st_mode))
4916 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004917 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02004918 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004919 else
4920 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004921 type = vim_strsave((char_u *)t);
4922 }
4923 rettv->vval.v_string = type;
4924}
4925
4926/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01004927 * "getjumplist()" function
4928 */
4929 static void
4930f_getjumplist(typval_T *argvars, typval_T *rettv)
4931{
4932#ifdef FEAT_JUMPLIST
4933 win_T *wp;
4934 int i;
4935 list_T *l;
4936 dict_T *d;
4937#endif
4938
4939 if (rettv_list_alloc(rettv) != OK)
4940 return;
4941
4942#ifdef FEAT_JUMPLIST
Bram Moolenaar00aa0692019-04-27 20:37:57 +02004943 wp = find_tabwin(&argvars[0], &argvars[1], NULL);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004944 if (wp == NULL)
4945 return;
4946
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01004947 cleanup_jumplist(wp, TRUE);
4948
Bram Moolenaar4f505882018-02-10 21:06:32 +01004949 l = list_alloc();
4950 if (l == NULL)
4951 return;
4952
4953 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4954 return;
4955 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
4956
4957 for (i = 0; i < wp->w_jumplistlen; ++i)
4958 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004959 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
4960 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01004961 if ((d = dict_alloc()) == NULL)
4962 return;
4963 if (list_append_dict(l, d) == FAIL)
4964 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004965 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
4966 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004967 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004968 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01004969 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02004970 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01004971 }
4972#endif
4973}
4974
4975/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004976 * "getline(lnum, [end])" function
4977 */
4978 static void
4979f_getline(typval_T *argvars, typval_T *rettv)
4980{
4981 linenr_T lnum;
4982 linenr_T end;
4983 int retlist;
4984
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004985 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004986 if (argvars[1].v_type == VAR_UNKNOWN)
4987 {
4988 end = 0;
4989 retlist = FALSE;
4990 }
4991 else
4992 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004993 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004994 retlist = TRUE;
4995 }
4996
4997 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
4998}
4999
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005000#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005001 static void
5002get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5003{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005004 if (what_arg->v_type == VAR_UNKNOWN)
5005 {
5006 if (rettv_list_alloc(rettv) == OK)
5007 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005008 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005009 }
5010 else
5011 {
5012 if (rettv_dict_alloc(rettv) == OK)
5013 if (is_qf || (wp != NULL))
5014 {
5015 if (what_arg->v_type == VAR_DICT)
5016 {
5017 dict_T *d = what_arg->vval.v_dict;
5018
5019 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005020 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005021 }
5022 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005023 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005024 }
5025 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005026}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005027#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005028
5029/*
5030 * "getloclist()" function
5031 */
5032 static void
5033f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5034{
5035#ifdef FEAT_QUICKFIX
5036 win_T *wp;
5037
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005038 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005039 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5040#endif
5041}
5042
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005043/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005044 * "getpid()" function
5045 */
5046 static void
5047f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5048{
5049 rettv->vval.v_number = mch_get_pid();
5050}
5051
5052 static void
5053getpos_both(
5054 typval_T *argvars,
5055 typval_T *rettv,
5056 int getcurpos)
5057{
5058 pos_T *fp;
5059 list_T *l;
5060 int fnum = -1;
5061
5062 if (rettv_list_alloc(rettv) == OK)
5063 {
5064 l = rettv->vval.v_list;
5065 if (getcurpos)
5066 fp = &curwin->w_cursor;
5067 else
5068 fp = var2fpos(&argvars[0], TRUE, &fnum);
5069 if (fnum != -1)
5070 list_append_number(l, (varnumber_T)fnum);
5071 else
5072 list_append_number(l, (varnumber_T)0);
5073 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5074 : (varnumber_T)0);
5075 list_append_number(l, (fp != NULL)
5076 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5077 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005078 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005079 (varnumber_T)0);
5080 if (getcurpos)
5081 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005082 int save_set_curswant = curwin->w_set_curswant;
5083 colnr_T save_curswant = curwin->w_curswant;
5084 colnr_T save_virtcol = curwin->w_virtcol;
5085
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005086 update_curswant();
5087 list_append_number(l, curwin->w_curswant == MAXCOL ?
5088 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005089
5090 // Do not change "curswant", as it is unexpected that a get
5091 // function has a side effect.
5092 if (save_set_curswant)
5093 {
5094 curwin->w_set_curswant = save_set_curswant;
5095 curwin->w_curswant = save_curswant;
5096 curwin->w_virtcol = save_virtcol;
5097 curwin->w_valid &= ~VALID_VIRTCOL;
5098 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005099 }
5100 }
5101 else
5102 rettv->vval.v_number = FALSE;
5103}
5104
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105/*
5106 * "getcurpos()" function
5107 */
5108 static void
5109f_getcurpos(typval_T *argvars, typval_T *rettv)
5110{
5111 getpos_both(argvars, rettv, TRUE);
5112}
5113
5114/*
5115 * "getpos(string)" function
5116 */
5117 static void
5118f_getpos(typval_T *argvars, typval_T *rettv)
5119{
5120 getpos_both(argvars, rettv, FALSE);
5121}
5122
5123/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005124 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005125 */
5126 static void
5127f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5128{
5129#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005130 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005131#endif
5132}
5133
5134/*
5135 * "getreg()" function
5136 */
5137 static void
5138f_getreg(typval_T *argvars, typval_T *rettv)
5139{
5140 char_u *strregname;
5141 int regname;
5142 int arg2 = FALSE;
5143 int return_list = FALSE;
5144 int error = FALSE;
5145
5146 if (argvars[0].v_type != VAR_UNKNOWN)
5147 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005148 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005149 error = strregname == NULL;
5150 if (argvars[1].v_type != VAR_UNKNOWN)
5151 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005152 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005153 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005154 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005155 }
5156 }
5157 else
5158 strregname = get_vim_var_str(VV_REG);
5159
5160 if (error)
5161 return;
5162
5163 regname = (strregname == NULL ? '"' : *strregname);
5164 if (regname == 0)
5165 regname = '"';
5166
5167 if (return_list)
5168 {
5169 rettv->v_type = VAR_LIST;
5170 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5171 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5172 if (rettv->vval.v_list == NULL)
5173 (void)rettv_list_alloc(rettv);
5174 else
5175 ++rettv->vval.v_list->lv_refcount;
5176 }
5177 else
5178 {
5179 rettv->v_type = VAR_STRING;
5180 rettv->vval.v_string = get_reg_contents(regname,
5181 arg2 ? GREG_EXPR_SRC : 0);
5182 }
5183}
5184
5185/*
5186 * "getregtype()" function
5187 */
5188 static void
5189f_getregtype(typval_T *argvars, typval_T *rettv)
5190{
5191 char_u *strregname;
5192 int regname;
5193 char_u buf[NUMBUFLEN + 2];
5194 long reglen = 0;
5195
5196 if (argvars[0].v_type != VAR_UNKNOWN)
5197 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005198 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005199 if (strregname == NULL) /* type error; errmsg already given */
5200 {
5201 rettv->v_type = VAR_STRING;
5202 rettv->vval.v_string = NULL;
5203 return;
5204 }
5205 }
5206 else
5207 /* Default to v:register */
5208 strregname = get_vim_var_str(VV_REG);
5209
5210 regname = (strregname == NULL ? '"' : *strregname);
5211 if (regname == 0)
5212 regname = '"';
5213
5214 buf[0] = NUL;
5215 buf[1] = NUL;
5216 switch (get_reg_type(regname, &reglen))
5217 {
5218 case MLINE: buf[0] = 'V'; break;
5219 case MCHAR: buf[0] = 'v'; break;
5220 case MBLOCK:
5221 buf[0] = Ctrl_V;
5222 sprintf((char *)buf + 1, "%ld", reglen + 1);
5223 break;
5224 }
5225 rettv->v_type = VAR_STRING;
5226 rettv->vval.v_string = vim_strsave(buf);
5227}
5228
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005229/*
5230 * Returns information (variables, options, etc.) about a tab page
5231 * as a dictionary.
5232 */
5233 static dict_T *
5234get_tabpage_info(tabpage_T *tp, int tp_idx)
5235{
5236 win_T *wp;
5237 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005238 list_T *l;
5239
5240 dict = dict_alloc();
5241 if (dict == NULL)
5242 return NULL;
5243
Bram Moolenaare0be1672018-07-08 16:50:37 +02005244 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005245
5246 l = list_alloc();
5247 if (l != NULL)
5248 {
5249 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
Bram Moolenaar5ca1ac32019-07-04 15:39:28 +02005250 wp != NULL; wp = wp->w_next)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005251 list_append_number(l, (varnumber_T)wp->w_id);
5252 dict_add_list(dict, "windows", l);
5253 }
5254
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005255 /* Make a reference to tabpage variables */
5256 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005257
5258 return dict;
5259}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005260
5261/*
5262 * "gettabinfo()" function
5263 */
5264 static void
5265f_gettabinfo(typval_T *argvars, typval_T *rettv)
5266{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005267 tabpage_T *tp, *tparg = NULL;
5268 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005269 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005270
5271 if (rettv_list_alloc(rettv) != OK)
5272 return;
5273
5274 if (argvars[0].v_type != VAR_UNKNOWN)
5275 {
5276 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005277 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005278 if (tparg == NULL)
5279 return;
5280 }
5281
5282 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005283 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005284 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005285 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005286 if (tparg != NULL && tp != tparg)
5287 continue;
5288 d = get_tabpage_info(tp, tpnr);
5289 if (d != NULL)
5290 list_append_dict(rettv->vval.v_list, d);
5291 if (tparg != NULL)
5292 return;
5293 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005294}
5295
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296/*
5297 * "gettabvar()" function
5298 */
5299 static void
5300f_gettabvar(typval_T *argvars, typval_T *rettv)
5301{
5302 win_T *oldcurwin;
5303 tabpage_T *tp, *oldtabpage;
5304 dictitem_T *v;
5305 char_u *varname;
5306 int done = FALSE;
5307
5308 rettv->v_type = VAR_STRING;
5309 rettv->vval.v_string = NULL;
5310
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005311 varname = tv_get_string_chk(&argvars[1]);
5312 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005313 if (tp != NULL && varname != NULL)
5314 {
5315 /* Set tp to be our tabpage, temporarily. Also set the window to the
5316 * first window in the tabpage, otherwise the window is not valid. */
5317 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005318 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5319 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005320 {
5321 /* look up the variable */
5322 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5323 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5324 if (v != NULL)
5325 {
5326 copy_tv(&v->di_tv, rettv);
5327 done = TRUE;
5328 }
5329 }
5330
5331 /* restore previous notion of curwin */
5332 restore_win(oldcurwin, oldtabpage, TRUE);
5333 }
5334
5335 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5336 copy_tv(&argvars[2], rettv);
5337}
5338
5339/*
5340 * "gettabwinvar()" function
5341 */
5342 static void
5343f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5344{
5345 getwinvar(argvars, rettv, 1);
5346}
5347
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005348/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005349 * "gettagstack()" function
5350 */
5351 static void
5352f_gettagstack(typval_T *argvars, typval_T *rettv)
5353{
5354 win_T *wp = curwin; // default is current window
5355
5356 if (rettv_dict_alloc(rettv) != OK)
5357 return;
5358
5359 if (argvars[0].v_type != VAR_UNKNOWN)
5360 {
5361 wp = find_win_by_nr_or_id(&argvars[0]);
5362 if (wp == NULL)
5363 return;
5364 }
5365
5366 get_tagstack(wp, rettv->vval.v_dict);
5367}
5368
5369/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005370 * Returns information about a window as a dictionary.
5371 */
5372 static dict_T *
5373get_win_info(win_T *wp, short tpnr, short winnr)
5374{
5375 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005376
5377 dict = dict_alloc();
5378 if (dict == NULL)
5379 return NULL;
5380
Bram Moolenaare0be1672018-07-08 16:50:37 +02005381 dict_add_number(dict, "tabnr", tpnr);
5382 dict_add_number(dict, "winnr", winnr);
5383 dict_add_number(dict, "winid", wp->w_id);
5384 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005385 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005386 dict_add_number(dict, "topline", wp->w_topline);
5387 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005388#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005389 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005390#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005391 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005392 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005393 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005394
Bram Moolenaar69905d12017-08-13 18:14:47 +02005395#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005396 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005397#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005398#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005399 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5400 dict_add_number(dict, "loclist",
5401 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005402#endif
5403
Bram Moolenaar30567352016-08-27 21:25:44 +02005404 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005405 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005406
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005407 return dict;
5408}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005409
5410/*
5411 * "getwininfo()" function
5412 */
5413 static void
5414f_getwininfo(typval_T *argvars, typval_T *rettv)
5415{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005416 tabpage_T *tp;
5417 win_T *wp = NULL, *wparg = NULL;
5418 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005419 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005420
5421 if (rettv_list_alloc(rettv) != OK)
5422 return;
5423
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005424 if (argvars[0].v_type != VAR_UNKNOWN)
5425 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005426 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005427 if (wparg == NULL)
5428 return;
5429 }
5430
5431 /* Collect information about either all the windows across all the tab
5432 * pages or one particular window.
5433 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005434 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005435 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005436 tabnr++;
5437 winnr = 0;
5438 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005439 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005440 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005441 if (wparg != NULL && wp != wparg)
5442 continue;
5443 d = get_win_info(wp, tabnr, winnr);
5444 if (d != NULL)
5445 list_append_dict(rettv->vval.v_list, d);
5446 if (wparg != NULL)
5447 /* found information about a specific window */
5448 return;
5449 }
5450 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005451}
5452
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005453/*
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005454 * "win_execute()" function
5455 */
5456 static void
5457f_win_execute(typval_T *argvars, typval_T *rettv)
5458{
5459 int id = (int)tv_get_number(argvars);
Bram Moolenaar820680b2019-08-09 14:56:22 +02005460 tabpage_T *tp;
5461 win_T *wp = win_id2wp_tp(id, &tp);
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005462 win_T *save_curwin;
5463 tabpage_T *save_curtab;
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005464
Bram Moolenaar820680b2019-08-09 14:56:22 +02005465 if (wp != NULL && tp != NULL)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005466 {
Bram Moolenaar820680b2019-08-09 14:56:22 +02005467 if (switch_win_noblock(&save_curwin, &save_curtab, wp, tp, TRUE) == OK)
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005468 {
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005469 check_cursor();
5470 execute_common(argvars, rettv, 1);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005471 }
Bram Moolenaar89adc3a2019-05-30 17:29:40 +02005472 restore_win_noblock(save_curwin, save_curtab, TRUE);
Bram Moolenaar868b7b62019-05-29 21:44:40 +02005473 }
5474}
5475
5476/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005477 * "win_findbuf()" function
5478 */
5479 static void
5480f_win_findbuf(typval_T *argvars, typval_T *rettv)
5481{
5482 if (rettv_list_alloc(rettv) != FAIL)
5483 win_findbuf(argvars, rettv->vval.v_list);
5484}
5485
5486/*
5487 * "win_getid()" function
5488 */
5489 static void
5490f_win_getid(typval_T *argvars, typval_T *rettv)
5491{
5492 rettv->vval.v_number = win_getid(argvars);
5493}
5494
5495/*
5496 * "win_gotoid()" function
5497 */
5498 static void
5499f_win_gotoid(typval_T *argvars, typval_T *rettv)
5500{
5501 rettv->vval.v_number = win_gotoid(argvars);
5502}
5503
5504/*
5505 * "win_id2tabwin()" function
5506 */
5507 static void
5508f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5509{
5510 if (rettv_list_alloc(rettv) != FAIL)
5511 win_id2tabwin(argvars, rettv->vval.v_list);
5512}
5513
5514/*
5515 * "win_id2win()" function
5516 */
5517 static void
5518f_win_id2win(typval_T *argvars, typval_T *rettv)
5519{
5520 rettv->vval.v_number = win_id2win(argvars);
5521}
5522
5523/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005524 * "win_screenpos()" function
5525 */
5526 static void
5527f_win_screenpos(typval_T *argvars, typval_T *rettv)
5528{
5529 win_T *wp;
5530
5531 if (rettv_list_alloc(rettv) == FAIL)
5532 return;
5533
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005534 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005535 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5536 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5537}
5538
5539/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005540 * "getwinpos({timeout})" function
5541 */
5542 static void
5543f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5544{
5545 int x = -1;
5546 int y = -1;
5547
5548 if (rettv_list_alloc(rettv) == FAIL)
5549 return;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005550#if defined(FEAT_GUI) \
5551 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5552 || defined(MSWIN)
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005553 {
5554 varnumber_T timeout = 100;
5555
5556 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005557 timeout = tv_get_number(&argvars[0]);
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005558
5559 (void)ui_get_winpos(&x, &y, timeout);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005560 }
5561#endif
5562 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5563 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5564}
5565
5566
5567/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005568 * "getwinposx()" function
5569 */
5570 static void
5571f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
5572{
5573 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005574#if defined(FEAT_GUI) \
5575 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5576 || defined(MSWIN)
5577
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005578 {
5579 int x, y;
5580
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005581 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005582 rettv->vval.v_number = x;
5583 }
5584#endif
5585}
5586
5587/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005588 * "getwinposy()" function
5589 */
5590 static void
5591f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
5592{
5593 rettv->vval.v_number = -1;
Bram Moolenaar16c34c32019-04-06 22:01:24 +02005594#if defined(FEAT_GUI) \
5595 || (defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)) \
5596 || defined(MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005597 {
5598 int x, y;
5599
Bram Moolenaarfa1e90c2019-04-06 17:47:40 +02005600 if (ui_get_winpos(&x, &y, 100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02005601 rettv->vval.v_number = y;
5602 }
5603#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604}
5605
5606/*
5607 * "getwinvar()" function
5608 */
5609 static void
5610f_getwinvar(typval_T *argvars, typval_T *rettv)
5611{
5612 getwinvar(argvars, rettv, 0);
5613}
5614
5615/*
5616 * "glob()" function
5617 */
5618 static void
5619f_glob(typval_T *argvars, typval_T *rettv)
5620{
5621 int options = WILD_SILENT|WILD_USE_NL;
5622 expand_T xpc;
5623 int error = FALSE;
5624
5625 /* When the optional second argument is non-zero, don't remove matches
5626 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
5627 rettv->v_type = VAR_STRING;
5628 if (argvars[1].v_type != VAR_UNKNOWN)
5629 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005630 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005631 options |= WILD_KEEP_ALL;
5632 if (argvars[2].v_type != VAR_UNKNOWN)
5633 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005634 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005635 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005636 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005637 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005638 options |= WILD_ALLLINKS;
5639 }
5640 }
5641 if (!error)
5642 {
5643 ExpandInit(&xpc);
5644 xpc.xp_context = EXPAND_FILES;
5645 if (p_wic)
5646 options += WILD_ICASE;
5647 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005648 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005649 NULL, options, WILD_ALL);
5650 else if (rettv_list_alloc(rettv) != FAIL)
5651 {
5652 int i;
5653
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005654 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005655 NULL, options, WILD_ALL_KEEP);
5656 for (i = 0; i < xpc.xp_numfiles; i++)
5657 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5658
5659 ExpandCleanup(&xpc);
5660 }
5661 }
5662 else
5663 rettv->vval.v_string = NULL;
5664}
5665
5666/*
5667 * "globpath()" function
5668 */
5669 static void
5670f_globpath(typval_T *argvars, typval_T *rettv)
5671{
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005672 int flags = WILD_IGNORE_COMPLETESLASH;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005673 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005674 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005675 int error = FALSE;
5676 garray_T ga;
5677 int i;
5678
Bram Moolenaar50f91d22019-08-02 19:52:15 +02005679 // When the optional second argument is non-zero, don't remove matches
5680 // for 'wildignore' and don't put matches for 'suffixes' at the end.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005681 rettv->v_type = VAR_STRING;
5682 if (argvars[2].v_type != VAR_UNKNOWN)
5683 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005684 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005685 flags |= WILD_KEEP_ALL;
5686 if (argvars[3].v_type != VAR_UNKNOWN)
5687 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005688 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02005689 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005690 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005691 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005692 flags |= WILD_ALLLINKS;
5693 }
5694 }
5695 if (file != NULL && !error)
5696 {
5697 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005698 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005699 if (rettv->v_type == VAR_STRING)
5700 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
5701 else if (rettv_list_alloc(rettv) != FAIL)
5702 for (i = 0; i < ga.ga_len; ++i)
5703 list_append_string(rettv->vval.v_list,
5704 ((char_u **)(ga.ga_data))[i], -1);
5705 ga_clear_strings(&ga);
5706 }
5707 else
5708 rettv->vval.v_string = NULL;
5709}
5710
5711/*
5712 * "glob2regpat()" function
5713 */
5714 static void
5715f_glob2regpat(typval_T *argvars, typval_T *rettv)
5716{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005717 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005718
5719 rettv->v_type = VAR_STRING;
5720 rettv->vval.v_string = (pat == NULL)
5721 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
5722}
5723
5724/* for VIM_VERSION_ defines */
5725#include "version.h"
5726
5727/*
5728 * "has()" function
5729 */
5730 static void
5731f_has(typval_T *argvars, typval_T *rettv)
5732{
5733 int i;
5734 char_u *name;
5735 int n = FALSE;
5736 static char *(has_list[]) =
5737 {
5738#ifdef AMIGA
5739 "amiga",
5740# ifdef FEAT_ARP
5741 "arp",
5742# endif
5743#endif
5744#ifdef __BEOS__
5745 "beos",
5746#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005747#if defined(BSD) && !defined(MACOS_X)
5748 "bsd",
5749#endif
5750#ifdef hpux
5751 "hpux",
5752#endif
5753#ifdef __linux__
5754 "linux",
5755#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02005756#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01005757 "mac", /* Mac OS X (and, once, Mac OS Classic) */
5758 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02005759# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01005760 "macunix", /* Mac OS X, with the darwin feature */
5761 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02005762# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005763#endif
5764#ifdef __QNX__
5765 "qnx",
5766#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005767#ifdef SUN_SYSTEM
5768 "sun",
5769#else
5770 "moon",
5771#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005772#ifdef UNIX
5773 "unix",
5774#endif
5775#ifdef VMS
5776 "vms",
5777#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005778#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005779 "win32",
5780#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01005781#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005782 "win32unix",
5783#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01005784#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005785 "win64",
5786#endif
5787#ifdef EBCDIC
5788 "ebcdic",
5789#endif
5790#ifndef CASE_INSENSITIVE_FILENAME
5791 "fname_case",
5792#endif
5793#ifdef HAVE_ACL
5794 "acl",
5795#endif
5796#ifdef FEAT_ARABIC
5797 "arabic",
5798#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005799 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005800#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01005801 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02005802#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01005803#ifdef FEAT_AUTOSERVERNAME
5804 "autoservername",
5805#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005806#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005807 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01005808# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005809 "balloon_multiline",
5810# endif
5811#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01005812#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01005813 "balloon_eval_term",
5814#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005815#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
5816 "builtin_terms",
5817# ifdef ALL_BUILTIN_TCAPS
5818 "all_builtin_terms",
5819# endif
5820#endif
5821#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01005822 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005823 || defined(FEAT_GUI_MOTIF))
5824 "browsefilter",
5825#endif
5826#ifdef FEAT_BYTEOFF
5827 "byte_offset",
5828#endif
5829#ifdef FEAT_JOB_CHANNEL
5830 "channel",
5831#endif
5832#ifdef FEAT_CINDENT
5833 "cindent",
5834#endif
5835#ifdef FEAT_CLIENTSERVER
5836 "clientserver",
5837#endif
5838#ifdef FEAT_CLIPBOARD
5839 "clipboard",
5840#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005841 "cmdline_compl",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005842 "cmdline_hist",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005843#ifdef FEAT_COMMENTS
5844 "comments",
5845#endif
5846#ifdef FEAT_CONCEAL
5847 "conceal",
5848#endif
5849#ifdef FEAT_CRYPT
5850 "cryptv",
5851 "crypt-blowfish",
5852 "crypt-blowfish2",
5853#endif
5854#ifdef FEAT_CSCOPE
5855 "cscope",
5856#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005857 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005858#ifdef CURSOR_SHAPE
5859 "cursorshape",
5860#endif
5861#ifdef DEBUG
5862 "debug",
5863#endif
5864#ifdef FEAT_CON_DIALOG
5865 "dialog_con",
5866#endif
5867#ifdef FEAT_GUI_DIALOG
5868 "dialog_gui",
5869#endif
5870#ifdef FEAT_DIFF
5871 "diff",
5872#endif
5873#ifdef FEAT_DIGRAPHS
5874 "digraphs",
5875#endif
5876#ifdef FEAT_DIRECTX
5877 "directx",
5878#endif
5879#ifdef FEAT_DND
5880 "dnd",
5881#endif
5882#ifdef FEAT_EMACS_TAGS
5883 "emacs_tags",
5884#endif
5885 "eval", /* always present, of course! */
5886 "ex_extra", /* graduated feature */
5887#ifdef FEAT_SEARCH_EXTRA
5888 "extra_search",
5889#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005890#ifdef FEAT_SEARCHPATH
5891 "file_in_path",
5892#endif
5893#ifdef FEAT_FILTERPIPE
5894 "filterpipe",
5895#endif
5896#ifdef FEAT_FIND_ID
5897 "find_in_path",
5898#endif
5899#ifdef FEAT_FLOAT
5900 "float",
5901#endif
5902#ifdef FEAT_FOLDING
5903 "folding",
5904#endif
5905#ifdef FEAT_FOOTER
5906 "footer",
5907#endif
5908#if !defined(USE_SYSTEM) && defined(UNIX)
5909 "fork",
5910#endif
5911#ifdef FEAT_GETTEXT
5912 "gettext",
5913#endif
5914#ifdef FEAT_GUI
5915 "gui",
5916#endif
5917#ifdef FEAT_GUI_ATHENA
5918# ifdef FEAT_GUI_NEXTAW
5919 "gui_neXtaw",
5920# else
5921 "gui_athena",
5922# endif
5923#endif
5924#ifdef FEAT_GUI_GTK
5925 "gui_gtk",
5926# ifdef USE_GTK3
5927 "gui_gtk3",
5928# else
5929 "gui_gtk2",
5930# endif
5931#endif
5932#ifdef FEAT_GUI_GNOME
5933 "gui_gnome",
5934#endif
5935#ifdef FEAT_GUI_MAC
5936 "gui_mac",
5937#endif
5938#ifdef FEAT_GUI_MOTIF
5939 "gui_motif",
5940#endif
5941#ifdef FEAT_GUI_PHOTON
5942 "gui_photon",
5943#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01005944#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005945 "gui_win32",
5946#endif
5947#ifdef FEAT_HANGULIN
5948 "hangul_input",
5949#endif
5950#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
5951 "iconv",
5952#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005953 "insert_expand",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005954#ifdef FEAT_JOB_CHANNEL
5955 "job",
5956#endif
5957#ifdef FEAT_JUMPLIST
5958 "jumplist",
5959#endif
5960#ifdef FEAT_KEYMAP
5961 "keymap",
5962#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02005963 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005964#ifdef FEAT_LANGMAP
5965 "langmap",
5966#endif
5967#ifdef FEAT_LIBCALL
5968 "libcall",
5969#endif
5970#ifdef FEAT_LINEBREAK
5971 "linebreak",
5972#endif
5973#ifdef FEAT_LISP
5974 "lispindent",
5975#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005976 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005977 "localmap",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005978#ifdef FEAT_LUA
5979# ifndef DYNAMIC_LUA
5980 "lua",
5981# endif
5982#endif
5983#ifdef FEAT_MENU
5984 "menu",
5985#endif
5986#ifdef FEAT_SESSION
5987 "mksession",
5988#endif
5989#ifdef FEAT_MODIFY_FNAME
5990 "modify_fname",
5991#endif
5992#ifdef FEAT_MOUSE
5993 "mouse",
5994#endif
5995#ifdef FEAT_MOUSESHAPE
5996 "mouseshape",
5997#endif
5998#if defined(UNIX) || defined(VMS)
5999# ifdef FEAT_MOUSE_DEC
6000 "mouse_dec",
6001# endif
6002# ifdef FEAT_MOUSE_GPM
6003 "mouse_gpm",
6004# endif
6005# ifdef FEAT_MOUSE_JSB
6006 "mouse_jsbterm",
6007# endif
6008# ifdef FEAT_MOUSE_NET
6009 "mouse_netterm",
6010# endif
6011# ifdef FEAT_MOUSE_PTERM
6012 "mouse_pterm",
6013# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006014# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006015 "mouse_sgr",
6016# endif
6017# ifdef FEAT_SYSMOUSE
6018 "mouse_sysmouse",
6019# endif
6020# ifdef FEAT_MOUSE_URXVT
6021 "mouse_urxvt",
6022# endif
6023# ifdef FEAT_MOUSE_XTERM
6024 "mouse_xterm",
6025# endif
6026#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006027 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006028#ifdef FEAT_MBYTE_IME
6029 "multi_byte_ime",
6030#endif
6031#ifdef FEAT_MULTI_LANG
6032 "multi_lang",
6033#endif
6034#ifdef FEAT_MZSCHEME
6035#ifndef DYNAMIC_MZSCHEME
6036 "mzscheme",
6037#endif
6038#endif
6039#ifdef FEAT_NUM64
6040 "num64",
6041#endif
6042#ifdef FEAT_OLE
6043 "ole",
6044#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006045#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006046 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006047#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006048#ifdef FEAT_PATH_EXTRA
6049 "path_extra",
6050#endif
6051#ifdef FEAT_PERL
6052#ifndef DYNAMIC_PERL
6053 "perl",
6054#endif
6055#endif
6056#ifdef FEAT_PERSISTENT_UNDO
6057 "persistent_undo",
6058#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006059#if defined(FEAT_PYTHON)
6060 "python_compiled",
6061# if defined(DYNAMIC_PYTHON)
6062 "python_dynamic",
6063# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006064 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006065 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006066# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006067#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006068#if defined(FEAT_PYTHON3)
6069 "python3_compiled",
6070# if defined(DYNAMIC_PYTHON3)
6071 "python3_dynamic",
6072# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006073 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006074 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006075# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006076#endif
6077#ifdef FEAT_POSTSCRIPT
6078 "postscript",
6079#endif
6080#ifdef FEAT_PRINTER
6081 "printer",
6082#endif
6083#ifdef FEAT_PROFILE
6084 "profile",
6085#endif
6086#ifdef FEAT_RELTIME
6087 "reltime",
6088#endif
6089#ifdef FEAT_QUICKFIX
6090 "quickfix",
6091#endif
6092#ifdef FEAT_RIGHTLEFT
6093 "rightleft",
6094#endif
6095#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6096 "ruby",
6097#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006098 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006099#ifdef FEAT_CMDL_INFO
6100 "showcmd",
6101 "cmdline_info",
6102#endif
6103#ifdef FEAT_SIGNS
6104 "signs",
6105#endif
6106#ifdef FEAT_SMARTINDENT
6107 "smartindent",
6108#endif
6109#ifdef STARTUPTIME
6110 "startuptime",
6111#endif
6112#ifdef FEAT_STL_OPT
6113 "statusline",
6114#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006115#ifdef FEAT_NETBEANS_INTG
6116 "netbeans_intg",
6117#endif
Bram Moolenaar427f5b62019-06-09 13:43:51 +02006118#ifdef FEAT_SOUND
6119 "sound",
6120#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006121#ifdef FEAT_SPELL
6122 "spell",
6123#endif
6124#ifdef FEAT_SYN_HL
6125 "syntax",
6126#endif
6127#if defined(USE_SYSTEM) || !defined(UNIX)
6128 "system",
6129#endif
6130#ifdef FEAT_TAG_BINS
6131 "tag_binary",
6132#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006133#ifdef FEAT_TCL
6134# ifndef DYNAMIC_TCL
6135 "tcl",
6136# endif
6137#endif
6138#ifdef FEAT_TERMGUICOLORS
6139 "termguicolors",
6140#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006141#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006142 "terminal",
6143#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006144#ifdef TERMINFO
6145 "terminfo",
6146#endif
6147#ifdef FEAT_TERMRESPONSE
6148 "termresponse",
6149#endif
6150#ifdef FEAT_TEXTOBJ
6151 "textobjects",
6152#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006153#ifdef FEAT_TEXT_PROP
6154 "textprop",
6155#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006156#ifdef HAVE_TGETENT
6157 "tgetent",
6158#endif
6159#ifdef FEAT_TIMERS
6160 "timers",
6161#endif
6162#ifdef FEAT_TITLE
6163 "title",
6164#endif
6165#ifdef FEAT_TOOLBAR
6166 "toolbar",
6167#endif
6168#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6169 "unnamedplus",
6170#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006171 "user-commands", /* was accidentally included in 5.4 */
6172 "user_commands",
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006173#ifdef FEAT_VARTABS
6174 "vartabs",
6175#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006176 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006177#ifdef FEAT_VIMINFO
6178 "viminfo",
6179#endif
Bram Moolenaar558ca4a2019-04-04 18:15:38 +02006180 "vimscript-1",
6181 "vimscript-2",
Bram Moolenaar93a48792019-04-20 21:54:28 +02006182 "vimscript-3",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006183 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006184 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006185 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006186 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006187#ifdef FEAT_VTP
6188 "vtp",
6189#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006190#ifdef FEAT_WILDIGN
6191 "wildignore",
6192#endif
6193#ifdef FEAT_WILDMENU
6194 "wildmenu",
6195#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006196 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006197#ifdef FEAT_WAK
6198 "winaltkeys",
6199#endif
6200#ifdef FEAT_WRITEBACKUP
6201 "writebackup",
6202#endif
6203#ifdef FEAT_XIM
6204 "xim",
6205#endif
6206#ifdef FEAT_XFONTSET
6207 "xfontset",
6208#endif
6209#ifdef FEAT_XPM_W32
6210 "xpm",
6211 "xpm_w32", /* for backward compatibility */
6212#else
6213# if defined(HAVE_XPM)
6214 "xpm",
6215# endif
6216#endif
6217#ifdef USE_XSMP
6218 "xsmp",
6219#endif
6220#ifdef USE_XSMP_INTERACT
6221 "xsmp_interact",
6222#endif
6223#ifdef FEAT_XCLIPBOARD
6224 "xterm_clipboard",
6225#endif
6226#ifdef FEAT_XTERM_SAVE
6227 "xterm_save",
6228#endif
6229#if defined(UNIX) && defined(FEAT_X11)
6230 "X11",
6231#endif
6232 NULL
6233 };
6234
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006235 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006236 for (i = 0; has_list[i] != NULL; ++i)
6237 if (STRICMP(name, has_list[i]) == 0)
6238 {
6239 n = TRUE;
6240 break;
6241 }
6242
6243 if (n == FALSE)
6244 {
6245 if (STRNICMP(name, "patch", 5) == 0)
6246 {
6247 if (name[5] == '-'
6248 && STRLEN(name) >= 11
6249 && vim_isdigit(name[6])
6250 && vim_isdigit(name[8])
6251 && vim_isdigit(name[10]))
6252 {
6253 int major = atoi((char *)name + 6);
6254 int minor = atoi((char *)name + 8);
6255
6256 /* Expect "patch-9.9.01234". */
6257 n = (major < VIM_VERSION_MAJOR
6258 || (major == VIM_VERSION_MAJOR
6259 && (minor < VIM_VERSION_MINOR
6260 || (minor == VIM_VERSION_MINOR
6261 && has_patch(atoi((char *)name + 10))))));
6262 }
6263 else
6264 n = has_patch(atoi((char *)name + 5));
6265 }
6266 else if (STRICMP(name, "vim_starting") == 0)
6267 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006268 else if (STRICMP(name, "ttyin") == 0)
6269 n = mch_input_isatty();
6270 else if (STRICMP(name, "ttyout") == 0)
6271 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006272 else if (STRICMP(name, "multi_byte_encoding") == 0)
6273 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006274#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006275 else if (STRICMP(name, "balloon_multiline") == 0)
6276 n = multiline_balloon_available();
6277#endif
6278#ifdef DYNAMIC_TCL
6279 else if (STRICMP(name, "tcl") == 0)
6280 n = tcl_enabled(FALSE);
6281#endif
6282#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6283 else if (STRICMP(name, "iconv") == 0)
6284 n = iconv_enabled(FALSE);
6285#endif
6286#ifdef DYNAMIC_LUA
6287 else if (STRICMP(name, "lua") == 0)
6288 n = lua_enabled(FALSE);
6289#endif
6290#ifdef DYNAMIC_MZSCHEME
6291 else if (STRICMP(name, "mzscheme") == 0)
6292 n = mzscheme_enabled(FALSE);
6293#endif
6294#ifdef DYNAMIC_RUBY
6295 else if (STRICMP(name, "ruby") == 0)
6296 n = ruby_enabled(FALSE);
6297#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006298#ifdef DYNAMIC_PYTHON
6299 else if (STRICMP(name, "python") == 0)
6300 n = python_enabled(FALSE);
6301#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006302#ifdef DYNAMIC_PYTHON3
6303 else if (STRICMP(name, "python3") == 0)
6304 n = python3_enabled(FALSE);
6305#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006306#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6307 else if (STRICMP(name, "pythonx") == 0)
6308 {
6309# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6310 if (p_pyx == 0)
6311 n = python3_enabled(FALSE) || python_enabled(FALSE);
6312 else if (p_pyx == 3)
6313 n = python3_enabled(FALSE);
6314 else if (p_pyx == 2)
6315 n = python_enabled(FALSE);
6316# elif defined(DYNAMIC_PYTHON)
6317 n = python_enabled(FALSE);
6318# elif defined(DYNAMIC_PYTHON3)
6319 n = python3_enabled(FALSE);
6320# endif
6321 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006322#endif
6323#ifdef DYNAMIC_PERL
6324 else if (STRICMP(name, "perl") == 0)
6325 n = perl_enabled(FALSE);
6326#endif
6327#ifdef FEAT_GUI
6328 else if (STRICMP(name, "gui_running") == 0)
6329 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006330# ifdef FEAT_BROWSE
6331 else if (STRICMP(name, "browse") == 0)
6332 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6333# endif
6334#endif
6335#ifdef FEAT_SYN_HL
6336 else if (STRICMP(name, "syntax_items") == 0)
6337 n = syntax_present(curwin);
6338#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006339#ifdef FEAT_VTP
6340 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006341 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006342#endif
6343#ifdef FEAT_NETBEANS_INTG
6344 else if (STRICMP(name, "netbeans_enabled") == 0)
6345 n = netbeans_active();
6346#endif
Bram Moolenaar4b8366b2019-05-04 17:34:34 +02006347#ifdef FEAT_MOUSE_GPM
6348 else if (STRICMP(name, "mouse_gpm_enabled") == 0)
6349 n = gpm_enabled();
6350#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006351#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006352 else if (STRICMP(name, "terminal") == 0)
6353 n = terminal_enabled();
6354#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006355#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006356 else if (STRICMP(name, "conpty") == 0)
6357 n = use_conpty();
6358#endif
Bram Moolenaar4999a7f2019-08-10 22:21:48 +02006359#ifdef FEAT_CLIPBOARD
6360 else if (STRICMP(name, "clipboard_working") == 0)
6361 n = clip_star.available;
6362#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006363 }
6364
6365 rettv->vval.v_number = n;
6366}
6367
6368/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006369 * "haslocaldir()" function
6370 */
6371 static void
6372f_haslocaldir(typval_T *argvars, typval_T *rettv)
6373{
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006374 tabpage_T *tp = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006375 win_T *wp = NULL;
6376
Bram Moolenaar00aa0692019-04-27 20:37:57 +02006377 wp = find_tabwin(&argvars[0], &argvars[1], &tp);
6378
6379 // Check for window-local and tab-local directories
6380 if (wp != NULL && wp->w_localdir != NULL)
6381 rettv->vval.v_number = 1;
6382 else if (tp != NULL && tp->tp_localdir != NULL)
6383 rettv->vval.v_number = 2;
6384 else
6385 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006386}
6387
6388/*
6389 * "hasmapto()" function
6390 */
6391 static void
6392f_hasmapto(typval_T *argvars, typval_T *rettv)
6393{
6394 char_u *name;
6395 char_u *mode;
6396 char_u buf[NUMBUFLEN];
6397 int abbr = FALSE;
6398
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006399 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006400 if (argvars[1].v_type == VAR_UNKNOWN)
6401 mode = (char_u *)"nvo";
6402 else
6403 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006404 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006405 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006406 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006407 }
6408
6409 if (map_to_exists(name, mode, abbr))
6410 rettv->vval.v_number = TRUE;
6411 else
6412 rettv->vval.v_number = FALSE;
6413}
6414
6415/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006416 * "highlightID(name)" function
6417 */
6418 static void
6419f_hlID(typval_T *argvars, typval_T *rettv)
6420{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006421 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006422}
6423
6424/*
6425 * "highlight_exists()" function
6426 */
6427 static void
6428f_hlexists(typval_T *argvars, typval_T *rettv)
6429{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006430 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006431}
6432
6433/*
6434 * "hostname()" function
6435 */
6436 static void
6437f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
6438{
6439 char_u hostname[256];
6440
6441 mch_get_host_name(hostname, 256);
6442 rettv->v_type = VAR_STRING;
6443 rettv->vval.v_string = vim_strsave(hostname);
6444}
6445
6446/*
6447 * iconv() function
6448 */
6449 static void
6450f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
6451{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006452 char_u buf1[NUMBUFLEN];
6453 char_u buf2[NUMBUFLEN];
6454 char_u *from, *to, *str;
6455 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006456
6457 rettv->v_type = VAR_STRING;
6458 rettv->vval.v_string = NULL;
6459
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006460 str = tv_get_string(&argvars[0]);
6461 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
6462 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006463 vimconv.vc_type = CONV_NONE;
6464 convert_setup(&vimconv, from, to);
6465
6466 /* If the encodings are equal, no conversion needed. */
6467 if (vimconv.vc_type == CONV_NONE)
6468 rettv->vval.v_string = vim_strsave(str);
6469 else
6470 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
6471
6472 convert_setup(&vimconv, NULL, NULL);
6473 vim_free(from);
6474 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006475}
6476
6477/*
6478 * "indent()" function
6479 */
6480 static void
6481f_indent(typval_T *argvars, typval_T *rettv)
6482{
6483 linenr_T lnum;
6484
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006485 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
6487 rettv->vval.v_number = get_indent_lnum(lnum);
6488 else
6489 rettv->vval.v_number = -1;
6490}
6491
6492/*
6493 * "index()" function
6494 */
6495 static void
6496f_index(typval_T *argvars, typval_T *rettv)
6497{
6498 list_T *l;
6499 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006500 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 long idx = 0;
6502 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006503 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006504
6505 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006506 if (argvars[0].v_type == VAR_BLOB)
6507 {
6508 typval_T tv;
6509 int start = 0;
6510
6511 if (argvars[2].v_type != VAR_UNKNOWN)
6512 {
6513 start = tv_get_number_chk(&argvars[2], &error);
6514 if (error)
6515 return;
6516 }
6517 b = argvars[0].vval.v_blob;
6518 if (b == NULL)
6519 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01006520 if (start < 0)
6521 {
6522 start = blob_len(b) + start;
6523 if (start < 0)
6524 start = 0;
6525 }
6526
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006527 for (idx = start; idx < blob_len(b); ++idx)
6528 {
6529 tv.v_type = VAR_NUMBER;
6530 tv.vval.v_number = blob_get(b, idx);
6531 if (tv_equal(&tv, &argvars[1], ic, FALSE))
6532 {
6533 rettv->vval.v_number = idx;
6534 return;
6535 }
6536 }
6537 return;
6538 }
6539 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006540 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006541 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006542 return;
6543 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006544
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006545 l = argvars[0].vval.v_list;
6546 if (l != NULL)
6547 {
6548 item = l->lv_first;
6549 if (argvars[2].v_type != VAR_UNKNOWN)
6550 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006551 /* Start at specified item. Use the cached index that list_find()
6552 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006553 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006554 idx = l->lv_idx;
6555 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006556 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006557 if (error)
6558 item = NULL;
6559 }
6560
6561 for ( ; item != NULL; item = item->li_next, ++idx)
6562 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
6563 {
6564 rettv->vval.v_number = idx;
6565 break;
6566 }
6567 }
6568}
6569
6570static int inputsecret_flag = 0;
6571
6572/*
6573 * "input()" function
6574 * Also handles inputsecret() when inputsecret is set.
6575 */
6576 static void
6577f_input(typval_T *argvars, typval_T *rettv)
6578{
6579 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
6580}
6581
6582/*
6583 * "inputdialog()" function
6584 */
6585 static void
6586f_inputdialog(typval_T *argvars, typval_T *rettv)
6587{
6588#if defined(FEAT_GUI_TEXTDIALOG)
6589 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
6590 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
6591 {
6592 char_u *message;
6593 char_u buf[NUMBUFLEN];
6594 char_u *defstr = (char_u *)"";
6595
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006596 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006597 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006598 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006599 vim_strncpy(IObuff, defstr, IOSIZE - 1);
6600 else
6601 IObuff[0] = NUL;
6602 if (message != NULL && defstr != NULL
6603 && do_dialog(VIM_QUESTION, NULL, message,
6604 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
6605 rettv->vval.v_string = vim_strsave(IObuff);
6606 else
6607 {
6608 if (message != NULL && defstr != NULL
6609 && argvars[1].v_type != VAR_UNKNOWN
6610 && argvars[2].v_type != VAR_UNKNOWN)
6611 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006612 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006613 else
6614 rettv->vval.v_string = NULL;
6615 }
6616 rettv->v_type = VAR_STRING;
6617 }
6618 else
6619#endif
6620 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
6621}
6622
6623/*
6624 * "inputlist()" function
6625 */
6626 static void
6627f_inputlist(typval_T *argvars, typval_T *rettv)
6628{
6629 listitem_T *li;
6630 int selected;
6631 int mouse_used;
6632
6633#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02006634 /* While starting up, there is no place to enter text. When running tests
6635 * with --not-a-term we assume feedkeys() will be used. */
6636 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006637 return;
6638#endif
6639 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
6640 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006641 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006642 return;
6643 }
6644
6645 msg_start();
6646 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
6647 lines_left = Rows; /* avoid more prompt */
6648 msg_scroll = TRUE;
6649 msg_clr_eos();
6650
6651 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
6652 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006653 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006654 msg_putchar('\n');
6655 }
6656
6657 /* Ask for choice. */
6658 selected = prompt_for_number(&mouse_used);
6659 if (mouse_used)
6660 selected -= lines_left;
6661
6662 rettv->vval.v_number = selected;
6663}
6664
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006665static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
6666
6667/*
6668 * "inputrestore()" function
6669 */
6670 static void
6671f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
6672{
6673 if (ga_userinput.ga_len > 0)
6674 {
6675 --ga_userinput.ga_len;
6676 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
6677 + ga_userinput.ga_len);
6678 /* default return is zero == OK */
6679 }
6680 else if (p_verbose > 1)
6681 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01006682 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006683 rettv->vval.v_number = 1; /* Failed */
6684 }
6685}
6686
6687/*
6688 * "inputsave()" function
6689 */
6690 static void
6691f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
6692{
6693 /* Add an entry to the stack of typeahead storage. */
6694 if (ga_grow(&ga_userinput, 1) == OK)
6695 {
6696 save_typeahead((tasave_T *)(ga_userinput.ga_data)
6697 + ga_userinput.ga_len);
6698 ++ga_userinput.ga_len;
6699 /* default return is zero == OK */
6700 }
6701 else
6702 rettv->vval.v_number = 1; /* Failed */
6703}
6704
6705/*
6706 * "inputsecret()" function
6707 */
6708 static void
6709f_inputsecret(typval_T *argvars, typval_T *rettv)
6710{
6711 ++cmdline_star;
6712 ++inputsecret_flag;
6713 f_input(argvars, rettv);
6714 --cmdline_star;
6715 --inputsecret_flag;
6716}
6717
6718/*
6719 * "insert()" function
6720 */
6721 static void
6722f_insert(typval_T *argvars, typval_T *rettv)
6723{
6724 long before = 0;
6725 listitem_T *item;
6726 list_T *l;
6727 int error = FALSE;
6728
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006729 if (argvars[0].v_type == VAR_BLOB)
6730 {
6731 int val, len;
6732 char_u *p;
6733
6734 len = blob_len(argvars[0].vval.v_blob);
6735 if (argvars[2].v_type != VAR_UNKNOWN)
6736 {
6737 before = (long)tv_get_number_chk(&argvars[2], &error);
6738 if (error)
6739 return; // type error; errmsg already given
6740 if (before < 0 || before > len)
6741 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006742 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006743 return;
6744 }
6745 }
6746 val = tv_get_number_chk(&argvars[1], &error);
6747 if (error)
6748 return;
6749 if (val < 0 || val > 255)
6750 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006751 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006752 return;
6753 }
6754
6755 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
6756 return;
6757 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
6758 mch_memmove(p + before + 1, p + before, (size_t)len - before);
6759 *(p + before) = val;
6760 ++argvars[0].vval.v_blob->bv_ga.ga_len;
6761
6762 copy_tv(&argvars[0], rettv);
6763 }
6764 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01006765 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01006766 else if ((l = argvars[0].vval.v_list) != NULL
6767 && !var_check_lock(l->lv_lock,
6768 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006769 {
6770 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006771 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006772 if (error)
6773 return; /* type error; errmsg already given */
6774
6775 if (before == l->lv_len)
6776 item = NULL;
6777 else
6778 {
6779 item = list_find(l, before);
6780 if (item == NULL)
6781 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006782 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006783 l = NULL;
6784 }
6785 }
6786 if (l != NULL)
6787 {
6788 list_insert_tv(l, &argvars[1], item);
6789 copy_tv(&argvars[0], rettv);
6790 }
6791 }
6792}
6793
6794/*
6795 * "invert(expr)" function
6796 */
6797 static void
6798f_invert(typval_T *argvars, typval_T *rettv)
6799{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006800 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006801}
6802
6803/*
6804 * "isdirectory()" function
6805 */
6806 static void
6807f_isdirectory(typval_T *argvars, typval_T *rettv)
6808{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006809 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006810}
6811
6812/*
6813 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
6814 * or it refers to a List or Dictionary that is locked.
6815 */
6816 static int
6817tv_islocked(typval_T *tv)
6818{
6819 return (tv->v_lock & VAR_LOCKED)
6820 || (tv->v_type == VAR_LIST
6821 && tv->vval.v_list != NULL
6822 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
6823 || (tv->v_type == VAR_DICT
6824 && tv->vval.v_dict != NULL
6825 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
6826}
6827
6828/*
6829 * "islocked()" function
6830 */
6831 static void
6832f_islocked(typval_T *argvars, typval_T *rettv)
6833{
6834 lval_T lv;
6835 char_u *end;
6836 dictitem_T *di;
6837
6838 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006839 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01006840 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006841 if (end != NULL && lv.ll_name != NULL)
6842 {
6843 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006844 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006845 else
6846 {
6847 if (lv.ll_tv == NULL)
6848 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006849 di = find_var(lv.ll_name, NULL, TRUE);
6850 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006851 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01006852 /* Consider a variable locked when:
6853 * 1. the variable itself is locked
6854 * 2. the value of the variable is locked.
6855 * 3. the List or Dict value is locked.
6856 */
6857 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
6858 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006859 }
6860 }
6861 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006862 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006863 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006864 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006865 else if (lv.ll_list != NULL)
6866 /* List item. */
6867 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
6868 else
6869 /* Dictionary item. */
6870 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
6871 }
6872 }
6873
6874 clear_lval(&lv);
6875}
6876
6877#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
6878/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02006879 * "isinf()" function
6880 */
6881 static void
6882f_isinf(typval_T *argvars, typval_T *rettv)
6883{
6884 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
6885 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
6886}
6887
6888/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006889 * "isnan()" function
6890 */
6891 static void
6892f_isnan(typval_T *argvars, typval_T *rettv)
6893{
6894 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
6895 && isnan(argvars[0].vval.v_float);
6896}
6897#endif
6898
6899/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006900 * "last_buffer_nr()" function.
6901 */
6902 static void
6903f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
6904{
6905 int n = 0;
6906 buf_T *buf;
6907
Bram Moolenaar29323592016-07-24 22:04:11 +02006908 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006909 if (n < buf->b_fnum)
6910 n = buf->b_fnum;
6911
6912 rettv->vval.v_number = n;
6913}
6914
6915/*
6916 * "len()" function
6917 */
6918 static void
6919f_len(typval_T *argvars, typval_T *rettv)
6920{
6921 switch (argvars[0].v_type)
6922 {
6923 case VAR_STRING:
6924 case VAR_NUMBER:
6925 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006926 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006927 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01006928 case VAR_BLOB:
6929 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
6930 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006931 case VAR_LIST:
6932 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
6933 break;
6934 case VAR_DICT:
6935 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
6936 break;
6937 case VAR_UNKNOWN:
6938 case VAR_SPECIAL:
6939 case VAR_FLOAT:
6940 case VAR_FUNC:
6941 case VAR_PARTIAL:
6942 case VAR_JOB:
6943 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006944 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006945 break;
6946 }
6947}
6948
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006949 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01006950libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006951{
6952#ifdef FEAT_LIBCALL
6953 char_u *string_in;
6954 char_u **string_result;
6955 int nr_result;
6956#endif
6957
6958 rettv->v_type = type;
6959 if (type != VAR_NUMBER)
6960 rettv->vval.v_string = NULL;
6961
6962 if (check_restricted() || check_secure())
6963 return;
6964
6965#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02006966 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006967 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
6968 {
6969 string_in = NULL;
6970 if (argvars[2].v_type == VAR_STRING)
6971 string_in = argvars[2].vval.v_string;
6972 if (type == VAR_NUMBER)
6973 string_result = NULL;
6974 else
6975 string_result = &rettv->vval.v_string;
6976 if (mch_libcall(argvars[0].vval.v_string,
6977 argvars[1].vval.v_string,
6978 string_in,
6979 argvars[2].vval.v_number,
6980 string_result,
6981 &nr_result) == OK
6982 && type == VAR_NUMBER)
6983 rettv->vval.v_number = nr_result;
6984 }
6985#endif
6986}
6987
6988/*
6989 * "libcall()" function
6990 */
6991 static void
6992f_libcall(typval_T *argvars, typval_T *rettv)
6993{
6994 libcall_common(argvars, rettv, VAR_STRING);
6995}
6996
6997/*
6998 * "libcallnr()" function
6999 */
7000 static void
7001f_libcallnr(typval_T *argvars, typval_T *rettv)
7002{
7003 libcall_common(argvars, rettv, VAR_NUMBER);
7004}
7005
7006/*
7007 * "line(string)" function
7008 */
7009 static void
7010f_line(typval_T *argvars, typval_T *rettv)
7011{
7012 linenr_T lnum = 0;
7013 pos_T *fp;
7014 int fnum;
7015
7016 fp = var2fpos(&argvars[0], TRUE, &fnum);
7017 if (fp != NULL)
7018 lnum = fp->lnum;
7019 rettv->vval.v_number = lnum;
7020}
7021
7022/*
7023 * "line2byte(lnum)" function
7024 */
7025 static void
7026f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7027{
7028#ifndef FEAT_BYTEOFF
7029 rettv->vval.v_number = -1;
7030#else
7031 linenr_T lnum;
7032
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007033 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007034 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7035 rettv->vval.v_number = -1;
7036 else
7037 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7038 if (rettv->vval.v_number >= 0)
7039 ++rettv->vval.v_number;
7040#endif
7041}
7042
7043/*
7044 * "lispindent(lnum)" function
7045 */
7046 static void
7047f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7048{
7049#ifdef FEAT_LISP
7050 pos_T pos;
7051 linenr_T lnum;
7052
7053 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007054 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007055 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7056 {
7057 curwin->w_cursor.lnum = lnum;
7058 rettv->vval.v_number = get_lisp_indent();
7059 curwin->w_cursor = pos;
7060 }
7061 else
7062#endif
7063 rettv->vval.v_number = -1;
7064}
7065
7066/*
7067 * "localtime()" function
7068 */
7069 static void
7070f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7071{
7072 rettv->vval.v_number = (varnumber_T)time(NULL);
7073}
7074
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007075#ifdef FEAT_FLOAT
7076/*
7077 * "log()" function
7078 */
7079 static void
7080f_log(typval_T *argvars, typval_T *rettv)
7081{
7082 float_T f = 0.0;
7083
7084 rettv->v_type = VAR_FLOAT;
7085 if (get_float_arg(argvars, &f) == OK)
7086 rettv->vval.v_float = log(f);
7087 else
7088 rettv->vval.v_float = 0.0;
7089}
7090
7091/*
7092 * "log10()" function
7093 */
7094 static void
7095f_log10(typval_T *argvars, typval_T *rettv)
7096{
7097 float_T f = 0.0;
7098
7099 rettv->v_type = VAR_FLOAT;
7100 if (get_float_arg(argvars, &f) == OK)
7101 rettv->vval.v_float = log10(f);
7102 else
7103 rettv->vval.v_float = 0.0;
7104}
7105#endif
7106
7107#ifdef FEAT_LUA
7108/*
7109 * "luaeval()" function
7110 */
7111 static void
7112f_luaeval(typval_T *argvars, typval_T *rettv)
7113{
7114 char_u *str;
7115 char_u buf[NUMBUFLEN];
7116
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007117 if (check_restricted() || check_secure())
7118 return;
7119
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007120 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007121 do_luaeval(str, argvars + 1, rettv);
7122}
7123#endif
7124
7125/*
7126 * "map()" function
7127 */
7128 static void
7129f_map(typval_T *argvars, typval_T *rettv)
7130{
7131 filter_map(argvars, rettv, TRUE);
7132}
7133
7134/*
7135 * "maparg()" function
7136 */
7137 static void
7138f_maparg(typval_T *argvars, typval_T *rettv)
7139{
7140 get_maparg(argvars, rettv, TRUE);
7141}
7142
7143/*
7144 * "mapcheck()" function
7145 */
7146 static void
7147f_mapcheck(typval_T *argvars, typval_T *rettv)
7148{
7149 get_maparg(argvars, rettv, FALSE);
7150}
7151
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007152typedef enum
7153{
7154 MATCH_END, /* matchend() */
7155 MATCH_MATCH, /* match() */
7156 MATCH_STR, /* matchstr() */
7157 MATCH_LIST, /* matchlist() */
7158 MATCH_POS /* matchstrpos() */
7159} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007160
7161 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007162find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007163{
7164 char_u *str = NULL;
7165 long len = 0;
7166 char_u *expr = NULL;
7167 char_u *pat;
7168 regmatch_T regmatch;
7169 char_u patbuf[NUMBUFLEN];
7170 char_u strbuf[NUMBUFLEN];
7171 char_u *save_cpo;
7172 long start = 0;
7173 long nth = 1;
7174 colnr_T startcol = 0;
7175 int match = 0;
7176 list_T *l = NULL;
7177 listitem_T *li = NULL;
7178 long idx = 0;
7179 char_u *tofree = NULL;
7180
7181 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
7182 save_cpo = p_cpo;
7183 p_cpo = (char_u *)"";
7184
7185 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007186 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007187 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007188 /* type MATCH_LIST: return empty list when there are no matches.
7189 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007190 if (rettv_list_alloc(rettv) == FAIL)
7191 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007192 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007193 && (list_append_string(rettv->vval.v_list,
7194 (char_u *)"", 0) == FAIL
7195 || list_append_number(rettv->vval.v_list,
7196 (varnumber_T)-1) == FAIL
7197 || list_append_number(rettv->vval.v_list,
7198 (varnumber_T)-1) == FAIL
7199 || list_append_number(rettv->vval.v_list,
7200 (varnumber_T)-1) == FAIL))
7201 {
7202 list_free(rettv->vval.v_list);
7203 rettv->vval.v_list = NULL;
7204 goto theend;
7205 }
7206 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007207 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007208 {
7209 rettv->v_type = VAR_STRING;
7210 rettv->vval.v_string = NULL;
7211 }
7212
7213 if (argvars[0].v_type == VAR_LIST)
7214 {
7215 if ((l = argvars[0].vval.v_list) == NULL)
7216 goto theend;
7217 li = l->lv_first;
7218 }
7219 else
7220 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007221 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007222 len = (long)STRLEN(str);
7223 }
7224
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007225 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007226 if (pat == NULL)
7227 goto theend;
7228
7229 if (argvars[2].v_type != VAR_UNKNOWN)
7230 {
7231 int error = FALSE;
7232
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007233 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007234 if (error)
7235 goto theend;
7236 if (l != NULL)
7237 {
7238 li = list_find(l, start);
7239 if (li == NULL)
7240 goto theend;
7241 idx = l->lv_idx; /* use the cached index */
7242 }
7243 else
7244 {
7245 if (start < 0)
7246 start = 0;
7247 if (start > len)
7248 goto theend;
7249 /* When "count" argument is there ignore matches before "start",
7250 * otherwise skip part of the string. Differs when pattern is "^"
7251 * or "\<". */
7252 if (argvars[3].v_type != VAR_UNKNOWN)
7253 startcol = start;
7254 else
7255 {
7256 str += start;
7257 len -= start;
7258 }
7259 }
7260
7261 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007262 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007263 if (error)
7264 goto theend;
7265 }
7266
7267 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
7268 if (regmatch.regprog != NULL)
7269 {
7270 regmatch.rm_ic = p_ic;
7271
7272 for (;;)
7273 {
7274 if (l != NULL)
7275 {
7276 if (li == NULL)
7277 {
7278 match = FALSE;
7279 break;
7280 }
7281 vim_free(tofree);
7282 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
7283 if (str == NULL)
7284 break;
7285 }
7286
7287 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
7288
7289 if (match && --nth <= 0)
7290 break;
7291 if (l == NULL && !match)
7292 break;
7293
7294 /* Advance to just after the match. */
7295 if (l != NULL)
7296 {
7297 li = li->li_next;
7298 ++idx;
7299 }
7300 else
7301 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007302 startcol = (colnr_T)(regmatch.startp[0]
7303 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007304 if (startcol > (colnr_T)len
7305 || str + startcol <= regmatch.startp[0])
7306 {
7307 match = FALSE;
7308 break;
7309 }
7310 }
7311 }
7312
7313 if (match)
7314 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007315 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007316 {
7317 listitem_T *li1 = rettv->vval.v_list->lv_first;
7318 listitem_T *li2 = li1->li_next;
7319 listitem_T *li3 = li2->li_next;
7320 listitem_T *li4 = li3->li_next;
7321
7322 vim_free(li1->li_tv.vval.v_string);
7323 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
7324 (int)(regmatch.endp[0] - regmatch.startp[0]));
7325 li3->li_tv.vval.v_number =
7326 (varnumber_T)(regmatch.startp[0] - expr);
7327 li4->li_tv.vval.v_number =
7328 (varnumber_T)(regmatch.endp[0] - expr);
7329 if (l != NULL)
7330 li2->li_tv.vval.v_number = (varnumber_T)idx;
7331 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007332 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007333 {
7334 int i;
7335
7336 /* return list with matched string and submatches */
7337 for (i = 0; i < NSUBEXP; ++i)
7338 {
7339 if (regmatch.endp[i] == NULL)
7340 {
7341 if (list_append_string(rettv->vval.v_list,
7342 (char_u *)"", 0) == FAIL)
7343 break;
7344 }
7345 else if (list_append_string(rettv->vval.v_list,
7346 regmatch.startp[i],
7347 (int)(regmatch.endp[i] - regmatch.startp[i]))
7348 == FAIL)
7349 break;
7350 }
7351 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007352 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007353 {
7354 /* return matched string */
7355 if (l != NULL)
7356 copy_tv(&li->li_tv, rettv);
7357 else
7358 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
7359 (int)(regmatch.endp[0] - regmatch.startp[0]));
7360 }
7361 else if (l != NULL)
7362 rettv->vval.v_number = idx;
7363 else
7364 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007365 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007366 rettv->vval.v_number =
7367 (varnumber_T)(regmatch.startp[0] - str);
7368 else
7369 rettv->vval.v_number =
7370 (varnumber_T)(regmatch.endp[0] - str);
7371 rettv->vval.v_number += (varnumber_T)(str - expr);
7372 }
7373 }
7374 vim_regfree(regmatch.regprog);
7375 }
7376
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007377theend:
7378 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007379 /* matchstrpos() without a list: drop the second item. */
7380 listitem_remove(rettv->vval.v_list,
7381 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007382 vim_free(tofree);
7383 p_cpo = save_cpo;
7384}
7385
7386/*
7387 * "match()" function
7388 */
7389 static void
7390f_match(typval_T *argvars, typval_T *rettv)
7391{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007392 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007393}
7394
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007395/*
7396 * "matchend()" function
7397 */
7398 static void
7399f_matchend(typval_T *argvars, typval_T *rettv)
7400{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007401 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007402}
7403
7404/*
7405 * "matchlist()" function
7406 */
7407 static void
7408f_matchlist(typval_T *argvars, typval_T *rettv)
7409{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007410 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007411}
7412
7413/*
7414 * "matchstr()" function
7415 */
7416 static void
7417f_matchstr(typval_T *argvars, typval_T *rettv)
7418{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007419 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007420}
7421
7422/*
7423 * "matchstrpos()" function
7424 */
7425 static void
7426f_matchstrpos(typval_T *argvars, typval_T *rettv)
7427{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02007428 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007429}
7430
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007431 static void
7432max_min(typval_T *argvars, typval_T *rettv, int domax)
7433{
7434 varnumber_T n = 0;
7435 varnumber_T i;
7436 int error = FALSE;
7437
7438 if (argvars[0].v_type == VAR_LIST)
7439 {
7440 list_T *l;
7441 listitem_T *li;
7442
7443 l = argvars[0].vval.v_list;
7444 if (l != NULL)
7445 {
7446 li = l->lv_first;
7447 if (li != NULL)
7448 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007449 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007450 for (;;)
7451 {
7452 li = li->li_next;
7453 if (li == NULL)
7454 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007455 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007456 if (domax ? i > n : i < n)
7457 n = i;
7458 }
7459 }
7460 }
7461 }
7462 else if (argvars[0].v_type == VAR_DICT)
7463 {
7464 dict_T *d;
7465 int first = TRUE;
7466 hashitem_T *hi;
7467 int todo;
7468
7469 d = argvars[0].vval.v_dict;
7470 if (d != NULL)
7471 {
7472 todo = (int)d->dv_hashtab.ht_used;
7473 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
7474 {
7475 if (!HASHITEM_EMPTY(hi))
7476 {
7477 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007478 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007479 if (first)
7480 {
7481 n = i;
7482 first = FALSE;
7483 }
7484 else if (domax ? i > n : i < n)
7485 n = i;
7486 }
7487 }
7488 }
7489 }
7490 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007491 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007492 rettv->vval.v_number = error ? 0 : n;
7493}
7494
7495/*
7496 * "max()" function
7497 */
7498 static void
7499f_max(typval_T *argvars, typval_T *rettv)
7500{
7501 max_min(argvars, rettv, TRUE);
7502}
7503
7504/*
7505 * "min()" function
7506 */
7507 static void
7508f_min(typval_T *argvars, typval_T *rettv)
7509{
7510 max_min(argvars, rettv, FALSE);
7511}
7512
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007513/*
7514 * Create the directory in which "dir" is located, and higher levels when
7515 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02007516 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007517 */
7518 static int
7519mkdir_recurse(char_u *dir, int prot)
7520{
7521 char_u *p;
7522 char_u *updir;
7523 int r = FAIL;
7524
7525 /* Get end of directory name in "dir".
7526 * We're done when it's "/" or "c:/". */
7527 p = gettail_sep(dir);
7528 if (p <= get_past_head(dir))
7529 return OK;
7530
7531 /* If the directory exists we're done. Otherwise: create it.*/
7532 updir = vim_strnsave(dir, (int)(p - dir));
7533 if (updir == NULL)
7534 return FAIL;
7535 if (mch_isdir(updir))
7536 r = OK;
7537 else if (mkdir_recurse(updir, prot) == OK)
7538 r = vim_mkdir_emsg(updir, prot);
7539 vim_free(updir);
7540 return r;
7541}
7542
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007543/*
7544 * "mkdir()" function
7545 */
7546 static void
7547f_mkdir(typval_T *argvars, typval_T *rettv)
7548{
7549 char_u *dir;
7550 char_u buf[NUMBUFLEN];
7551 int prot = 0755;
7552
7553 rettv->vval.v_number = FAIL;
7554 if (check_restricted() || check_secure())
7555 return;
7556
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007557 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007558 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007559 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007560
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007561 if (*gettail(dir) == NUL)
7562 /* remove trailing slashes */
7563 *gettail_sep(dir) = NUL;
7564
7565 if (argvars[1].v_type != VAR_UNKNOWN)
7566 {
7567 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007568 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007569 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007570 if (prot == -1)
7571 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007572 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007573 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007574 {
7575 if (mch_isdir(dir))
7576 {
7577 /* With the "p" flag it's OK if the dir already exists. */
7578 rettv->vval.v_number = OK;
7579 return;
7580 }
7581 mkdir_recurse(dir, prot);
7582 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007583 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02007584 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007585}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007586
7587/*
7588 * "mode()" function
7589 */
7590 static void
7591f_mode(typval_T *argvars, typval_T *rettv)
7592{
Bram Moolenaar612cc382018-07-29 15:34:26 +02007593 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007594
Bram Moolenaar612cc382018-07-29 15:34:26 +02007595 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007596
7597 if (time_for_testing == 93784)
7598 {
7599 /* Testing the two-character code. */
7600 buf[0] = 'x';
7601 buf[1] = '!';
7602 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02007603#ifdef FEAT_TERMINAL
7604 else if (term_use_loop())
7605 buf[0] = 't';
7606#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007607 else if (VIsual_active)
7608 {
7609 if (VIsual_select)
7610 buf[0] = VIsual_mode + 's' - 'v';
7611 else
7612 buf[0] = VIsual_mode;
7613 }
7614 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
7615 || State == CONFIRM)
7616 {
7617 buf[0] = 'r';
7618 if (State == ASKMORE)
7619 buf[1] = 'm';
7620 else if (State == CONFIRM)
7621 buf[1] = '?';
7622 }
7623 else if (State == EXTERNCMD)
7624 buf[0] = '!';
7625 else if (State & INSERT)
7626 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627 if (State & VREPLACE_FLAG)
7628 {
7629 buf[0] = 'R';
7630 buf[1] = 'v';
7631 }
7632 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01007633 {
7634 if (State & REPLACE_FLAG)
7635 buf[0] = 'R';
7636 else
7637 buf[0] = 'i';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007638 if (ins_compl_active())
7639 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01007640 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01007641 buf[1] = 'x';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007642 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007643 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01007644 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007645 {
7646 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007647 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007648 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01007649 else if (exmode_active == EXMODE_NORMAL)
7650 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007651 }
7652 else
7653 {
7654 buf[0] = 'n';
7655 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007656 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007657 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01007658 // to be able to detect force-linewise/blockwise/characterwise operations
7659 buf[2] = motion_force;
7660 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02007661 else if (restart_edit == 'I' || restart_edit == 'R'
7662 || restart_edit == 'V')
7663 {
7664 buf[1] = 'i';
7665 buf[2] = restart_edit;
7666 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007667 }
7668
7669 /* Clear out the minor mode when the argument is not a non-zero number or
7670 * non-empty string. */
7671 if (!non_zero_arg(&argvars[0]))
7672 buf[1] = NUL;
7673
7674 rettv->vval.v_string = vim_strsave(buf);
7675 rettv->v_type = VAR_STRING;
7676}
7677
7678#if defined(FEAT_MZSCHEME) || defined(PROTO)
7679/*
7680 * "mzeval()" function
7681 */
7682 static void
7683f_mzeval(typval_T *argvars, typval_T *rettv)
7684{
7685 char_u *str;
7686 char_u buf[NUMBUFLEN];
7687
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007688 if (check_restricted() || check_secure())
7689 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007690 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007691 do_mzeval(str, rettv);
7692}
7693
7694 void
7695mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
7696{
7697 typval_T argvars[3];
7698
7699 argvars[0].v_type = VAR_STRING;
7700 argvars[0].vval.v_string = name;
7701 copy_tv(args, &argvars[1]);
7702 argvars[2].v_type = VAR_UNKNOWN;
7703 f_call(argvars, rettv);
7704 clear_tv(&argvars[1]);
7705}
7706#endif
7707
7708/*
7709 * "nextnonblank()" function
7710 */
7711 static void
7712f_nextnonblank(typval_T *argvars, typval_T *rettv)
7713{
7714 linenr_T lnum;
7715
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007716 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007717 {
7718 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
7719 {
7720 lnum = 0;
7721 break;
7722 }
7723 if (*skipwhite(ml_get(lnum)) != NUL)
7724 break;
7725 }
7726 rettv->vval.v_number = lnum;
7727}
7728
7729/*
7730 * "nr2char()" function
7731 */
7732 static void
7733f_nr2char(typval_T *argvars, typval_T *rettv)
7734{
7735 char_u buf[NUMBUFLEN];
7736
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007737 if (has_mbyte)
7738 {
7739 int utf8 = 0;
7740
7741 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007742 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007743 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01007744 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007745 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007746 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007747 }
7748 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007749 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007750 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007751 buf[1] = NUL;
7752 }
7753 rettv->v_type = VAR_STRING;
7754 rettv->vval.v_string = vim_strsave(buf);
7755}
7756
7757/*
7758 * "or(expr, expr)" function
7759 */
7760 static void
7761f_or(typval_T *argvars, typval_T *rettv)
7762{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007763 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
7764 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007765}
7766
7767/*
7768 * "pathshorten()" function
7769 */
7770 static void
7771f_pathshorten(typval_T *argvars, typval_T *rettv)
7772{
7773 char_u *p;
7774
7775 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007776 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007777 if (p == NULL)
7778 rettv->vval.v_string = NULL;
7779 else
7780 {
7781 p = vim_strsave(p);
7782 rettv->vval.v_string = p;
7783 if (p != NULL)
7784 shorten_dir(p);
7785 }
7786}
7787
7788#ifdef FEAT_PERL
7789/*
7790 * "perleval()" function
7791 */
7792 static void
7793f_perleval(typval_T *argvars, typval_T *rettv)
7794{
7795 char_u *str;
7796 char_u buf[NUMBUFLEN];
7797
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007798 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007799 do_perleval(str, rettv);
7800}
7801#endif
7802
7803#ifdef FEAT_FLOAT
7804/*
7805 * "pow()" function
7806 */
7807 static void
7808f_pow(typval_T *argvars, typval_T *rettv)
7809{
7810 float_T fx = 0.0, fy = 0.0;
7811
7812 rettv->v_type = VAR_FLOAT;
7813 if (get_float_arg(argvars, &fx) == OK
7814 && get_float_arg(&argvars[1], &fy) == OK)
7815 rettv->vval.v_float = pow(fx, fy);
7816 else
7817 rettv->vval.v_float = 0.0;
7818}
7819#endif
7820
7821/*
7822 * "prevnonblank()" function
7823 */
7824 static void
7825f_prevnonblank(typval_T *argvars, typval_T *rettv)
7826{
7827 linenr_T lnum;
7828
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007829 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007830 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
7831 lnum = 0;
7832 else
7833 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
7834 --lnum;
7835 rettv->vval.v_number = lnum;
7836}
7837
7838/* This dummy va_list is here because:
7839 * - passing a NULL pointer doesn't work when va_list isn't a pointer
7840 * - locally in the function results in a "used before set" warning
7841 * - using va_start() to initialize it gives "function with fixed args" error */
7842static va_list ap;
7843
7844/*
7845 * "printf()" function
7846 */
7847 static void
7848f_printf(typval_T *argvars, typval_T *rettv)
7849{
7850 char_u buf[NUMBUFLEN];
7851 int len;
7852 char_u *s;
7853 int saved_did_emsg = did_emsg;
7854 char *fmt;
7855
7856 rettv->v_type = VAR_STRING;
7857 rettv->vval.v_string = NULL;
7858
7859 /* Get the required length, allocate the buffer and do it for real. */
7860 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007861 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007862 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007863 if (!did_emsg)
7864 {
7865 s = alloc(len + 1);
7866 if (s != NULL)
7867 {
7868 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02007869 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
7870 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007871 }
7872 }
7873 did_emsg |= saved_did_emsg;
7874}
7875
7876/*
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007877 * "pum_getpos()" function
7878 */
7879 static void
7880f_pum_getpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7881{
7882 if (rettv_dict_alloc(rettv) != OK)
7883 return;
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007884 pum_set_event_info(rettv->vval.v_dict);
Bram Moolenaare9bd5722019-08-17 19:36:06 +02007885}
7886
7887/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007888 * "pumvisible()" function
7889 */
7890 static void
7891f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
7892{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007893 if (pum_visible())
7894 rettv->vval.v_number = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007895}
7896
7897#ifdef FEAT_PYTHON3
7898/*
7899 * "py3eval()" function
7900 */
7901 static void
7902f_py3eval(typval_T *argvars, typval_T *rettv)
7903{
7904 char_u *str;
7905 char_u buf[NUMBUFLEN];
7906
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007907 if (check_restricted() || check_secure())
7908 return;
7909
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007910 if (p_pyx == 0)
7911 p_pyx = 3;
7912
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007913 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007914 do_py3eval(str, rettv);
7915}
7916#endif
7917
7918#ifdef FEAT_PYTHON
7919/*
7920 * "pyeval()" function
7921 */
7922 static void
7923f_pyeval(typval_T *argvars, typval_T *rettv)
7924{
7925 char_u *str;
7926 char_u buf[NUMBUFLEN];
7927
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007928 if (check_restricted() || check_secure())
7929 return;
7930
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007931 if (p_pyx == 0)
7932 p_pyx = 2;
7933
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007934 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007935 do_pyeval(str, rettv);
7936}
7937#endif
7938
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007939#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
7940/*
7941 * "pyxeval()" function
7942 */
7943 static void
7944f_pyxeval(typval_T *argvars, typval_T *rettv)
7945{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007946 if (check_restricted() || check_secure())
7947 return;
7948
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01007949# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
7950 init_pyxversion();
7951 if (p_pyx == 2)
7952 f_pyeval(argvars, rettv);
7953 else
7954 f_py3eval(argvars, rettv);
7955# elif defined(FEAT_PYTHON)
7956 f_pyeval(argvars, rettv);
7957# elif defined(FEAT_PYTHON3)
7958 f_py3eval(argvars, rettv);
7959# endif
7960}
7961#endif
7962
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007963/*
7964 * "range()" function
7965 */
7966 static void
7967f_range(typval_T *argvars, typval_T *rettv)
7968{
7969 varnumber_T start;
7970 varnumber_T end;
7971 varnumber_T stride = 1;
7972 varnumber_T i;
7973 int error = FALSE;
7974
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007975 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976 if (argvars[1].v_type == VAR_UNKNOWN)
7977 {
7978 end = start - 1;
7979 start = 0;
7980 }
7981 else
7982 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007983 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007984 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007985 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007986 }
7987
7988 if (error)
7989 return; /* type error; errmsg already given */
7990 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007991 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007992 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007993 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007994 else
7995 {
7996 if (rettv_list_alloc(rettv) == OK)
7997 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
7998 if (list_append_number(rettv->vval.v_list,
7999 (varnumber_T)i) == FAIL)
8000 break;
8001 }
8002}
8003
8004/*
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008005 * Evaluate "expr" (= "context") for readdir().
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008006 */
8007 static int
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008008readdir_checkitem(void *context, char_u *name)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008009{
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008010 typval_T *expr = (typval_T *)context;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008011 typval_T save_val;
8012 typval_T rettv;
8013 typval_T argv[2];
8014 int retval = 0;
8015 int error = FALSE;
8016
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008017 if (expr->v_type == VAR_UNKNOWN)
8018 return 1;
8019
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008020 prepare_vimvar(VV_VAL, &save_val);
8021 set_vim_var_string(VV_VAL, name, -1);
8022 argv[0].v_type = VAR_STRING;
8023 argv[0].vval.v_string = name;
8024
8025 if (eval_expr_typval(expr, argv, 1, &rettv) == FAIL)
8026 goto theend;
8027
8028 retval = tv_get_number_chk(&rettv, &error);
8029 if (error)
8030 retval = -1;
8031 clear_tv(&rettv);
8032
8033theend:
8034 set_vim_var_string(VV_VAL, NULL, 0);
8035 restore_vimvar(VV_VAL, &save_val);
8036 return retval;
8037}
8038
8039/*
8040 * "readdir()" function
8041 */
8042 static void
8043f_readdir(typval_T *argvars, typval_T *rettv)
8044{
8045 typval_T *expr;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008046 int ret;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008047 char_u *path;
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008048 char_u *p;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008049 garray_T ga;
8050 int i;
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008051
8052 if (rettv_list_alloc(rettv) == FAIL)
8053 return;
8054 path = tv_get_string(&argvars[0]);
8055 expr = &argvars[1];
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008056
Bram Moolenaar701ff0a2019-05-24 14:14:14 +02008057 ret = readdir_core(&ga, path, (void *)expr, readdir_checkitem);
8058 if (ret == OK && rettv->vval.v_list != NULL && ga.ga_len > 0)
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008059 {
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008060 for (i = 0; i < ga.ga_len; i++)
8061 {
8062 p = ((char_u **)ga.ga_data)[i];
8063 list_append_string(rettv->vval.v_list, p, -1);
8064 }
8065 }
Bram Moolenaar334ad412019-04-19 15:20:46 +02008066 ga_clear_strings(&ga);
Bram Moolenaar543c9b12019-04-05 22:50:40 +02008067}
8068
8069/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008070 * "readfile()" function
8071 */
8072 static void
8073f_readfile(typval_T *argvars, typval_T *rettv)
8074{
8075 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008076 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008077 int failed = FALSE;
8078 char_u *fname;
8079 FILE *fd;
8080 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
8081 int io_size = sizeof(buf);
8082 int readlen; /* size of last fread() */
8083 char_u *prev = NULL; /* previously read bytes, if any */
8084 long prevlen = 0; /* length of data in prev */
8085 long prevsize = 0; /* size of prev buffer */
8086 long maxline = MAXLNUM;
8087 long cnt = 0;
8088 char_u *p; /* position in buf */
8089 char_u *start; /* start of current line */
8090
8091 if (argvars[1].v_type != VAR_UNKNOWN)
8092 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008093 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008094 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008095 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
8096 blob = TRUE;
8097
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008098 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008099 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008100 }
8101
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008102 if (blob)
8103 {
8104 if (rettv_blob_alloc(rettv) == FAIL)
8105 return;
8106 }
8107 else
8108 {
8109 if (rettv_list_alloc(rettv) == FAIL)
8110 return;
8111 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008112
8113 /* Always open the file in binary mode, library functions have a mind of
8114 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008115 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008116 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
8117 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008118 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008119 return;
8120 }
8121
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008122 if (blob)
8123 {
8124 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
8125 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008126 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008127 blob_free(rettv->vval.v_blob);
8128 }
8129 fclose(fd);
8130 return;
8131 }
8132
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008133 while (cnt < maxline || maxline < 0)
8134 {
8135 readlen = (int)fread(buf, 1, io_size, fd);
8136
8137 /* This for loop processes what was read, but is also entered at end
8138 * of file so that either:
8139 * - an incomplete line gets written
8140 * - a "binary" file gets an empty line at the end if it ends in a
8141 * newline. */
8142 for (p = buf, start = buf;
8143 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
8144 ++p)
8145 {
8146 if (*p == '\n' || readlen <= 0)
8147 {
8148 listitem_T *li;
8149 char_u *s = NULL;
8150 long_u len = p - start;
8151
8152 /* Finished a line. Remove CRs before NL. */
8153 if (readlen > 0 && !binary)
8154 {
8155 while (len > 0 && start[len - 1] == '\r')
8156 --len;
8157 /* removal may cross back to the "prev" string */
8158 if (len == 0)
8159 while (prevlen > 0 && prev[prevlen - 1] == '\r')
8160 --prevlen;
8161 }
8162 if (prevlen == 0)
8163 s = vim_strnsave(start, (int)len);
8164 else
8165 {
8166 /* Change "prev" buffer to be the right size. This way
8167 * the bytes are only copied once, and very long lines are
8168 * allocated only once. */
8169 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
8170 {
8171 mch_memmove(s + prevlen, start, len);
8172 s[prevlen + len] = NUL;
8173 prev = NULL; /* the list will own the string */
8174 prevlen = prevsize = 0;
8175 }
8176 }
8177 if (s == NULL)
8178 {
8179 do_outofmem_msg((long_u) prevlen + len + 1);
8180 failed = TRUE;
8181 break;
8182 }
8183
8184 if ((li = listitem_alloc()) == NULL)
8185 {
8186 vim_free(s);
8187 failed = TRUE;
8188 break;
8189 }
8190 li->li_tv.v_type = VAR_STRING;
8191 li->li_tv.v_lock = 0;
8192 li->li_tv.vval.v_string = s;
8193 list_append(rettv->vval.v_list, li);
8194
8195 start = p + 1; /* step over newline */
8196 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
8197 break;
8198 }
8199 else if (*p == NUL)
8200 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008201 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
8202 * when finding the BF and check the previous two bytes. */
8203 else if (*p == 0xbf && enc_utf8 && !binary)
8204 {
8205 /* Find the two bytes before the 0xbf. If p is at buf, or buf
8206 * + 1, these may be in the "prev" string. */
8207 char_u back1 = p >= buf + 1 ? p[-1]
8208 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
8209 char_u back2 = p >= buf + 2 ? p[-2]
8210 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
8211 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
8212
8213 if (back2 == 0xef && back1 == 0xbb)
8214 {
8215 char_u *dest = p - 2;
8216
8217 /* Usually a BOM is at the beginning of a file, and so at
8218 * the beginning of a line; then we can just step over it.
8219 */
8220 if (start == dest)
8221 start = p + 1;
8222 else
8223 {
8224 /* have to shuffle buf to close gap */
8225 int adjust_prevlen = 0;
8226
8227 if (dest < buf)
8228 {
8229 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
8230 dest = buf;
8231 }
8232 if (readlen > p - buf + 1)
8233 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
8234 readlen -= 3 - adjust_prevlen;
8235 prevlen -= adjust_prevlen;
8236 p = dest - 1;
8237 }
8238 }
8239 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008240 } /* for */
8241
8242 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
8243 break;
8244 if (start < p)
8245 {
8246 /* There's part of a line in buf, store it in "prev". */
8247 if (p - start + prevlen >= prevsize)
8248 {
8249 /* need bigger "prev" buffer */
8250 char_u *newprev;
8251
8252 /* A common use case is ordinary text files and "prev" gets a
8253 * fragment of a line, so the first allocation is made
8254 * small, to avoid repeatedly 'allocing' large and
8255 * 'reallocing' small. */
8256 if (prevsize == 0)
8257 prevsize = (long)(p - start);
8258 else
8259 {
8260 long grow50pc = (prevsize * 3) / 2;
8261 long growmin = (long)((p - start) * 2 + prevlen);
8262 prevsize = grow50pc > growmin ? grow50pc : growmin;
8263 }
Bram Moolenaarc799fe22019-05-28 23:08:19 +02008264 newprev = vim_realloc(prev, prevsize);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008265 if (newprev == NULL)
8266 {
8267 do_outofmem_msg((long_u)prevsize);
8268 failed = TRUE;
8269 break;
8270 }
8271 prev = newprev;
8272 }
8273 /* Add the line part to end of "prev". */
8274 mch_memmove(prev + prevlen, start, p - start);
8275 prevlen += (long)(p - start);
8276 }
8277 } /* while */
8278
8279 /*
8280 * For a negative line count use only the lines at the end of the file,
8281 * free the rest.
8282 */
8283 if (!failed && maxline < 0)
8284 while (cnt > -maxline)
8285 {
8286 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
8287 --cnt;
8288 }
8289
8290 if (failed)
8291 {
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008292 // an empty list is returned on error
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008293 list_free(rettv->vval.v_list);
Bram Moolenaar6ed88192019-05-11 18:37:44 +02008294 rettv_list_alloc(rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008295 }
8296
8297 vim_free(prev);
8298 fclose(fd);
8299}
8300
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02008301 static void
8302return_register(int regname, typval_T *rettv)
8303{
8304 char_u buf[2] = {0, 0};
8305
8306 buf[0] = (char_u)regname;
8307 rettv->v_type = VAR_STRING;
8308 rettv->vval.v_string = vim_strsave(buf);
8309}
8310
8311/*
8312 * "reg_executing()" function
8313 */
8314 static void
8315f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
8316{
8317 return_register(reg_executing, rettv);
8318}
8319
8320/*
8321 * "reg_recording()" function
8322 */
8323 static void
8324f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
8325{
8326 return_register(reg_recording, rettv);
8327}
8328
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008329#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008330/*
8331 * Convert a List to proftime_T.
8332 * Return FAIL when there is something wrong.
8333 */
8334 static int
8335list2proftime(typval_T *arg, proftime_T *tm)
8336{
8337 long n1, n2;
8338 int error = FALSE;
8339
8340 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
8341 || arg->vval.v_list->lv_len != 2)
8342 return FAIL;
8343 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
8344 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008345# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008346 tm->HighPart = n1;
8347 tm->LowPart = n2;
8348# else
8349 tm->tv_sec = n1;
8350 tm->tv_usec = n2;
8351# endif
8352 return error ? FAIL : OK;
8353}
8354#endif /* FEAT_RELTIME */
8355
8356/*
8357 * "reltime()" function
8358 */
8359 static void
8360f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8361{
8362#ifdef FEAT_RELTIME
8363 proftime_T res;
8364 proftime_T start;
8365
8366 if (argvars[0].v_type == VAR_UNKNOWN)
8367 {
8368 /* No arguments: get current time. */
8369 profile_start(&res);
8370 }
8371 else if (argvars[1].v_type == VAR_UNKNOWN)
8372 {
8373 if (list2proftime(&argvars[0], &res) == FAIL)
8374 return;
8375 profile_end(&res);
8376 }
8377 else
8378 {
8379 /* Two arguments: compute the difference. */
8380 if (list2proftime(&argvars[0], &start) == FAIL
8381 || list2proftime(&argvars[1], &res) == FAIL)
8382 return;
8383 profile_sub(&res, &start);
8384 }
8385
8386 if (rettv_list_alloc(rettv) == OK)
8387 {
8388 long n1, n2;
8389
Bram Moolenaar4f974752019-02-17 17:44:42 +01008390# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008391 n1 = res.HighPart;
8392 n2 = res.LowPart;
8393# else
8394 n1 = res.tv_sec;
8395 n2 = res.tv_usec;
8396# endif
8397 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
8398 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
8399 }
8400#endif
8401}
8402
8403#ifdef FEAT_FLOAT
8404/*
8405 * "reltimefloat()" function
8406 */
8407 static void
8408f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
8409{
8410# ifdef FEAT_RELTIME
8411 proftime_T tm;
8412# endif
8413
8414 rettv->v_type = VAR_FLOAT;
8415 rettv->vval.v_float = 0;
8416# ifdef FEAT_RELTIME
8417 if (list2proftime(&argvars[0], &tm) == OK)
8418 rettv->vval.v_float = profile_float(&tm);
8419# endif
8420}
8421#endif
8422
8423/*
8424 * "reltimestr()" function
8425 */
8426 static void
8427f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
8428{
8429#ifdef FEAT_RELTIME
8430 proftime_T tm;
8431#endif
8432
8433 rettv->v_type = VAR_STRING;
8434 rettv->vval.v_string = NULL;
8435#ifdef FEAT_RELTIME
8436 if (list2proftime(&argvars[0], &tm) == OK)
8437 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
8438#endif
8439}
8440
8441#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008442 static void
8443make_connection(void)
8444{
8445 if (X_DISPLAY == NULL
8446# ifdef FEAT_GUI
8447 && !gui.in_use
8448# endif
8449 )
8450 {
8451 x_force_connect = TRUE;
8452 setup_term_clip();
8453 x_force_connect = FALSE;
8454 }
8455}
8456
8457 static int
8458check_connection(void)
8459{
8460 make_connection();
8461 if (X_DISPLAY == NULL)
8462 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008463 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008464 return FAIL;
8465 }
8466 return OK;
8467}
8468#endif
8469
8470#ifdef FEAT_CLIENTSERVER
8471 static void
8472remote_common(typval_T *argvars, typval_T *rettv, int expr)
8473{
8474 char_u *server_name;
8475 char_u *keys;
8476 char_u *r = NULL;
8477 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008478 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008479# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008480 HWND w;
8481# else
8482 Window w;
8483# endif
8484
8485 if (check_restricted() || check_secure())
8486 return;
8487
8488# ifdef FEAT_X11
8489 if (check_connection() == FAIL)
8490 return;
8491# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008492 if (argvars[2].v_type != VAR_UNKNOWN
8493 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008494 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008495
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008496 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008497 if (server_name == NULL)
8498 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008499 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01008500# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008501 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008502# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008503 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
8504 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008505# endif
8506 {
8507 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008508 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008509 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008510 vim_free(r);
8511 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008512 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008513 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008514 return;
8515 }
8516
8517 rettv->vval.v_string = r;
8518
8519 if (argvars[2].v_type != VAR_UNKNOWN)
8520 {
8521 dictitem_T v;
8522 char_u str[30];
8523 char_u *idvar;
8524
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008525 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008526 if (idvar != NULL && *idvar != NUL)
8527 {
8528 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
8529 v.di_tv.v_type = VAR_STRING;
8530 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008531 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008532 vim_free(v.di_tv.vval.v_string);
8533 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008534 }
8535}
8536#endif
8537
8538/*
8539 * "remote_expr()" function
8540 */
8541 static void
8542f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
8543{
8544 rettv->v_type = VAR_STRING;
8545 rettv->vval.v_string = NULL;
8546#ifdef FEAT_CLIENTSERVER
8547 remote_common(argvars, rettv, TRUE);
8548#endif
8549}
8550
8551/*
8552 * "remote_foreground()" function
8553 */
8554 static void
8555f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8556{
8557#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01008558# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008559 /* On Win32 it's done in this application. */
8560 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008561 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008562
8563 if (server_name != NULL)
8564 serverForeground(server_name);
8565 }
8566# else
8567 /* Send a foreground() expression to the server. */
8568 argvars[1].v_type = VAR_STRING;
8569 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
8570 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02008571 rettv->v_type = VAR_STRING;
8572 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008573 remote_common(argvars, rettv, TRUE);
8574 vim_free(argvars[1].vval.v_string);
8575# endif
8576#endif
8577}
8578
8579 static void
8580f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
8581{
8582#ifdef FEAT_CLIENTSERVER
8583 dictitem_T v;
8584 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008585# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008586 long_u n = 0;
8587# endif
8588 char_u *serverid;
8589
8590 if (check_restricted() || check_secure())
8591 {
8592 rettv->vval.v_number = -1;
8593 return;
8594 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008595 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008596 if (serverid == NULL)
8597 {
8598 rettv->vval.v_number = -1;
8599 return; /* type error; errmsg already given */
8600 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01008601# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008602 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
8603 if (n == 0)
8604 rettv->vval.v_number = -1;
8605 else
8606 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008607 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008608 rettv->vval.v_number = (s != NULL);
8609 }
8610# else
8611 if (check_connection() == FAIL)
8612 return;
8613
8614 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
8615 serverStrToWin(serverid), &s);
8616# endif
8617
8618 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
8619 {
8620 char_u *retvar;
8621
8622 v.di_tv.v_type = VAR_STRING;
8623 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008624 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008625 if (retvar != NULL)
8626 set_var(retvar, &v.di_tv, FALSE);
8627 vim_free(v.di_tv.vval.v_string);
8628 }
8629#else
8630 rettv->vval.v_number = -1;
8631#endif
8632}
8633
8634 static void
8635f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
8636{
8637 char_u *r = NULL;
8638
8639#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008640 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008641
8642 if (serverid != NULL && !check_restricted() && !check_secure())
8643 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008644 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01008645# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01008646 /* The server's HWND is encoded in the 'id' parameter */
8647 long_u n = 0;
8648# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008649
8650 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008651 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008652
Bram Moolenaar4f974752019-02-17 17:44:42 +01008653# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008654 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
8655 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008656 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008657 if (r == NULL)
8658# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01008659 if (check_connection() == FAIL
8660 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
8661 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008662# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008663 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008664 }
8665#endif
8666 rettv->v_type = VAR_STRING;
8667 rettv->vval.v_string = r;
8668}
8669
8670/*
8671 * "remote_send()" function
8672 */
8673 static void
8674f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
8675{
8676 rettv->v_type = VAR_STRING;
8677 rettv->vval.v_string = NULL;
8678#ifdef FEAT_CLIENTSERVER
8679 remote_common(argvars, rettv, FALSE);
8680#endif
8681}
8682
8683/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008684 * "remote_startserver()" function
8685 */
8686 static void
8687f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8688{
8689#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008690 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008691
8692 if (server == NULL)
8693 return; /* type error; errmsg already given */
8694 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008695 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008696 else
8697 {
8698# ifdef FEAT_X11
8699 if (check_connection() == OK)
8700 serverRegisterName(X_DISPLAY, server);
8701# else
8702 serverSetName(server);
8703# endif
8704 }
8705#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008706 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01008707#endif
8708}
8709
8710/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008711 * "remove()" function
8712 */
8713 static void
8714f_remove(typval_T *argvars, typval_T *rettv)
8715{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008716 char_u *arg_errmsg = (char_u *)N_("remove() argument");
8717
8718 if (argvars[0].v_type == VAR_DICT)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008719 dict_remove(argvars, rettv, arg_errmsg);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01008720 else if (argvars[0].v_type == VAR_BLOB)
Bram Moolenaar9f9fe372019-07-27 23:12:12 +02008721 blob_remove(argvars, rettv);
8722 else if (argvars[0].v_type == VAR_LIST)
8723 list_remove(argvars, rettv, arg_errmsg);
8724 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01008725 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008726}
8727
8728/*
8729 * "rename({from}, {to})" function
8730 */
8731 static void
8732f_rename(typval_T *argvars, typval_T *rettv)
8733{
8734 char_u buf[NUMBUFLEN];
8735
8736 if (check_restricted() || check_secure())
8737 rettv->vval.v_number = -1;
8738 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008739 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
8740 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008741}
8742
8743/*
8744 * "repeat()" function
8745 */
8746 static void
8747f_repeat(typval_T *argvars, typval_T *rettv)
8748{
8749 char_u *p;
8750 int n;
8751 int slen;
8752 int len;
8753 char_u *r;
8754 int i;
8755
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008756 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008757 if (argvars[0].v_type == VAR_LIST)
8758 {
8759 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
8760 while (n-- > 0)
8761 if (list_extend(rettv->vval.v_list,
8762 argvars[0].vval.v_list, NULL) == FAIL)
8763 break;
8764 }
8765 else
8766 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008767 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008768 rettv->v_type = VAR_STRING;
8769 rettv->vval.v_string = NULL;
8770
8771 slen = (int)STRLEN(p);
8772 len = slen * n;
8773 if (len <= 0)
8774 return;
8775
8776 r = alloc(len + 1);
8777 if (r != NULL)
8778 {
8779 for (i = 0; i < n; i++)
8780 mch_memmove(r + i * slen, p, (size_t)slen);
8781 r[len] = NUL;
8782 }
8783
8784 rettv->vval.v_string = r;
8785 }
8786}
8787
8788/*
8789 * "resolve()" function
8790 */
8791 static void
8792f_resolve(typval_T *argvars, typval_T *rettv)
8793{
8794 char_u *p;
8795#ifdef HAVE_READLINK
8796 char_u *buf = NULL;
8797#endif
8798
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008799 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008800#ifdef FEAT_SHORTCUT
8801 {
8802 char_u *v = NULL;
8803
Bram Moolenaardce1e892019-02-10 23:18:53 +01008804 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008805 if (v != NULL)
8806 rettv->vval.v_string = v;
8807 else
8808 rettv->vval.v_string = vim_strsave(p);
8809 }
8810#else
8811# ifdef HAVE_READLINK
8812 {
8813 char_u *cpy;
8814 int len;
8815 char_u *remain = NULL;
8816 char_u *q;
8817 int is_relative_to_current = FALSE;
8818 int has_trailing_pathsep = FALSE;
8819 int limit = 100;
8820
8821 p = vim_strsave(p);
8822
8823 if (p[0] == '.' && (vim_ispathsep(p[1])
8824 || (p[1] == '.' && (vim_ispathsep(p[2])))))
8825 is_relative_to_current = TRUE;
8826
8827 len = STRLEN(p);
8828 if (len > 0 && after_pathsep(p, p + len))
8829 {
8830 has_trailing_pathsep = TRUE;
8831 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
8832 }
8833
8834 q = getnextcomp(p);
8835 if (*q != NUL)
8836 {
8837 /* Separate the first path component in "p", and keep the
8838 * remainder (beginning with the path separator). */
8839 remain = vim_strsave(q - 1);
8840 q[-1] = NUL;
8841 }
8842
8843 buf = alloc(MAXPATHL + 1);
8844 if (buf == NULL)
8845 goto fail;
8846
8847 for (;;)
8848 {
8849 for (;;)
8850 {
8851 len = readlink((char *)p, (char *)buf, MAXPATHL);
8852 if (len <= 0)
8853 break;
8854 buf[len] = NUL;
8855
8856 if (limit-- == 0)
8857 {
8858 vim_free(p);
8859 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008860 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008861 rettv->vval.v_string = NULL;
8862 goto fail;
8863 }
8864
8865 /* Ensure that the result will have a trailing path separator
8866 * if the argument has one. */
8867 if (remain == NULL && has_trailing_pathsep)
8868 add_pathsep(buf);
8869
8870 /* Separate the first path component in the link value and
8871 * concatenate the remainders. */
8872 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
8873 if (*q != NUL)
8874 {
8875 if (remain == NULL)
8876 remain = vim_strsave(q - 1);
8877 else
8878 {
8879 cpy = concat_str(q - 1, remain);
8880 if (cpy != NULL)
8881 {
8882 vim_free(remain);
8883 remain = cpy;
8884 }
8885 }
8886 q[-1] = NUL;
8887 }
8888
8889 q = gettail(p);
8890 if (q > p && *q == NUL)
8891 {
8892 /* Ignore trailing path separator. */
8893 q[-1] = NUL;
8894 q = gettail(p);
8895 }
8896 if (q > p && !mch_isFullName(buf))
8897 {
8898 /* symlink is relative to directory of argument */
Bram Moolenaar964b3742019-05-24 18:54:09 +02008899 cpy = alloc(STRLEN(p) + STRLEN(buf) + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008900 if (cpy != NULL)
8901 {
8902 STRCPY(cpy, p);
8903 STRCPY(gettail(cpy), buf);
8904 vim_free(p);
8905 p = cpy;
8906 }
8907 }
8908 else
8909 {
8910 vim_free(p);
8911 p = vim_strsave(buf);
8912 }
8913 }
8914
8915 if (remain == NULL)
8916 break;
8917
8918 /* Append the first path component of "remain" to "p". */
8919 q = getnextcomp(remain + 1);
8920 len = q - remain - (*q != NUL);
8921 cpy = vim_strnsave(p, STRLEN(p) + len);
8922 if (cpy != NULL)
8923 {
8924 STRNCAT(cpy, remain, len);
8925 vim_free(p);
8926 p = cpy;
8927 }
8928 /* Shorten "remain". */
8929 if (*q != NUL)
8930 STRMOVE(remain, q - 1);
8931 else
Bram Moolenaard23a8232018-02-10 18:45:26 +01008932 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008933 }
8934
8935 /* If the result is a relative path name, make it explicitly relative to
8936 * the current directory if and only if the argument had this form. */
8937 if (!vim_ispathsep(*p))
8938 {
8939 if (is_relative_to_current
8940 && *p != NUL
8941 && !(p[0] == '.'
8942 && (p[1] == NUL
8943 || vim_ispathsep(p[1])
8944 || (p[1] == '.'
8945 && (p[2] == NUL
8946 || vim_ispathsep(p[2]))))))
8947 {
8948 /* Prepend "./". */
8949 cpy = concat_str((char_u *)"./", p);
8950 if (cpy != NULL)
8951 {
8952 vim_free(p);
8953 p = cpy;
8954 }
8955 }
8956 else if (!is_relative_to_current)
8957 {
8958 /* Strip leading "./". */
8959 q = p;
8960 while (q[0] == '.' && vim_ispathsep(q[1]))
8961 q += 2;
8962 if (q > p)
8963 STRMOVE(p, p + 2);
8964 }
8965 }
8966
8967 /* Ensure that the result will have no trailing path separator
8968 * if the argument had none. But keep "/" or "//". */
8969 if (!has_trailing_pathsep)
8970 {
8971 q = p + STRLEN(p);
8972 if (after_pathsep(p, q))
8973 *gettail_sep(p) = NUL;
8974 }
8975
8976 rettv->vval.v_string = p;
8977 }
8978# else
8979 rettv->vval.v_string = vim_strsave(p);
8980# endif
8981#endif
8982
8983 simplify_filename(rettv->vval.v_string);
8984
8985#ifdef HAVE_READLINK
8986fail:
8987 vim_free(buf);
8988#endif
8989 rettv->v_type = VAR_STRING;
8990}
8991
8992/*
8993 * "reverse({list})" function
8994 */
8995 static void
8996f_reverse(typval_T *argvars, typval_T *rettv)
8997{
8998 list_T *l;
8999 listitem_T *li, *ni;
9000
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009001 if (argvars[0].v_type == VAR_BLOB)
9002 {
9003 blob_T *b = argvars[0].vval.v_blob;
9004 int i, len = blob_len(b);
9005
9006 for (i = 0; i < len / 2; i++)
9007 {
9008 int tmp = blob_get(b, i);
9009
9010 blob_set(b, i, blob_get(b, len - i - 1));
9011 blob_set(b, len - i - 1, tmp);
9012 }
9013 rettv_blob_set(rettv, b);
9014 return;
9015 }
9016
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009017 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009018 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009019 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009020 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009021 (char_u *)N_("reverse() argument"), TRUE))
9022 {
9023 li = l->lv_last;
9024 l->lv_first = l->lv_last = NULL;
9025 l->lv_len = 0;
9026 while (li != NULL)
9027 {
9028 ni = li->li_prev;
9029 list_append(l, li);
9030 li = ni;
9031 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02009032 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009033 l->lv_idx = l->lv_len - l->lv_idx - 1;
9034 }
9035}
9036
9037#define SP_NOMOVE 0x01 /* don't move cursor */
9038#define SP_REPEAT 0x02 /* repeat to find outer pair */
9039#define SP_RETCOUNT 0x04 /* return matchcount */
9040#define SP_SETPCMARK 0x08 /* set previous context mark */
9041#define SP_START 0x10 /* accept match at start position */
9042#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
9043#define SP_END 0x40 /* leave cursor at end of match */
9044#define SP_COLUMN 0x80 /* start at cursor column */
9045
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009046/*
9047 * Get flags for a search function.
9048 * Possibly sets "p_ws".
9049 * Returns BACKWARD, FORWARD or zero (for an error).
9050 */
9051 static int
9052get_search_arg(typval_T *varp, int *flagsp)
9053{
9054 int dir = FORWARD;
9055 char_u *flags;
9056 char_u nbuf[NUMBUFLEN];
9057 int mask;
9058
9059 if (varp->v_type != VAR_UNKNOWN)
9060 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009061 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009062 if (flags == NULL)
9063 return 0; /* type error; errmsg already given */
9064 while (*flags != NUL)
9065 {
9066 switch (*flags)
9067 {
9068 case 'b': dir = BACKWARD; break;
9069 case 'w': p_ws = TRUE; break;
9070 case 'W': p_ws = FALSE; break;
9071 default: mask = 0;
9072 if (flagsp != NULL)
9073 switch (*flags)
9074 {
9075 case 'c': mask = SP_START; break;
9076 case 'e': mask = SP_END; break;
9077 case 'm': mask = SP_RETCOUNT; break;
9078 case 'n': mask = SP_NOMOVE; break;
9079 case 'p': mask = SP_SUBPAT; break;
9080 case 'r': mask = SP_REPEAT; break;
9081 case 's': mask = SP_SETPCMARK; break;
9082 case 'z': mask = SP_COLUMN; break;
9083 }
9084 if (mask == 0)
9085 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009086 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009087 dir = 0;
9088 }
9089 else
9090 *flagsp |= mask;
9091 }
9092 if (dir == 0)
9093 break;
9094 ++flags;
9095 }
9096 }
9097 return dir;
9098}
9099
9100/*
9101 * Shared by search() and searchpos() functions.
9102 */
9103 static int
9104search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
9105{
9106 int flags;
9107 char_u *pat;
9108 pos_T pos;
9109 pos_T save_cursor;
9110 int save_p_ws = p_ws;
9111 int dir;
9112 int retval = 0; /* default: FAIL */
9113 long lnum_stop = 0;
9114 proftime_T tm;
9115#ifdef FEAT_RELTIME
9116 long time_limit = 0;
9117#endif
9118 int options = SEARCH_KEEP;
9119 int subpatnum;
9120
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009121 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009122 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
9123 if (dir == 0)
9124 goto theend;
9125 flags = *flagsp;
9126 if (flags & SP_START)
9127 options |= SEARCH_START;
9128 if (flags & SP_END)
9129 options |= SEARCH_END;
9130 if (flags & SP_COLUMN)
9131 options |= SEARCH_COL;
9132
9133 /* Optional arguments: line number to stop searching and timeout. */
9134 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
9135 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009136 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009137 if (lnum_stop < 0)
9138 goto theend;
9139#ifdef FEAT_RELTIME
9140 if (argvars[3].v_type != VAR_UNKNOWN)
9141 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009142 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009143 if (time_limit < 0)
9144 goto theend;
9145 }
9146#endif
9147 }
9148
9149#ifdef FEAT_RELTIME
9150 /* Set the time limit, if there is one. */
9151 profile_setlimit(time_limit, &tm);
9152#endif
9153
9154 /*
9155 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
9156 * Check to make sure only those flags are set.
9157 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
9158 * flags cannot be set. Check for that condition also.
9159 */
9160 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
9161 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9162 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009163 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009164 goto theend;
9165 }
9166
9167 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009168 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009169 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009170 if (subpatnum != FAIL)
9171 {
9172 if (flags & SP_SUBPAT)
9173 retval = subpatnum;
9174 else
9175 retval = pos.lnum;
9176 if (flags & SP_SETPCMARK)
9177 setpcmark();
9178 curwin->w_cursor = pos;
9179 if (match_pos != NULL)
9180 {
9181 /* Store the match cursor position */
9182 match_pos->lnum = pos.lnum;
9183 match_pos->col = pos.col + 1;
9184 }
9185 /* "/$" will put the cursor after the end of the line, may need to
9186 * correct that here */
9187 check_cursor();
9188 }
9189
9190 /* If 'n' flag is used: restore cursor position. */
9191 if (flags & SP_NOMOVE)
9192 curwin->w_cursor = save_cursor;
9193 else
9194 curwin->w_set_curswant = TRUE;
9195theend:
9196 p_ws = save_p_ws;
9197
9198 return retval;
9199}
9200
9201#ifdef FEAT_FLOAT
9202
9203/*
9204 * round() is not in C90, use ceil() or floor() instead.
9205 */
9206 float_T
9207vim_round(float_T f)
9208{
9209 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
9210}
9211
9212/*
9213 * "round({float})" function
9214 */
9215 static void
9216f_round(typval_T *argvars, typval_T *rettv)
9217{
9218 float_T f = 0.0;
9219
9220 rettv->v_type = VAR_FLOAT;
9221 if (get_float_arg(argvars, &f) == OK)
9222 rettv->vval.v_float = vim_round(f);
9223 else
9224 rettv->vval.v_float = 0.0;
9225}
9226#endif
9227
Bram Moolenaare99be0e2019-03-26 22:51:09 +01009228#ifdef FEAT_RUBY
9229/*
9230 * "rubyeval()" function
9231 */
9232 static void
9233f_rubyeval(typval_T *argvars, typval_T *rettv)
9234{
9235 char_u *str;
9236 char_u buf[NUMBUFLEN];
9237
9238 str = tv_get_string_buf(&argvars[0], buf);
9239 do_rubyeval(str, rettv);
9240}
9241#endif
9242
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009243/*
9244 * "screenattr()" function
9245 */
9246 static void
9247f_screenattr(typval_T *argvars, typval_T *rettv)
9248{
9249 int row;
9250 int col;
9251 int c;
9252
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009253 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9254 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009255 if (row < 0 || row >= screen_Rows
9256 || col < 0 || col >= screen_Columns)
9257 c = -1;
9258 else
9259 c = ScreenAttrs[LineOffset[row] + col];
9260 rettv->vval.v_number = c;
9261}
9262
9263/*
9264 * "screenchar()" function
9265 */
9266 static void
9267f_screenchar(typval_T *argvars, typval_T *rettv)
9268{
9269 int row;
9270 int col;
9271 int off;
9272 int c;
9273
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009274 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9275 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009276 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009277 c = -1;
9278 else
9279 {
9280 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009281 if (enc_utf8 && ScreenLinesUC[off] != 0)
9282 c = ScreenLinesUC[off];
9283 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009284 c = ScreenLines[off];
9285 }
9286 rettv->vval.v_number = c;
9287}
9288
9289/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009290 * "screenchars()" function
9291 */
9292 static void
9293f_screenchars(typval_T *argvars, typval_T *rettv)
9294{
9295 int row;
9296 int col;
9297 int off;
9298 int c;
9299 int i;
9300
9301 if (rettv_list_alloc(rettv) == FAIL)
9302 return;
9303 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9304 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9305 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9306 return;
9307
9308 off = LineOffset[row] + col;
9309 if (enc_utf8 && ScreenLinesUC[off] != 0)
9310 c = ScreenLinesUC[off];
9311 else
9312 c = ScreenLines[off];
9313 list_append_number(rettv->vval.v_list, (varnumber_T)c);
9314
9315 if (enc_utf8)
9316
9317 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9318 list_append_number(rettv->vval.v_list,
9319 (varnumber_T)ScreenLinesC[i][off]);
9320}
9321
9322/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009323 * "screencol()" function
9324 *
9325 * First column is 1 to be consistent with virtcol().
9326 */
9327 static void
9328f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
9329{
9330 rettv->vval.v_number = screen_screencol() + 1;
9331}
9332
9333/*
9334 * "screenrow()" function
9335 */
9336 static void
9337f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
9338{
9339 rettv->vval.v_number = screen_screenrow() + 1;
9340}
9341
9342/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +01009343 * "screenstring()" function
9344 */
9345 static void
9346f_screenstring(typval_T *argvars, typval_T *rettv)
9347{
9348 int row;
9349 int col;
9350 int off;
9351 int c;
9352 int i;
9353 char_u buf[MB_MAXBYTES + 1];
9354 int buflen = 0;
9355
9356 rettv->vval.v_string = NULL;
9357 rettv->v_type = VAR_STRING;
9358
9359 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
9360 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
9361 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
9362 return;
9363
9364 off = LineOffset[row] + col;
9365 if (enc_utf8 && ScreenLinesUC[off] != 0)
9366 c = ScreenLinesUC[off];
9367 else
9368 c = ScreenLines[off];
9369 buflen += mb_char2bytes(c, buf);
9370
9371 if (enc_utf8)
9372 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
9373 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
9374
9375 buf[buflen] = NUL;
9376 rettv->vval.v_string = vim_strsave(buf);
9377}
9378
9379/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009380 * "search()" function
9381 */
9382 static void
9383f_search(typval_T *argvars, typval_T *rettv)
9384{
9385 int flags = 0;
9386
9387 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
9388}
9389
9390/*
9391 * "searchdecl()" function
9392 */
9393 static void
9394f_searchdecl(typval_T *argvars, typval_T *rettv)
9395{
9396 int locally = 1;
9397 int thisblock = 0;
9398 int error = FALSE;
9399 char_u *name;
9400
9401 rettv->vval.v_number = 1; /* default: FAIL */
9402
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009403 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009404 if (argvars[1].v_type != VAR_UNKNOWN)
9405 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009406 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009407 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009408 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009409 }
9410 if (!error && name != NULL)
9411 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
9412 locally, thisblock, SEARCH_KEEP) == FAIL;
9413}
9414
9415/*
9416 * Used by searchpair() and searchpairpos()
9417 */
9418 static int
9419searchpair_cmn(typval_T *argvars, pos_T *match_pos)
9420{
9421 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +01009422 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009423 int save_p_ws = p_ws;
9424 int dir;
9425 int flags = 0;
9426 char_u nbuf1[NUMBUFLEN];
9427 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009428 int retval = 0; /* default: FAIL */
9429 long lnum_stop = 0;
9430 long time_limit = 0;
9431
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009432 /* Get the three pattern arguments: start, middle, end. Will result in an
9433 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009434 spat = tv_get_string_chk(&argvars[0]);
9435 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
9436 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009437 if (spat == NULL || mpat == NULL || epat == NULL)
9438 goto theend; /* type error */
9439
9440 /* Handle the optional fourth argument: flags */
9441 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
9442 if (dir == 0)
9443 goto theend;
9444
9445 /* Don't accept SP_END or SP_SUBPAT.
9446 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
9447 */
9448 if ((flags & (SP_END | SP_SUBPAT)) != 0
9449 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
9450 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009451 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009452 goto theend;
9453 }
9454
9455 /* Using 'r' implies 'W', otherwise it doesn't work. */
9456 if (flags & SP_REPEAT)
9457 p_ws = FALSE;
9458
9459 /* Optional fifth argument: skip expression */
9460 if (argvars[3].v_type == VAR_UNKNOWN
9461 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +01009462 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009463 else
9464 {
Bram Moolenaar48570482017-10-30 21:48:41 +01009465 skip = &argvars[4];
9466 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
9467 && skip->v_type != VAR_STRING)
9468 {
9469 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009470 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +01009471 goto theend;
9472 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009473 if (argvars[5].v_type != VAR_UNKNOWN)
9474 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009475 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009476 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009477 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009478 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009479 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009480 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009481#ifdef FEAT_RELTIME
9482 if (argvars[6].v_type != VAR_UNKNOWN)
9483 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009484 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009485 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009486 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009487 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009488 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +02009489 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009490 }
9491#endif
9492 }
9493 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009494
9495 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
9496 match_pos, lnum_stop, time_limit);
9497
9498theend:
9499 p_ws = save_p_ws;
9500
9501 return retval;
9502}
9503
9504/*
9505 * "searchpair()" function
9506 */
9507 static void
9508f_searchpair(typval_T *argvars, typval_T *rettv)
9509{
9510 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
9511}
9512
9513/*
9514 * "searchpairpos()" function
9515 */
9516 static void
9517f_searchpairpos(typval_T *argvars, typval_T *rettv)
9518{
9519 pos_T match_pos;
9520 int lnum = 0;
9521 int col = 0;
9522
9523 if (rettv_list_alloc(rettv) == FAIL)
9524 return;
9525
9526 if (searchpair_cmn(argvars, &match_pos) > 0)
9527 {
9528 lnum = match_pos.lnum;
9529 col = match_pos.col;
9530 }
9531
9532 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9533 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9534}
9535
9536/*
9537 * Search for a start/middle/end thing.
9538 * Used by searchpair(), see its documentation for the details.
9539 * Returns 0 or -1 for no match,
9540 */
9541 long
9542do_searchpair(
9543 char_u *spat, /* start pattern */
9544 char_u *mpat, /* middle pattern */
9545 char_u *epat, /* end pattern */
9546 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +01009547 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009548 int flags, /* SP_SETPCMARK and other SP_ values */
9549 pos_T *match_pos,
9550 linenr_T lnum_stop, /* stop at this line if not zero */
9551 long time_limit UNUSED) /* stop after this many msec */
9552{
9553 char_u *save_cpo;
9554 char_u *pat, *pat2 = NULL, *pat3 = NULL;
9555 long retval = 0;
9556 pos_T pos;
9557 pos_T firstpos;
9558 pos_T foundpos;
9559 pos_T save_cursor;
9560 pos_T save_pos;
9561 int n;
9562 int r;
9563 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +01009564 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009565 int err;
9566 int options = SEARCH_KEEP;
9567 proftime_T tm;
9568
9569 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
9570 save_cpo = p_cpo;
9571 p_cpo = empty_option;
9572
9573#ifdef FEAT_RELTIME
9574 /* Set the time limit, if there is one. */
9575 profile_setlimit(time_limit, &tm);
9576#endif
9577
9578 /* Make two search patterns: start/end (pat2, for in nested pairs) and
9579 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar964b3742019-05-24 18:54:09 +02009580 pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
9581 pat3 = alloc(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009582 if (pat2 == NULL || pat3 == NULL)
9583 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009584 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009585 if (*mpat == NUL)
9586 STRCPY(pat3, pat2);
9587 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +01009588 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009589 spat, epat, mpat);
9590 if (flags & SP_START)
9591 options |= SEARCH_START;
9592
Bram Moolenaar48570482017-10-30 21:48:41 +01009593 if (skip != NULL)
9594 {
9595 /* Empty string means to not use the skip expression. */
9596 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
9597 use_skip = skip->vval.v_string != NULL
9598 && *skip->vval.v_string != NUL;
9599 }
9600
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009601 save_cursor = curwin->w_cursor;
9602 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009603 CLEAR_POS(&firstpos);
9604 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009605 pat = pat3;
9606 for (;;)
9607 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +01009608 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +02009609 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009610 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009611 /* didn't find it or found the first match again: FAIL */
9612 break;
9613
9614 if (firstpos.lnum == 0)
9615 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01009616 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009617 {
9618 /* Found the same position again. Can happen with a pattern that
9619 * has "\zs" at the end and searching backwards. Advance one
9620 * character and try again. */
9621 if (dir == BACKWARD)
9622 decl(&pos);
9623 else
9624 incl(&pos);
9625 }
9626 foundpos = pos;
9627
9628 /* clear the start flag to avoid getting stuck here */
9629 options &= ~SEARCH_START;
9630
9631 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +01009632 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009633 {
9634 save_pos = curwin->w_cursor;
9635 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +01009636 err = FALSE;
9637 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009638 curwin->w_cursor = save_pos;
9639 if (err)
9640 {
9641 /* Evaluating {skip} caused an error, break here. */
9642 curwin->w_cursor = save_cursor;
9643 retval = -1;
9644 break;
9645 }
9646 if (r)
9647 continue;
9648 }
9649
9650 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
9651 {
9652 /* Found end when searching backwards or start when searching
9653 * forward: nested pair. */
9654 ++nest;
9655 pat = pat2; /* nested, don't search for middle */
9656 }
9657 else
9658 {
9659 /* Found end when searching forward or start when searching
9660 * backward: end of (nested) pair; or found middle in outer pair. */
9661 if (--nest == 1)
9662 pat = pat3; /* outer level, search for middle */
9663 }
9664
9665 if (nest == 0)
9666 {
9667 /* Found the match: return matchcount or line number. */
9668 if (flags & SP_RETCOUNT)
9669 ++retval;
9670 else
9671 retval = pos.lnum;
9672 if (flags & SP_SETPCMARK)
9673 setpcmark();
9674 curwin->w_cursor = pos;
9675 if (!(flags & SP_REPEAT))
9676 break;
9677 nest = 1; /* search for next unmatched */
9678 }
9679 }
9680
9681 if (match_pos != NULL)
9682 {
9683 /* Store the match cursor position */
9684 match_pos->lnum = curwin->w_cursor.lnum;
9685 match_pos->col = curwin->w_cursor.col + 1;
9686 }
9687
9688 /* If 'n' flag is used or search failed: restore cursor position. */
9689 if ((flags & SP_NOMOVE) || retval == 0)
9690 curwin->w_cursor = save_cursor;
9691
9692theend:
9693 vim_free(pat2);
9694 vim_free(pat3);
9695 if (p_cpo == empty_option)
9696 p_cpo = save_cpo;
9697 else
9698 /* Darn, evaluating the {skip} expression changed the value. */
9699 free_string_option(save_cpo);
9700
9701 return retval;
9702}
9703
9704/*
9705 * "searchpos()" function
9706 */
9707 static void
9708f_searchpos(typval_T *argvars, typval_T *rettv)
9709{
9710 pos_T match_pos;
9711 int lnum = 0;
9712 int col = 0;
9713 int n;
9714 int flags = 0;
9715
9716 if (rettv_list_alloc(rettv) == FAIL)
9717 return;
9718
9719 n = search_cmn(argvars, &match_pos, &flags);
9720 if (n > 0)
9721 {
9722 lnum = match_pos.lnum;
9723 col = match_pos.col;
9724 }
9725
9726 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
9727 list_append_number(rettv->vval.v_list, (varnumber_T)col);
9728 if (flags & SP_SUBPAT)
9729 list_append_number(rettv->vval.v_list, (varnumber_T)n);
9730}
9731
9732 static void
9733f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
9734{
9735#ifdef FEAT_CLIENTSERVER
9736 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009737 char_u *server = tv_get_string_chk(&argvars[0]);
9738 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009739
9740 rettv->vval.v_number = -1;
9741 if (server == NULL || reply == NULL)
9742 return;
9743 if (check_restricted() || check_secure())
9744 return;
9745# ifdef FEAT_X11
9746 if (check_connection() == FAIL)
9747 return;
9748# endif
9749
9750 if (serverSendReply(server, reply) < 0)
9751 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009752 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009753 return;
9754 }
9755 rettv->vval.v_number = 0;
9756#else
9757 rettv->vval.v_number = -1;
9758#endif
9759}
9760
9761 static void
9762f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
9763{
9764 char_u *r = NULL;
9765
9766#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009767# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009768 r = serverGetVimNames();
9769# else
9770 make_connection();
9771 if (X_DISPLAY != NULL)
9772 r = serverGetVimNames(X_DISPLAY);
9773# endif
9774#endif
9775 rettv->v_type = VAR_STRING;
9776 rettv->vval.v_string = r;
9777}
9778
9779/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009780 * "setbufline()" function
9781 */
9782 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02009783f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009784{
9785 linenr_T lnum;
9786 buf_T *buf;
9787
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009788 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009789 if (buf == NULL)
9790 rettv->vval.v_number = 1; /* FAIL */
9791 else
9792 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009793 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02009794 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +02009795 }
9796}
9797
9798/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009799 * "setbufvar()" function
9800 */
9801 static void
9802f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
9803{
9804 buf_T *buf;
9805 char_u *varname, *bufvarname;
9806 typval_T *varp;
9807 char_u nbuf[NUMBUFLEN];
9808
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009809 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009810 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009811 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
9812 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01009813 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009814 varp = &argvars[2];
9815
9816 if (buf != NULL && varname != NULL && varp != NULL)
9817 {
9818 if (*varname == '&')
9819 {
9820 long numval;
9821 char_u *strval;
9822 int error = FALSE;
9823 aco_save_T aco;
9824
9825 /* set curbuf to be our buf, temporarily */
9826 aucmd_prepbuf(&aco, buf);
9827
9828 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009829 numval = (long)tv_get_number_chk(varp, &error);
9830 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009831 if (!error && strval != NULL)
9832 set_option_value(varname, numval, strval, OPT_LOCAL);
9833
9834 /* reset notion of buffer */
9835 aucmd_restbuf(&aco);
9836 }
9837 else
9838 {
9839 buf_T *save_curbuf = curbuf;
9840
Bram Moolenaar964b3742019-05-24 18:54:09 +02009841 bufvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009842 if (bufvarname != NULL)
9843 {
9844 curbuf = buf;
9845 STRCPY(bufvarname, "b:");
9846 STRCPY(bufvarname + 2, varname);
9847 set_var(bufvarname, varp, TRUE);
9848 vim_free(bufvarname);
9849 curbuf = save_curbuf;
9850 }
9851 }
9852 }
9853}
9854
9855 static void
9856f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
9857{
9858 dict_T *d;
9859 dictitem_T *di;
9860 char_u *csearch;
9861
9862 if (argvars[0].v_type != VAR_DICT)
9863 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009864 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009865 return;
9866 }
9867
9868 if ((d = argvars[0].vval.v_dict) != NULL)
9869 {
Bram Moolenaar8f667172018-12-14 15:38:31 +01009870 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009871 if (csearch != NULL)
9872 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009873 if (enc_utf8)
9874 {
9875 int pcc[MAX_MCO];
9876 int c = utfc_ptr2char(csearch, pcc);
9877
9878 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
9879 }
9880 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009881 set_last_csearch(PTR2CHAR(csearch),
9882 csearch, MB_PTR2LEN(csearch));
9883 }
9884
9885 di = dict_find(d, (char_u *)"forward", -1);
9886 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009887 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009888 ? FORWARD : BACKWARD);
9889
9890 di = dict_find(d, (char_u *)"until", -1);
9891 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009892 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009893 }
9894}
9895
9896/*
9897 * "setcmdpos()" function
9898 */
9899 static void
9900f_setcmdpos(typval_T *argvars, typval_T *rettv)
9901{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009902 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009903
9904 if (pos >= 0)
9905 rettv->vval.v_number = set_cmdline_pos(pos);
9906}
9907
9908/*
Bram Moolenaar691ddee2019-05-09 14:52:41 +02009909 * "setenv()" function
9910 */
9911 static void
9912f_setenv(typval_T *argvars, typval_T *rettv UNUSED)
9913{
9914 char_u namebuf[NUMBUFLEN];
9915 char_u valbuf[NUMBUFLEN];
9916 char_u *name = tv_get_string_buf(&argvars[0], namebuf);
9917
9918 if (argvars[1].v_type == VAR_SPECIAL
9919 && argvars[1].vval.v_number == VVAL_NULL)
9920 vim_unsetenv(name);
9921 else
9922 vim_setenv(name, tv_get_string_buf(&argvars[1], valbuf));
9923}
9924
9925/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009926 * "setfperm({fname}, {mode})" function
9927 */
9928 static void
9929f_setfperm(typval_T *argvars, typval_T *rettv)
9930{
9931 char_u *fname;
9932 char_u modebuf[NUMBUFLEN];
9933 char_u *mode_str;
9934 int i;
9935 int mask;
9936 int mode = 0;
9937
9938 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009939 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009940 if (fname == NULL)
9941 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009942 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009943 if (mode_str == NULL)
9944 return;
9945 if (STRLEN(mode_str) != 9)
9946 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009947 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009948 return;
9949 }
9950
9951 mask = 1;
9952 for (i = 8; i >= 0; --i)
9953 {
9954 if (mode_str[i] != '-')
9955 mode |= mask;
9956 mask = mask << 1;
9957 }
9958 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
9959}
9960
9961/*
9962 * "setline()" function
9963 */
9964 static void
9965f_setline(typval_T *argvars, typval_T *rettv)
9966{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009967 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009968
Bram Moolenaarca851592018-06-06 21:04:07 +02009969 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009970}
9971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009972/*
9973 * Used by "setqflist()" and "setloclist()" functions
9974 */
9975 static void
9976set_qf_ll_list(
9977 win_T *wp UNUSED,
9978 typval_T *list_arg UNUSED,
9979 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +02009980 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009981 typval_T *rettv)
9982{
9983#ifdef FEAT_QUICKFIX
9984 static char *e_invact = N_("E927: Invalid action: '%s'");
9985 char_u *act;
9986 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009987 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009988#endif
9989
9990 rettv->vval.v_number = -1;
9991
9992#ifdef FEAT_QUICKFIX
9993 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009994 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +02009995 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009996 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009997 else
9998 {
9999 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010000 dict_T *d = NULL;
10001 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010002
10003 if (action_arg->v_type == VAR_STRING)
10004 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010005 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010006 if (act == NULL)
10007 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020010008 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
10009 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010010 action = *act;
10011 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010012 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010013 }
10014 else if (action_arg->v_type == VAR_UNKNOWN)
10015 action = ' ';
10016 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010017 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010018
Bram Moolenaard823fa92016-08-12 16:29:27 +020010019 if (action_arg->v_type != VAR_UNKNOWN
10020 && what_arg->v_type != VAR_UNKNOWN)
10021 {
10022 if (what_arg->v_type == VAR_DICT)
10023 d = what_arg->vval.v_dict;
10024 else
10025 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010026 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020010027 valid_dict = FALSE;
10028 }
10029 }
10030
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010031 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020010032 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010033 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
10034 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010035 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020010036 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010037 }
10038#endif
10039}
10040
10041/*
10042 * "setloclist()" function
10043 */
10044 static void
10045f_setloclist(typval_T *argvars, typval_T *rettv)
10046{
10047 win_T *win;
10048
10049 rettv->vval.v_number = -1;
10050
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020010051 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010052 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020010053 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010054}
10055
10056/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010057 * "setpos()" function
10058 */
10059 static void
10060f_setpos(typval_T *argvars, typval_T *rettv)
10061{
10062 pos_T pos;
10063 int fnum;
10064 char_u *name;
10065 colnr_T curswant = -1;
10066
10067 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010068 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010069 if (name != NULL)
10070 {
10071 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
10072 {
10073 if (--pos.col < 0)
10074 pos.col = 0;
10075 if (name[0] == '.' && name[1] == NUL)
10076 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010077 /* set cursor; "fnum" is ignored */
10078 curwin->w_cursor = pos;
10079 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010080 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010081 curwin->w_curswant = curswant - 1;
10082 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010083 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010010084 check_cursor();
10085 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010086 }
10087 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
10088 {
10089 /* set mark */
10090 if (setmark_pos(name[1], &pos, fnum) == OK)
10091 rettv->vval.v_number = 0;
10092 }
10093 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010094 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010095 }
10096 }
10097}
10098
10099/*
10100 * "setqflist()" function
10101 */
10102 static void
10103f_setqflist(typval_T *argvars, typval_T *rettv)
10104{
Bram Moolenaard823fa92016-08-12 16:29:27 +020010105 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010106}
10107
10108/*
10109 * "setreg()" function
10110 */
10111 static void
10112f_setreg(typval_T *argvars, typval_T *rettv)
10113{
10114 int regname;
10115 char_u *strregname;
10116 char_u *stropt;
10117 char_u *strval;
10118 int append;
10119 char_u yank_type;
10120 long block_len;
10121
10122 block_len = -1;
10123 yank_type = MAUTO;
10124 append = FALSE;
10125
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010126 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010127 rettv->vval.v_number = 1; /* FAIL is default */
10128
10129 if (strregname == NULL)
10130 return; /* type error; errmsg already given */
10131 regname = *strregname;
10132 if (regname == 0 || regname == '@')
10133 regname = '"';
10134
10135 if (argvars[2].v_type != VAR_UNKNOWN)
10136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010137 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010138 if (stropt == NULL)
10139 return; /* type error */
10140 for (; *stropt != NUL; ++stropt)
10141 switch (*stropt)
10142 {
10143 case 'a': case 'A': /* append */
10144 append = TRUE;
10145 break;
10146 case 'v': case 'c': /* character-wise selection */
10147 yank_type = MCHAR;
10148 break;
10149 case 'V': case 'l': /* line-wise selection */
10150 yank_type = MLINE;
10151 break;
10152 case 'b': case Ctrl_V: /* block-wise selection */
10153 yank_type = MBLOCK;
10154 if (VIM_ISDIGIT(stropt[1]))
10155 {
10156 ++stropt;
10157 block_len = getdigits(&stropt) - 1;
10158 --stropt;
10159 }
10160 break;
10161 }
10162 }
10163
10164 if (argvars[1].v_type == VAR_LIST)
10165 {
10166 char_u **lstval;
10167 char_u **allocval;
10168 char_u buf[NUMBUFLEN];
10169 char_u **curval;
10170 char_u **curallocval;
10171 list_T *ll = argvars[1].vval.v_list;
10172 listitem_T *li;
10173 int len;
10174
10175 /* If the list is NULL handle like an empty list. */
10176 len = ll == NULL ? 0 : ll->lv_len;
10177
10178 /* First half: use for pointers to result lines; second half: use for
10179 * pointers to allocated copies. */
Bram Moolenaarc799fe22019-05-28 23:08:19 +020010180 lstval = ALLOC_MULT(char_u *, (len + 1) * 2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010181 if (lstval == NULL)
10182 return;
10183 curval = lstval;
10184 allocval = lstval + len + 2;
10185 curallocval = allocval;
10186
10187 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
10188 li = li->li_next)
10189 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010190 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010191 if (strval == NULL)
10192 goto free_lstval;
10193 if (strval == buf)
10194 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010195 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010196 * overwrite the string. */
10197 strval = vim_strsave(buf);
10198 if (strval == NULL)
10199 goto free_lstval;
10200 *curallocval++ = strval;
10201 }
10202 *curval++ = strval;
10203 }
10204 *curval++ = NULL;
10205
10206 write_reg_contents_lst(regname, lstval, -1,
10207 append, yank_type, block_len);
10208free_lstval:
10209 while (curallocval > allocval)
10210 vim_free(*--curallocval);
10211 vim_free(lstval);
10212 }
10213 else
10214 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010215 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010216 if (strval == NULL)
10217 return;
10218 write_reg_contents_ex(regname, strval, -1,
10219 append, yank_type, block_len);
10220 }
10221 rettv->vval.v_number = 0;
10222}
10223
10224/*
10225 * "settabvar()" function
10226 */
10227 static void
10228f_settabvar(typval_T *argvars, typval_T *rettv)
10229{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010230 tabpage_T *save_curtab;
10231 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010232 char_u *varname, *tabvarname;
10233 typval_T *varp;
10234
10235 rettv->vval.v_number = 0;
10236
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010237 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010238 return;
10239
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010240 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
10241 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010242 varp = &argvars[2];
10243
Bram Moolenaar4033c552017-09-16 20:54:51 +020010244 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010245 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010246 save_curtab = curtab;
10247 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010248
Bram Moolenaar964b3742019-05-24 18:54:09 +020010249 tabvarname = alloc(STRLEN(varname) + 3);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010250 if (tabvarname != NULL)
10251 {
10252 STRCPY(tabvarname, "t:");
10253 STRCPY(tabvarname + 2, varname);
10254 set_var(tabvarname, varp, TRUE);
10255 vim_free(tabvarname);
10256 }
10257
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010258 /* Restore current tabpage */
10259 if (valid_tabpage(save_curtab))
10260 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010261 }
10262}
10263
10264/*
10265 * "settabwinvar()" function
10266 */
10267 static void
10268f_settabwinvar(typval_T *argvars, typval_T *rettv)
10269{
10270 setwinvar(argvars, rettv, 1);
10271}
10272
10273/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010274 * "settagstack()" function
10275 */
10276 static void
10277f_settagstack(typval_T *argvars, typval_T *rettv)
10278{
10279 static char *e_invact2 = N_("E962: Invalid action: '%s'");
10280 win_T *wp;
10281 dict_T *d;
10282 int action = 'r';
10283
10284 rettv->vval.v_number = -1;
10285
10286 // first argument: window number or id
10287 wp = find_win_by_nr_or_id(&argvars[0]);
10288 if (wp == NULL)
10289 return;
10290
10291 // second argument: dict with items to set in the tag stack
10292 if (argvars[1].v_type != VAR_DICT)
10293 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010294 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010295 return;
10296 }
10297 d = argvars[1].vval.v_dict;
10298 if (d == NULL)
10299 return;
10300
10301 // third argument: action - 'a' for append and 'r' for replace.
10302 // default is to replace the stack.
10303 if (argvars[2].v_type == VAR_UNKNOWN)
10304 action = 'r';
10305 else if (argvars[2].v_type == VAR_STRING)
10306 {
10307 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010308 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010309 if (actstr == NULL)
10310 return;
10311 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
10312 action = *actstr;
10313 else
10314 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010315 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010316 return;
10317 }
10318 }
10319 else
10320 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010321 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010010322 return;
10323 }
10324
10325 if (set_tagstack(wp, d, action) == OK)
10326 rettv->vval.v_number = 0;
10327}
10328
10329/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010330 * "setwinvar()" function
10331 */
10332 static void
10333f_setwinvar(typval_T *argvars, typval_T *rettv)
10334{
10335 setwinvar(argvars, rettv, 0);
10336}
10337
10338#ifdef FEAT_CRYPT
10339/*
10340 * "sha256({string})" function
10341 */
10342 static void
10343f_sha256(typval_T *argvars, typval_T *rettv)
10344{
10345 char_u *p;
10346
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010347 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010348 rettv->vval.v_string = vim_strsave(
10349 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
10350 rettv->v_type = VAR_STRING;
10351}
10352#endif /* FEAT_CRYPT */
10353
10354/*
10355 * "shellescape({string})" function
10356 */
10357 static void
10358f_shellescape(typval_T *argvars, typval_T *rettv)
10359{
Bram Moolenaar20615522017-06-05 18:46:26 +020010360 int do_special = non_zero_arg(&argvars[1]);
10361
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010362 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010363 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010364 rettv->v_type = VAR_STRING;
10365}
10366
10367/*
10368 * shiftwidth() function
10369 */
10370 static void
10371f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
10372{
Bram Moolenaarf9514162018-11-22 03:08:29 +010010373 rettv->vval.v_number = 0;
10374
10375 if (argvars[0].v_type != VAR_UNKNOWN)
10376 {
10377 long col;
10378
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010379 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010010380 if (col < 0)
10381 return; // type error; errmsg already given
10382#ifdef FEAT_VARTABS
10383 rettv->vval.v_number = get_sw_value_col(curbuf, col);
10384 return;
10385#endif
10386 }
10387
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010388 rettv->vval.v_number = get_sw_value(curbuf);
10389}
10390
10391/*
10392 * "simplify()" function
10393 */
10394 static void
10395f_simplify(typval_T *argvars, typval_T *rettv)
10396{
10397 char_u *p;
10398
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010399 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010400 rettv->vval.v_string = vim_strsave(p);
10401 simplify_filename(rettv->vval.v_string); /* simplify in place */
10402 rettv->v_type = VAR_STRING;
10403}
10404
10405#ifdef FEAT_FLOAT
10406/*
10407 * "sin()" function
10408 */
10409 static void
10410f_sin(typval_T *argvars, typval_T *rettv)
10411{
10412 float_T f = 0.0;
10413
10414 rettv->v_type = VAR_FLOAT;
10415 if (get_float_arg(argvars, &f) == OK)
10416 rettv->vval.v_float = sin(f);
10417 else
10418 rettv->vval.v_float = 0.0;
10419}
10420
10421/*
10422 * "sinh()" function
10423 */
10424 static void
10425f_sinh(typval_T *argvars, typval_T *rettv)
10426{
10427 float_T f = 0.0;
10428
10429 rettv->v_type = VAR_FLOAT;
10430 if (get_float_arg(argvars, &f) == OK)
10431 rettv->vval.v_float = sinh(f);
10432 else
10433 rettv->vval.v_float = 0.0;
10434}
10435#endif
10436
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010437/*
10438 * "soundfold({word})" function
10439 */
10440 static void
10441f_soundfold(typval_T *argvars, typval_T *rettv)
10442{
10443 char_u *s;
10444
10445 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010446 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010447#ifdef FEAT_SPELL
10448 rettv->vval.v_string = eval_soundfold(s);
10449#else
10450 rettv->vval.v_string = vim_strsave(s);
10451#endif
10452}
10453
10454/*
10455 * "spellbadword()" function
10456 */
10457 static void
10458f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
10459{
10460 char_u *word = (char_u *)"";
10461 hlf_T attr = HLF_COUNT;
10462 int len = 0;
10463
10464 if (rettv_list_alloc(rettv) == FAIL)
10465 return;
10466
10467#ifdef FEAT_SPELL
10468 if (argvars[0].v_type == VAR_UNKNOWN)
10469 {
10470 /* Find the start and length of the badly spelled word. */
10471 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
10472 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010473 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010474 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010010475 curwin->w_set_curswant = TRUE;
10476 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010477 }
10478 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
10479 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010480 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010481 int capcol = -1;
10482
10483 if (str != NULL)
10484 {
10485 /* Check the argument for spelling. */
10486 while (*str != NUL)
10487 {
10488 len = spell_check(curwin, str, &attr, &capcol, FALSE);
10489 if (attr != HLF_COUNT)
10490 {
10491 word = str;
10492 break;
10493 }
10494 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020010495 capcol -= len;
Bram Moolenaar0c779e82019-08-09 17:01:02 +020010496 len = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010497 }
10498 }
10499 }
10500#endif
10501
10502 list_append_string(rettv->vval.v_list, word, len);
10503 list_append_string(rettv->vval.v_list, (char_u *)(
10504 attr == HLF_SPB ? "bad" :
10505 attr == HLF_SPR ? "rare" :
10506 attr == HLF_SPL ? "local" :
10507 attr == HLF_SPC ? "caps" :
10508 ""), -1);
10509}
10510
10511/*
10512 * "spellsuggest()" function
10513 */
10514 static void
10515f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
10516{
10517#ifdef FEAT_SPELL
10518 char_u *str;
10519 int typeerr = FALSE;
10520 int maxcount;
10521 garray_T ga;
10522 int i;
10523 listitem_T *li;
10524 int need_capital = FALSE;
10525#endif
10526
10527 if (rettv_list_alloc(rettv) == FAIL)
10528 return;
10529
10530#ifdef FEAT_SPELL
10531 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
10532 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010533 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010534 if (argvars[1].v_type != VAR_UNKNOWN)
10535 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010536 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010537 if (maxcount <= 0)
10538 return;
10539 if (argvars[2].v_type != VAR_UNKNOWN)
10540 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010541 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010542 if (typeerr)
10543 return;
10544 }
10545 }
10546 else
10547 maxcount = 25;
10548
10549 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
10550
10551 for (i = 0; i < ga.ga_len; ++i)
10552 {
10553 str = ((char_u **)ga.ga_data)[i];
10554
10555 li = listitem_alloc();
10556 if (li == NULL)
10557 vim_free(str);
10558 else
10559 {
10560 li->li_tv.v_type = VAR_STRING;
10561 li->li_tv.v_lock = 0;
10562 li->li_tv.vval.v_string = str;
10563 list_append(rettv->vval.v_list, li);
10564 }
10565 }
10566 ga_clear(&ga);
10567 }
10568#endif
10569}
10570
10571 static void
10572f_split(typval_T *argvars, typval_T *rettv)
10573{
10574 char_u *str;
10575 char_u *end;
10576 char_u *pat = NULL;
10577 regmatch_T regmatch;
10578 char_u patbuf[NUMBUFLEN];
10579 char_u *save_cpo;
10580 int match;
10581 colnr_T col = 0;
10582 int keepempty = FALSE;
10583 int typeerr = FALSE;
10584
10585 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10586 save_cpo = p_cpo;
10587 p_cpo = (char_u *)"";
10588
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010589 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010590 if (argvars[1].v_type != VAR_UNKNOWN)
10591 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010592 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010593 if (pat == NULL)
10594 typeerr = TRUE;
10595 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010596 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010597 }
10598 if (pat == NULL || *pat == NUL)
10599 pat = (char_u *)"[\\x01- ]\\+";
10600
10601 if (rettv_list_alloc(rettv) == FAIL)
10602 return;
10603 if (typeerr)
10604 return;
10605
10606 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
10607 if (regmatch.regprog != NULL)
10608 {
10609 regmatch.rm_ic = FALSE;
10610 while (*str != NUL || keepempty)
10611 {
10612 if (*str == NUL)
10613 match = FALSE; /* empty item at the end */
10614 else
10615 match = vim_regexec_nl(&regmatch, str, col);
10616 if (match)
10617 end = regmatch.startp[0];
10618 else
10619 end = str + STRLEN(str);
10620 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
10621 && *str != NUL && match && end < regmatch.endp[0]))
10622 {
10623 if (list_append_string(rettv->vval.v_list, str,
10624 (int)(end - str)) == FAIL)
10625 break;
10626 }
10627 if (!match)
10628 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010010629 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010630 if (regmatch.endp[0] > str)
10631 col = 0;
10632 else
Bram Moolenaar13505972019-01-24 15:04:48 +010010633 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010634 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010635 str = regmatch.endp[0];
10636 }
10637
10638 vim_regfree(regmatch.regprog);
10639 }
10640
10641 p_cpo = save_cpo;
10642}
10643
10644#ifdef FEAT_FLOAT
10645/*
10646 * "sqrt()" function
10647 */
10648 static void
10649f_sqrt(typval_T *argvars, typval_T *rettv)
10650{
10651 float_T f = 0.0;
10652
10653 rettv->v_type = VAR_FLOAT;
10654 if (get_float_arg(argvars, &f) == OK)
10655 rettv->vval.v_float = sqrt(f);
10656 else
10657 rettv->vval.v_float = 0.0;
10658}
10659
10660/*
10661 * "str2float()" function
10662 */
10663 static void
10664f_str2float(typval_T *argvars, typval_T *rettv)
10665{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010666 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010667 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010668
Bram Moolenaar08243d22017-01-10 16:12:29 +010010669 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010670 p = skipwhite(p + 1);
10671 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010010672 if (isneg)
10673 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010674 rettv->v_type = VAR_FLOAT;
10675}
10676#endif
10677
10678/*
Bram Moolenaar9d401282019-04-06 13:18:12 +020010679 * "str2list()" function
10680 */
10681 static void
10682f_str2list(typval_T *argvars, typval_T *rettv)
10683{
10684 char_u *p;
10685 int utf8 = FALSE;
10686
10687 if (rettv_list_alloc(rettv) == FAIL)
10688 return;
10689
10690 if (argvars[1].v_type != VAR_UNKNOWN)
10691 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
10692
10693 p = tv_get_string(&argvars[0]);
10694
10695 if (has_mbyte || utf8)
10696 {
10697 int (*ptr2len)(char_u *);
10698 int (*ptr2char)(char_u *);
10699
10700 if (utf8 || enc_utf8)
10701 {
10702 ptr2len = utf_ptr2len;
10703 ptr2char = utf_ptr2char;
10704 }
10705 else
10706 {
10707 ptr2len = mb_ptr2len;
10708 ptr2char = mb_ptr2char;
10709 }
10710
10711 for ( ; *p != NUL; p += (*ptr2len)(p))
10712 list_append_number(rettv->vval.v_list, (*ptr2char)(p));
10713 }
10714 else
10715 for ( ; *p != NUL; ++p)
10716 list_append_number(rettv->vval.v_list, *p);
10717}
10718
10719/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010720 * "str2nr()" function
10721 */
10722 static void
10723f_str2nr(typval_T *argvars, typval_T *rettv)
10724{
10725 int base = 10;
10726 char_u *p;
10727 varnumber_T n;
10728 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010010729 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010730
10731 if (argvars[1].v_type != VAR_UNKNOWN)
10732 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010733 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010734 if (base != 2 && base != 8 && base != 10 && base != 16)
10735 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010736 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010737 return;
10738 }
10739 }
10740
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010741 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010010742 isneg = (*p == '-');
10743 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010744 p = skipwhite(p + 1);
10745 switch (base)
10746 {
10747 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
10748 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
10749 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
10750 default: what = 0;
10751 }
Bram Moolenaar16e9b852019-05-19 19:59:35 +020010752 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0, FALSE);
10753 // Text after the number is silently ignored.
Bram Moolenaar08243d22017-01-10 16:12:29 +010010754 if (isneg)
10755 rettv->vval.v_number = -n;
10756 else
10757 rettv->vval.v_number = n;
10758
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010759}
10760
10761#ifdef HAVE_STRFTIME
10762/*
10763 * "strftime({format}[, {time}])" function
10764 */
10765 static void
10766f_strftime(typval_T *argvars, typval_T *rettv)
10767{
10768 char_u result_buf[256];
Bram Moolenaar63d25552019-05-10 21:28:38 +020010769 struct tm tmval;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010770 struct tm *curtime;
10771 time_t seconds;
10772 char_u *p;
10773
10774 rettv->v_type = VAR_STRING;
10775
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010776 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010777 if (argvars[1].v_type == VAR_UNKNOWN)
10778 seconds = time(NULL);
10779 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010780 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaardb517302019-06-18 22:53:24 +020010781 curtime = vim_localtime(&seconds, &tmval);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782 /* MSVC returns NULL for an invalid value of seconds. */
10783 if (curtime == NULL)
10784 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
10785 else
10786 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010787 vimconv_T conv;
10788 char_u *enc;
10789
10790 conv.vc_type = CONV_NONE;
10791 enc = enc_locale();
10792 convert_setup(&conv, p_enc, enc);
10793 if (conv.vc_type != CONV_NONE)
10794 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010795 if (p != NULL)
10796 (void)strftime((char *)result_buf, sizeof(result_buf),
10797 (char *)p, curtime);
10798 else
10799 result_buf[0] = NUL;
10800
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010801 if (conv.vc_type != CONV_NONE)
10802 vim_free(p);
10803 convert_setup(&conv, enc, p_enc);
10804 if (conv.vc_type != CONV_NONE)
10805 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
10806 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010807 rettv->vval.v_string = vim_strsave(result_buf);
10808
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010809 /* Release conversion descriptors */
10810 convert_setup(&conv, NULL, NULL);
10811 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010812 }
10813}
10814#endif
10815
10816/*
10817 * "strgetchar()" function
10818 */
10819 static void
10820f_strgetchar(typval_T *argvars, typval_T *rettv)
10821{
10822 char_u *str;
10823 int len;
10824 int error = FALSE;
10825 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010010826 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010827
10828 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010829 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010830 if (str == NULL)
10831 return;
10832 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010833 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010834 if (error)
10835 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010836
Bram Moolenaar13505972019-01-24 15:04:48 +010010837 while (charidx >= 0 && byteidx < len)
10838 {
10839 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010840 {
Bram Moolenaar13505972019-01-24 15:04:48 +010010841 rettv->vval.v_number = mb_ptr2char(str + byteidx);
10842 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010843 }
Bram Moolenaar13505972019-01-24 15:04:48 +010010844 --charidx;
10845 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010846 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010847}
10848
10849/*
10850 * "stridx()" function
10851 */
10852 static void
10853f_stridx(typval_T *argvars, typval_T *rettv)
10854{
10855 char_u buf[NUMBUFLEN];
10856 char_u *needle;
10857 char_u *haystack;
10858 char_u *save_haystack;
10859 char_u *pos;
10860 int start_idx;
10861
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010862 needle = tv_get_string_chk(&argvars[1]);
10863 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010864 rettv->vval.v_number = -1;
10865 if (needle == NULL || haystack == NULL)
10866 return; /* type error; errmsg already given */
10867
10868 if (argvars[2].v_type != VAR_UNKNOWN)
10869 {
10870 int error = FALSE;
10871
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010872 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010873 if (error || start_idx >= (int)STRLEN(haystack))
10874 return;
10875 if (start_idx >= 0)
10876 haystack += start_idx;
10877 }
10878
10879 pos = (char_u *)strstr((char *)haystack, (char *)needle);
10880 if (pos != NULL)
10881 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
10882}
10883
10884/*
10885 * "string()" function
10886 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010010887 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010888f_string(typval_T *argvars, typval_T *rettv)
10889{
10890 char_u *tofree;
10891 char_u numbuf[NUMBUFLEN];
10892
10893 rettv->v_type = VAR_STRING;
10894 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
10895 get_copyID());
10896 /* Make a copy if we have a value but it's not in allocated memory. */
10897 if (rettv->vval.v_string != NULL && tofree == NULL)
10898 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
10899}
10900
10901/*
10902 * "strlen()" function
10903 */
10904 static void
10905f_strlen(typval_T *argvars, typval_T *rettv)
10906{
10907 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010908 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010909}
10910
10911/*
10912 * "strchars()" function
10913 */
10914 static void
10915f_strchars(typval_T *argvars, typval_T *rettv)
10916{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010917 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010918 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010919 varnumber_T len = 0;
10920 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010921
10922 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010923 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010924 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010925 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010926 else
10927 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010928 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
10929 while (*s != NUL)
10930 {
10931 func_mb_ptr2char_adv(&s);
10932 ++len;
10933 }
10934 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010935 }
10936}
10937
10938/*
10939 * "strdisplaywidth()" function
10940 */
10941 static void
10942f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
10943{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010944 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010945 int col = 0;
10946
10947 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010948 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010949
10950 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
10951}
10952
10953/*
10954 * "strwidth()" function
10955 */
10956 static void
10957f_strwidth(typval_T *argvars, typval_T *rettv)
10958{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010959 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010960
Bram Moolenaar13505972019-01-24 15:04:48 +010010961 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010962}
10963
10964/*
10965 * "strcharpart()" function
10966 */
10967 static void
10968f_strcharpart(typval_T *argvars, typval_T *rettv)
10969{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010970 char_u *p;
10971 int nchar;
10972 int nbyte = 0;
10973 int charlen;
10974 int len = 0;
10975 int slen;
10976 int error = FALSE;
10977
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010978 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010979 slen = (int)STRLEN(p);
10980
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010981 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010982 if (!error)
10983 {
10984 if (nchar > 0)
10985 while (nchar > 0 && nbyte < slen)
10986 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020010987 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010988 --nchar;
10989 }
10990 else
10991 nbyte = nchar;
10992 if (argvars[2].v_type != VAR_UNKNOWN)
10993 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010994 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010995 while (charlen > 0 && nbyte + len < slen)
10996 {
10997 int off = nbyte + len;
10998
10999 if (off < 0)
11000 len += 1;
11001 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020011002 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011003 --charlen;
11004 }
11005 }
11006 else
11007 len = slen - nbyte; /* default: all bytes that are available. */
11008 }
11009
11010 /*
11011 * Only return the overlap between the specified part and the actual
11012 * string.
11013 */
11014 if (nbyte < 0)
11015 {
11016 len += nbyte;
11017 nbyte = 0;
11018 }
11019 else if (nbyte > slen)
11020 nbyte = slen;
11021 if (len < 0)
11022 len = 0;
11023 else if (nbyte + len > slen)
11024 len = slen - nbyte;
11025
11026 rettv->v_type = VAR_STRING;
11027 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011028}
11029
11030/*
11031 * "strpart()" function
11032 */
11033 static void
11034f_strpart(typval_T *argvars, typval_T *rettv)
11035{
11036 char_u *p;
11037 int n;
11038 int len;
11039 int slen;
11040 int error = FALSE;
11041
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011042 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011043 slen = (int)STRLEN(p);
11044
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011045 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011046 if (error)
11047 len = 0;
11048 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011049 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011050 else
11051 len = slen - n; /* default len: all bytes that are available. */
11052
11053 /*
11054 * Only return the overlap between the specified part and the actual
11055 * string.
11056 */
11057 if (n < 0)
11058 {
11059 len += n;
11060 n = 0;
11061 }
11062 else if (n > slen)
11063 n = slen;
11064 if (len < 0)
11065 len = 0;
11066 else if (n + len > slen)
11067 len = slen - n;
11068
11069 rettv->v_type = VAR_STRING;
11070 rettv->vval.v_string = vim_strnsave(p + n, len);
11071}
11072
11073/*
11074 * "strridx()" function
11075 */
11076 static void
11077f_strridx(typval_T *argvars, typval_T *rettv)
11078{
11079 char_u buf[NUMBUFLEN];
11080 char_u *needle;
11081 char_u *haystack;
11082 char_u *rest;
11083 char_u *lastmatch = NULL;
11084 int haystack_len, end_idx;
11085
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011086 needle = tv_get_string_chk(&argvars[1]);
11087 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011088
11089 rettv->vval.v_number = -1;
11090 if (needle == NULL || haystack == NULL)
11091 return; /* type error; errmsg already given */
11092
11093 haystack_len = (int)STRLEN(haystack);
11094 if (argvars[2].v_type != VAR_UNKNOWN)
11095 {
11096 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011097 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011098 if (end_idx < 0)
11099 return; /* can never find a match */
11100 }
11101 else
11102 end_idx = haystack_len;
11103
11104 if (*needle == NUL)
11105 {
11106 /* Empty string matches past the end. */
11107 lastmatch = haystack + end_idx;
11108 }
11109 else
11110 {
11111 for (rest = haystack; *rest != '\0'; ++rest)
11112 {
11113 rest = (char_u *)strstr((char *)rest, (char *)needle);
11114 if (rest == NULL || rest > haystack + end_idx)
11115 break;
11116 lastmatch = rest;
11117 }
11118 }
11119
11120 if (lastmatch == NULL)
11121 rettv->vval.v_number = -1;
11122 else
11123 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
11124}
11125
11126/*
11127 * "strtrans()" function
11128 */
11129 static void
11130f_strtrans(typval_T *argvars, typval_T *rettv)
11131{
11132 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011133 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011134}
11135
11136/*
11137 * "submatch()" function
11138 */
11139 static void
11140f_submatch(typval_T *argvars, typval_T *rettv)
11141{
11142 int error = FALSE;
11143 int no;
11144 int retList = 0;
11145
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011146 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011147 if (error)
11148 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011149 if (no < 0 || no >= NSUBEXP)
11150 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011151 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010011152 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020011153 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011154 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011155 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011156 if (error)
11157 return;
11158
11159 if (retList == 0)
11160 {
11161 rettv->v_type = VAR_STRING;
11162 rettv->vval.v_string = reg_submatch(no);
11163 }
11164 else
11165 {
11166 rettv->v_type = VAR_LIST;
11167 rettv->vval.v_list = reg_submatch_list(no);
11168 }
11169}
11170
11171/*
11172 * "substitute()" function
11173 */
11174 static void
11175f_substitute(typval_T *argvars, typval_T *rettv)
11176{
11177 char_u patbuf[NUMBUFLEN];
11178 char_u subbuf[NUMBUFLEN];
11179 char_u flagsbuf[NUMBUFLEN];
11180
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011181 char_u *str = tv_get_string_chk(&argvars[0]);
11182 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011183 char_u *sub = NULL;
11184 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011185 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011186
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011187 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
11188 expr = &argvars[2];
11189 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011190 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011191
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011192 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011193 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
11194 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011195 rettv->vval.v_string = NULL;
11196 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020011197 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011198}
11199
11200/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011201 * "swapinfo(swap_filename)" function
11202 */
11203 static void
11204f_swapinfo(typval_T *argvars, typval_T *rettv)
11205{
11206 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011207 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020011208}
11209
11210/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020011211 * "swapname(expr)" function
11212 */
11213 static void
11214f_swapname(typval_T *argvars, typval_T *rettv)
11215{
11216 buf_T *buf;
11217
11218 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011219 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020011220 if (buf == NULL || buf->b_ml.ml_mfp == NULL
11221 || buf->b_ml.ml_mfp->mf_fname == NULL)
11222 rettv->vval.v_string = NULL;
11223 else
11224 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
11225}
11226
11227/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011228 * "synID(lnum, col, trans)" function
11229 */
11230 static void
11231f_synID(typval_T *argvars UNUSED, typval_T *rettv)
11232{
11233 int id = 0;
11234#ifdef FEAT_SYN_HL
11235 linenr_T lnum;
11236 colnr_T col;
11237 int trans;
11238 int transerr = FALSE;
11239
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011240 lnum = tv_get_lnum(argvars); /* -1 on type error */
11241 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
11242 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011243
11244 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11245 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
11246 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
11247#endif
11248
11249 rettv->vval.v_number = id;
11250}
11251
11252/*
11253 * "synIDattr(id, what [, mode])" function
11254 */
11255 static void
11256f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
11257{
11258 char_u *p = NULL;
11259#ifdef FEAT_SYN_HL
11260 int id;
11261 char_u *what;
11262 char_u *mode;
11263 char_u modebuf[NUMBUFLEN];
11264 int modec;
11265
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011266 id = (int)tv_get_number(&argvars[0]);
11267 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011268 if (argvars[2].v_type != VAR_UNKNOWN)
11269 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011270 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011271 modec = TOLOWER_ASC(mode[0]);
11272 if (modec != 't' && modec != 'c' && modec != 'g')
11273 modec = 0; /* replace invalid with current */
11274 }
11275 else
11276 {
11277#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
11278 if (USE_24BIT)
11279 modec = 'g';
11280 else
11281#endif
11282 if (t_colors > 1)
11283 modec = 'c';
11284 else
11285 modec = 't';
11286 }
11287
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011288 switch (TOLOWER_ASC(what[0]))
11289 {
11290 case 'b':
11291 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
11292 p = highlight_color(id, what, modec);
11293 else /* bold */
11294 p = highlight_has_attr(id, HL_BOLD, modec);
11295 break;
11296
11297 case 'f': /* fg[#] or font */
11298 p = highlight_color(id, what, modec);
11299 break;
11300
11301 case 'i':
11302 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
11303 p = highlight_has_attr(id, HL_INVERSE, modec);
11304 else /* italic */
11305 p = highlight_has_attr(id, HL_ITALIC, modec);
11306 break;
11307
11308 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020011309 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011310 break;
11311
11312 case 'r': /* reverse */
11313 p = highlight_has_attr(id, HL_INVERSE, modec);
11314 break;
11315
11316 case 's':
11317 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
11318 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020011319 /* strikeout */
11320 else if (TOLOWER_ASC(what[1]) == 't' &&
11321 TOLOWER_ASC(what[2]) == 'r')
11322 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011323 else /* standout */
11324 p = highlight_has_attr(id, HL_STANDOUT, modec);
11325 break;
11326
11327 case 'u':
11328 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
11329 /* underline */
11330 p = highlight_has_attr(id, HL_UNDERLINE, modec);
11331 else
11332 /* undercurl */
11333 p = highlight_has_attr(id, HL_UNDERCURL, modec);
11334 break;
11335 }
11336
11337 if (p != NULL)
11338 p = vim_strsave(p);
11339#endif
11340 rettv->v_type = VAR_STRING;
11341 rettv->vval.v_string = p;
11342}
11343
11344/*
11345 * "synIDtrans(id)" function
11346 */
11347 static void
11348f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
11349{
11350 int id;
11351
11352#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011353 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011354
11355 if (id > 0)
11356 id = syn_get_final_id(id);
11357 else
11358#endif
11359 id = 0;
11360
11361 rettv->vval.v_number = id;
11362}
11363
11364/*
11365 * "synconcealed(lnum, col)" function
11366 */
11367 static void
11368f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
11369{
11370#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
11371 linenr_T lnum;
11372 colnr_T col;
11373 int syntax_flags = 0;
11374 int cchar;
11375 int matchid = 0;
11376 char_u str[NUMBUFLEN];
11377#endif
11378
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011379 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011380
11381#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011382 lnum = tv_get_lnum(argvars); /* -1 on type error */
11383 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011384
11385 vim_memset(str, NUL, sizeof(str));
11386
11387 if (rettv_list_alloc(rettv) != FAIL)
11388 {
11389 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11390 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11391 && curwin->w_p_cole > 0)
11392 {
11393 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
11394 syntax_flags = get_syntax_info(&matchid);
11395
11396 /* get the conceal character */
11397 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
11398 {
11399 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020011400 if (cchar == NUL && curwin->w_p_cole == 1)
11401 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011402 if (cchar != NUL)
11403 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011404 if (has_mbyte)
11405 (*mb_char2bytes)(cchar, str);
11406 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011407 str[0] = cchar;
11408 }
11409 }
11410 }
11411
11412 list_append_number(rettv->vval.v_list,
11413 (syntax_flags & HL_CONCEAL) != 0);
11414 /* -1 to auto-determine strlen */
11415 list_append_string(rettv->vval.v_list, str, -1);
11416 list_append_number(rettv->vval.v_list, matchid);
11417 }
11418#endif
11419}
11420
11421/*
11422 * "synstack(lnum, col)" function
11423 */
11424 static void
11425f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
11426{
11427#ifdef FEAT_SYN_HL
11428 linenr_T lnum;
11429 colnr_T col;
11430 int i;
11431 int id;
11432#endif
11433
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011434 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011435
11436#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011437 lnum = tv_get_lnum(argvars); /* -1 on type error */
11438 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011439
11440 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
11441 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
11442 && rettv_list_alloc(rettv) != FAIL)
11443 {
11444 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
11445 for (i = 0; ; ++i)
11446 {
11447 id = syn_get_stack_item(i);
11448 if (id < 0)
11449 break;
11450 if (list_append_number(rettv->vval.v_list, id) == FAIL)
11451 break;
11452 }
11453 }
11454#endif
11455}
11456
11457 static void
11458get_cmd_output_as_rettv(
11459 typval_T *argvars,
11460 typval_T *rettv,
11461 int retlist)
11462{
11463 char_u *res = NULL;
11464 char_u *p;
11465 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011466 int err = FALSE;
11467 FILE *fd;
11468 list_T *list = NULL;
11469 int flags = SHELL_SILENT;
11470
11471 rettv->v_type = VAR_STRING;
11472 rettv->vval.v_string = NULL;
11473 if (check_restricted() || check_secure())
11474 goto errret;
11475
11476 if (argvars[1].v_type != VAR_UNKNOWN)
11477 {
11478 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010011479 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011480 * command.
11481 */
11482 if ((infile = vim_tempname('i', TRUE)) == NULL)
11483 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011484 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011485 goto errret;
11486 }
11487
11488 fd = mch_fopen((char *)infile, WRITEBIN);
11489 if (fd == NULL)
11490 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011491 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011492 goto errret;
11493 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010011494 if (argvars[1].v_type == VAR_NUMBER)
11495 {
11496 linenr_T lnum;
11497 buf_T *buf;
11498
11499 buf = buflist_findnr(argvars[1].vval.v_number);
11500 if (buf == NULL)
11501 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011502 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010011503 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010011504 goto errret;
11505 }
11506
11507 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
11508 {
11509 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
11510 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
11511 {
11512 err = TRUE;
11513 break;
11514 }
11515 if (putc(NL, fd) == EOF)
11516 {
11517 err = TRUE;
11518 break;
11519 }
11520 }
11521 }
11522 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011523 {
11524 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
11525 err = TRUE;
11526 }
11527 else
11528 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010011529 size_t len;
11530 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011531
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011532 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011533 if (p == NULL)
11534 {
11535 fclose(fd);
11536 goto errret; /* type error; errmsg already given */
11537 }
11538 len = STRLEN(p);
11539 if (len > 0 && fwrite(p, len, 1, fd) != 1)
11540 err = TRUE;
11541 }
11542 if (fclose(fd) != 0)
11543 err = TRUE;
11544 if (err)
11545 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011546 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011547 goto errret;
11548 }
11549 }
11550
11551 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
11552 * echoes typeahead, that messes up the display. */
11553 if (!msg_silent)
11554 flags += SHELL_COOKED;
11555
11556 if (retlist)
11557 {
11558 int len;
11559 listitem_T *li;
11560 char_u *s = NULL;
11561 char_u *start;
11562 char_u *end;
11563 int i;
11564
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011565 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011566 if (res == NULL)
11567 goto errret;
11568
11569 list = list_alloc();
11570 if (list == NULL)
11571 goto errret;
11572
11573 for (i = 0; i < len; ++i)
11574 {
11575 start = res + i;
11576 while (i < len && res[i] != NL)
11577 ++i;
11578 end = res + i;
11579
Bram Moolenaar964b3742019-05-24 18:54:09 +020011580 s = alloc(end - start + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011581 if (s == NULL)
11582 goto errret;
11583
11584 for (p = s; start < end; ++p, ++start)
11585 *p = *start == NUL ? NL : *start;
11586 *p = NUL;
11587
11588 li = listitem_alloc();
11589 if (li == NULL)
11590 {
11591 vim_free(s);
11592 goto errret;
11593 }
11594 li->li_tv.v_type = VAR_STRING;
11595 li->li_tv.v_lock = 0;
11596 li->li_tv.vval.v_string = s;
11597 list_append(list, li);
11598 }
11599
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020011600 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011601 list = NULL;
11602 }
11603 else
11604 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011605 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010011606#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011607 /* translate <CR><NL> into <NL> */
11608 if (res != NULL)
11609 {
11610 char_u *s, *d;
11611
11612 d = res;
11613 for (s = res; *s; ++s)
11614 {
11615 if (s[0] == CAR && s[1] == NL)
11616 ++s;
11617 *d++ = *s;
11618 }
11619 *d = NUL;
11620 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011621#endif
11622 rettv->vval.v_string = res;
11623 res = NULL;
11624 }
11625
11626errret:
11627 if (infile != NULL)
11628 {
11629 mch_remove(infile);
11630 vim_free(infile);
11631 }
11632 if (res != NULL)
11633 vim_free(res);
11634 if (list != NULL)
11635 list_free(list);
11636}
11637
11638/*
11639 * "system()" function
11640 */
11641 static void
11642f_system(typval_T *argvars, typval_T *rettv)
11643{
11644 get_cmd_output_as_rettv(argvars, rettv, FALSE);
11645}
11646
11647/*
11648 * "systemlist()" function
11649 */
11650 static void
11651f_systemlist(typval_T *argvars, typval_T *rettv)
11652{
11653 get_cmd_output_as_rettv(argvars, rettv, TRUE);
11654}
11655
11656/*
11657 * "tabpagebuflist()" function
11658 */
11659 static void
11660f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11661{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011662 tabpage_T *tp;
11663 win_T *wp = NULL;
11664
11665 if (argvars[0].v_type == VAR_UNKNOWN)
11666 wp = firstwin;
11667 else
11668 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011669 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011670 if (tp != NULL)
11671 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11672 }
11673 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
11674 {
11675 for (; wp != NULL; wp = wp->w_next)
11676 if (list_append_number(rettv->vval.v_list,
11677 wp->w_buffer->b_fnum) == FAIL)
11678 break;
11679 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011680}
11681
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011682/*
11683 * "tabpagenr()" function
11684 */
11685 static void
11686f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
11687{
11688 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011689 char_u *arg;
11690
11691 if (argvars[0].v_type != VAR_UNKNOWN)
11692 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011693 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011694 nr = 0;
11695 if (arg != NULL)
11696 {
11697 if (STRCMP(arg, "$") == 0)
11698 nr = tabpage_index(NULL) - 1;
11699 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011700 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011701 }
11702 }
11703 else
11704 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011705 rettv->vval.v_number = nr;
11706}
11707
11708
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011709/*
11710 * Common code for tabpagewinnr() and winnr().
11711 */
11712 static int
11713get_winnr(tabpage_T *tp, typval_T *argvar)
11714{
11715 win_T *twin;
11716 int nr = 1;
11717 win_T *wp;
11718 char_u *arg;
11719
11720 twin = (tp == curtab) ? curwin : tp->tp_curwin;
11721 if (argvar->v_type != VAR_UNKNOWN)
11722 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011723 int invalid_arg = FALSE;
11724
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011725 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011726 if (arg == NULL)
11727 nr = 0; /* type error; errmsg already given */
11728 else if (STRCMP(arg, "$") == 0)
11729 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
11730 else if (STRCMP(arg, "#") == 0)
11731 {
11732 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
11733 if (twin == NULL)
11734 nr = 0;
11735 }
11736 else
11737 {
Bram Moolenaar46ad2882019-04-08 20:01:47 +020011738 long count;
11739 char_u *endp;
11740
11741 // Extract the window count (if specified). e.g. winnr('3j')
11742 count = strtol((char *)arg, (char **)&endp, 10);
11743 if (count <= 0)
11744 count = 1; // if count is not specified, default to 1
11745 if (endp != NULL && *endp != '\0')
11746 {
11747 if (STRCMP(endp, "j") == 0)
11748 twin = win_vert_neighbor(tp, twin, FALSE, count);
11749 else if (STRCMP(endp, "k") == 0)
11750 twin = win_vert_neighbor(tp, twin, TRUE, count);
11751 else if (STRCMP(endp, "h") == 0)
11752 twin = win_horz_neighbor(tp, twin, TRUE, count);
11753 else if (STRCMP(endp, "l") == 0)
11754 twin = win_horz_neighbor(tp, twin, FALSE, count);
11755 else
11756 invalid_arg = TRUE;
11757 }
11758 else
11759 invalid_arg = TRUE;
11760 }
11761
11762 if (invalid_arg)
11763 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011764 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011765 nr = 0;
11766 }
11767 }
11768
11769 if (nr > 0)
11770 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
11771 wp != twin; wp = wp->w_next)
11772 {
11773 if (wp == NULL)
11774 {
11775 /* didn't find it in this tabpage */
11776 nr = 0;
11777 break;
11778 }
11779 ++nr;
11780 }
11781 return nr;
11782}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011783
11784/*
11785 * "tabpagewinnr()" function
11786 */
11787 static void
11788f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
11789{
11790 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011791 tabpage_T *tp;
11792
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011793 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011794 if (tp == NULL)
11795 nr = 0;
11796 else
11797 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011798 rettv->vval.v_number = nr;
11799}
11800
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011801/*
11802 * "tagfiles()" function
11803 */
11804 static void
11805f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
11806{
11807 char_u *fname;
11808 tagname_T tn;
11809 int first;
11810
11811 if (rettv_list_alloc(rettv) == FAIL)
11812 return;
11813 fname = alloc(MAXPATHL);
11814 if (fname == NULL)
11815 return;
11816
11817 for (first = TRUE; ; first = FALSE)
11818 if (get_tagfname(&tn, first, fname) == FAIL
11819 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
11820 break;
11821 tagname_free(&tn);
11822 vim_free(fname);
11823}
11824
11825/*
11826 * "taglist()" function
11827 */
11828 static void
11829f_taglist(typval_T *argvars, typval_T *rettv)
11830{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011831 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011832 char_u *tag_pattern;
11833
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011834 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011835
11836 rettv->vval.v_number = FALSE;
11837 if (*tag_pattern == NUL)
11838 return;
11839
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011840 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011841 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011842 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010011843 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011844}
11845
11846/*
11847 * "tempname()" function
11848 */
11849 static void
11850f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
11851{
11852 static int x = 'A';
11853
11854 rettv->v_type = VAR_STRING;
11855 rettv->vval.v_string = vim_tempname(x, FALSE);
11856
11857 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
11858 * names. Skip 'I' and 'O', they are used for shell redirection. */
11859 do
11860 {
11861 if (x == 'Z')
11862 x = '0';
11863 else if (x == '9')
11864 x = 'A';
11865 else
11866 {
11867#ifdef EBCDIC
11868 if (x == 'I')
11869 x = 'J';
11870 else if (x == 'R')
11871 x = 'S';
11872 else
11873#endif
11874 ++x;
11875 }
11876 } while (x == 'I' || x == 'O');
11877}
11878
11879#ifdef FEAT_FLOAT
11880/*
11881 * "tan()" function
11882 */
11883 static void
11884f_tan(typval_T *argvars, typval_T *rettv)
11885{
11886 float_T f = 0.0;
11887
11888 rettv->v_type = VAR_FLOAT;
11889 if (get_float_arg(argvars, &f) == OK)
11890 rettv->vval.v_float = tan(f);
11891 else
11892 rettv->vval.v_float = 0.0;
11893}
11894
11895/*
11896 * "tanh()" function
11897 */
11898 static void
11899f_tanh(typval_T *argvars, typval_T *rettv)
11900{
11901 float_T f = 0.0;
11902
11903 rettv->v_type = VAR_FLOAT;
11904 if (get_float_arg(argvars, &f) == OK)
11905 rettv->vval.v_float = tanh(f);
11906 else
11907 rettv->vval.v_float = 0.0;
11908}
11909#endif
11910
11911/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011912 * Get a callback from "arg". It can be a Funcref or a function name.
11913 * When "arg" is zero return an empty string.
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011914 * "cb_name" is not allocated.
11915 * "cb_name" is set to NULL for an invalid argument.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011916 */
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011917 callback_T
11918get_callback(typval_T *arg)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011919{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011920 callback_T res;
11921
11922 res.cb_free_name = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011923 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
11924 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011925 res.cb_partial = arg->vval.v_partial;
11926 ++res.cb_partial->pt_refcount;
11927 res.cb_name = partial_name(res.cb_partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011928 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011929 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011930 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011931 res.cb_partial = NULL;
11932 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
11933 {
11934 // Note that we don't make a copy of the string.
11935 res.cb_name = arg->vval.v_string;
11936 func_ref(res.cb_name);
11937 }
11938 else if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
11939 {
11940 res.cb_name = (char_u *)"";
11941 }
11942 else
11943 {
11944 emsg(_("E921: Invalid callback argument"));
11945 res.cb_name = NULL;
11946 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011947 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011948 return res;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011949}
11950
11951/*
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011952 * Copy a callback into a typval_T.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011953 */
11954 void
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011955put_callback(callback_T *cb, typval_T *tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011956{
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011957 if (cb->cb_partial != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011958 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011959 tv->v_type = VAR_PARTIAL;
11960 tv->vval.v_partial = cb->cb_partial;
11961 ++tv->vval.v_partial->pt_refcount;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011962 }
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020011963 else
11964 {
11965 tv->v_type = VAR_FUNC;
11966 tv->vval.v_string = vim_strsave(cb->cb_name);
11967 func_ref(cb->cb_name);
11968 }
11969}
11970
11971/*
11972 * Make a copy of "src" into "dest", allocating the function name if needed,
11973 * without incrementing the refcount.
11974 */
11975 void
11976set_callback(callback_T *dest, callback_T *src)
11977{
11978 if (src->cb_partial == NULL)
11979 {
11980 // just a function name, make a copy
11981 dest->cb_name = vim_strsave(src->cb_name);
11982 dest->cb_free_name = TRUE;
11983 }
11984 else
11985 {
11986 // cb_name is a pointer into cb_partial
11987 dest->cb_name = src->cb_name;
11988 dest->cb_free_name = FALSE;
11989 }
11990 dest->cb_partial = src->cb_partial;
11991}
11992
11993/*
11994 * Unref/free "callback" returned by get_callback() or set_callback().
11995 */
11996 void
11997free_callback(callback_T *callback)
11998{
11999 if (callback->cb_partial != NULL)
12000 {
12001 partial_unref(callback->cb_partial);
12002 callback->cb_partial = NULL;
12003 }
12004 else if (callback->cb_name != NULL)
12005 func_unref(callback->cb_name);
12006 if (callback->cb_free_name)
12007 {
12008 vim_free(callback->cb_name);
12009 callback->cb_free_name = FALSE;
12010 }
12011 callback->cb_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012012}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012013
12014#ifdef FEAT_TIMERS
12015/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012016 * "timer_info([timer])" function
12017 */
12018 static void
12019f_timer_info(typval_T *argvars, typval_T *rettv)
12020{
12021 timer_T *timer = NULL;
12022
12023 if (rettv_list_alloc(rettv) != OK)
12024 return;
12025 if (argvars[0].v_type != VAR_UNKNOWN)
12026 {
12027 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012028 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012029 else
12030 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012031 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020012032 if (timer != NULL)
12033 add_timer_info(rettv, timer);
12034 }
12035 }
12036 else
12037 add_timer_info_all(rettv);
12038}
12039
12040/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012041 * "timer_pause(timer, paused)" function
12042 */
12043 static void
12044f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
12045{
12046 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012047 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012048
12049 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012050 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012051 else
12052 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012053 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012054 if (timer != NULL)
12055 timer->tr_paused = paused;
12056 }
12057}
12058
12059/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012060 * "timer_start(time, callback [, options])" function
12061 */
12062 static void
12063f_timer_start(typval_T *argvars, typval_T *rettv)
12064{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012065 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012066 timer_T *timer;
12067 int repeat = 0;
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012068 callback_T callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020012069 dict_T *dict;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012070
Bram Moolenaar75537a92016-09-05 22:45:28 +020012071 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012072 if (check_secure())
12073 return;
12074 if (argvars[2].v_type != VAR_UNKNOWN)
12075 {
12076 if (argvars[2].v_type != VAR_DICT
12077 || (dict = argvars[2].vval.v_dict) == NULL)
12078 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012079 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012080 return;
12081 }
12082 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012083 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012084 }
12085
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012086 callback = get_callback(&argvars[1]);
12087 if (callback.cb_name == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020012088 return;
12089
12090 timer = create_timer(msec, repeat);
12091 if (timer == NULL)
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012092 free_callback(&callback);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012093 else
12094 {
Bram Moolenaar3a97bb32019-06-01 13:28:35 +020012095 set_callback(&timer->tr_callback, &callback);
Bram Moolenaar75537a92016-09-05 22:45:28 +020012096 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012097 }
12098}
12099
12100/*
12101 * "timer_stop(timer)" function
12102 */
12103 static void
12104f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
12105{
12106 timer_T *timer;
12107
12108 if (argvars[0].v_type != VAR_NUMBER)
12109 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012110 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012111 return;
12112 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012113 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012114 if (timer != NULL)
12115 stop_timer(timer);
12116}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020012117
12118/*
12119 * "timer_stopall()" function
12120 */
12121 static void
12122f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12123{
12124 stop_all_timers();
12125}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012126#endif
12127
12128/*
12129 * "tolower(string)" function
12130 */
12131 static void
12132f_tolower(typval_T *argvars, typval_T *rettv)
12133{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012134 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012135 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012136}
12137
12138/*
12139 * "toupper(string)" function
12140 */
12141 static void
12142f_toupper(typval_T *argvars, typval_T *rettv)
12143{
12144 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012145 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012146}
12147
12148/*
12149 * "tr(string, fromstr, tostr)" function
12150 */
12151 static void
12152f_tr(typval_T *argvars, typval_T *rettv)
12153{
12154 char_u *in_str;
12155 char_u *fromstr;
12156 char_u *tostr;
12157 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012158 int inlen;
12159 int fromlen;
12160 int tolen;
12161 int idx;
12162 char_u *cpstr;
12163 int cplen;
12164 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012165 char_u buf[NUMBUFLEN];
12166 char_u buf2[NUMBUFLEN];
12167 garray_T ga;
12168
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012169 in_str = tv_get_string(&argvars[0]);
12170 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
12171 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012172
12173 /* Default return value: empty string. */
12174 rettv->v_type = VAR_STRING;
12175 rettv->vval.v_string = NULL;
12176 if (fromstr == NULL || tostr == NULL)
12177 return; /* type error; errmsg already given */
12178 ga_init2(&ga, (int)sizeof(char), 80);
12179
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012180 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012181 /* not multi-byte: fromstr and tostr must be the same length */
12182 if (STRLEN(fromstr) != STRLEN(tostr))
12183 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012184error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012185 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012186 ga_clear(&ga);
12187 return;
12188 }
12189
12190 /* fromstr and tostr have to contain the same number of chars */
12191 while (*in_str != NUL)
12192 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012193 if (has_mbyte)
12194 {
12195 inlen = (*mb_ptr2len)(in_str);
12196 cpstr = in_str;
12197 cplen = inlen;
12198 idx = 0;
12199 for (p = fromstr; *p != NUL; p += fromlen)
12200 {
12201 fromlen = (*mb_ptr2len)(p);
12202 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
12203 {
12204 for (p = tostr; *p != NUL; p += tolen)
12205 {
12206 tolen = (*mb_ptr2len)(p);
12207 if (idx-- == 0)
12208 {
12209 cplen = tolen;
12210 cpstr = p;
12211 break;
12212 }
12213 }
12214 if (*p == NUL) /* tostr is shorter than fromstr */
12215 goto error;
12216 break;
12217 }
12218 ++idx;
12219 }
12220
12221 if (first && cpstr == in_str)
12222 {
12223 /* Check that fromstr and tostr have the same number of
12224 * (multi-byte) characters. Done only once when a character
12225 * of in_str doesn't appear in fromstr. */
12226 first = FALSE;
12227 for (p = tostr; *p != NUL; p += tolen)
12228 {
12229 tolen = (*mb_ptr2len)(p);
12230 --idx;
12231 }
12232 if (idx != 0)
12233 goto error;
12234 }
12235
12236 (void)ga_grow(&ga, cplen);
12237 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
12238 ga.ga_len += cplen;
12239
12240 in_str += inlen;
12241 }
12242 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012243 {
12244 /* When not using multi-byte chars we can do it faster. */
12245 p = vim_strchr(fromstr, *in_str);
12246 if (p != NULL)
12247 ga_append(&ga, tostr[p - fromstr]);
12248 else
12249 ga_append(&ga, *in_str);
12250 ++in_str;
12251 }
12252 }
12253
12254 /* add a terminating NUL */
12255 (void)ga_grow(&ga, 1);
12256 ga_append(&ga, NUL);
12257
12258 rettv->vval.v_string = ga.ga_data;
12259}
12260
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012261/*
12262 * "trim({expr})" function
12263 */
12264 static void
12265f_trim(typval_T *argvars, typval_T *rettv)
12266{
12267 char_u buf1[NUMBUFLEN];
12268 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012269 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012270 char_u *mask = NULL;
12271 char_u *tail;
12272 char_u *prev;
12273 char_u *p;
12274 int c1;
12275
12276 rettv->v_type = VAR_STRING;
12277 if (head == NULL)
12278 {
12279 rettv->vval.v_string = NULL;
12280 return;
12281 }
12282
12283 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012284 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010012285
12286 while (*head != NUL)
12287 {
12288 c1 = PTR2CHAR(head);
12289 if (mask == NULL)
12290 {
12291 if (c1 > ' ' && c1 != 0xa0)
12292 break;
12293 }
12294 else
12295 {
12296 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12297 if (c1 == PTR2CHAR(p))
12298 break;
12299 if (*p == NUL)
12300 break;
12301 }
12302 MB_PTR_ADV(head);
12303 }
12304
12305 for (tail = head + STRLEN(head); tail > head; tail = prev)
12306 {
12307 prev = tail;
12308 MB_PTR_BACK(head, prev);
12309 c1 = PTR2CHAR(prev);
12310 if (mask == NULL)
12311 {
12312 if (c1 > ' ' && c1 != 0xa0)
12313 break;
12314 }
12315 else
12316 {
12317 for (p = mask; *p != NUL; MB_PTR_ADV(p))
12318 if (c1 == PTR2CHAR(p))
12319 break;
12320 if (*p == NUL)
12321 break;
12322 }
12323 }
12324 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
12325}
12326
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012327#ifdef FEAT_FLOAT
12328/*
12329 * "trunc({float})" function
12330 */
12331 static void
12332f_trunc(typval_T *argvars, typval_T *rettv)
12333{
12334 float_T f = 0.0;
12335
12336 rettv->v_type = VAR_FLOAT;
12337 if (get_float_arg(argvars, &f) == OK)
12338 /* trunc() is not in C90, use floor() or ceil() instead. */
12339 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
12340 else
12341 rettv->vval.v_float = 0.0;
12342}
12343#endif
12344
12345/*
12346 * "type(expr)" function
12347 */
12348 static void
12349f_type(typval_T *argvars, typval_T *rettv)
12350{
12351 int n = -1;
12352
12353 switch (argvars[0].v_type)
12354 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020012355 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
12356 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012357 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020012358 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
12359 case VAR_LIST: n = VAR_TYPE_LIST; break;
12360 case VAR_DICT: n = VAR_TYPE_DICT; break;
12361 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012362 case VAR_SPECIAL:
12363 if (argvars[0].vval.v_number == VVAL_FALSE
12364 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020012365 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012366 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020012367 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012368 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020012369 case VAR_JOB: n = VAR_TYPE_JOB; break;
12370 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012371 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012372 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010012373 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012374 n = -1;
12375 break;
12376 }
12377 rettv->vval.v_number = n;
12378}
12379
12380/*
12381 * "undofile(name)" function
12382 */
12383 static void
12384f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
12385{
12386 rettv->v_type = VAR_STRING;
12387#ifdef FEAT_PERSISTENT_UNDO
12388 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012389 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012390
12391 if (*fname == NUL)
12392 {
12393 /* If there is no file name there will be no undo file. */
12394 rettv->vval.v_string = NULL;
12395 }
12396 else
12397 {
Bram Moolenaare9ebc9a2019-05-19 15:27:14 +020012398 char_u *ffname = FullName_save(fname, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012399
12400 if (ffname != NULL)
12401 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
12402 vim_free(ffname);
12403 }
12404 }
12405#else
12406 rettv->vval.v_string = NULL;
12407#endif
12408}
12409
12410/*
12411 * "undotree()" function
12412 */
12413 static void
12414f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
12415{
12416 if (rettv_dict_alloc(rettv) == OK)
12417 {
12418 dict_T *dict = rettv->vval.v_dict;
12419 list_T *list;
12420
Bram Moolenaare0be1672018-07-08 16:50:37 +020012421 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
12422 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
12423 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
12424 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
12425 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
12426 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012427
12428 list = list_alloc();
12429 if (list != NULL)
12430 {
12431 u_eval_tree(curbuf->b_u_oldhead, list);
12432 dict_add_list(dict, "entries", list);
12433 }
12434 }
12435}
12436
12437/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012438 * "virtcol(string)" function
12439 */
12440 static void
12441f_virtcol(typval_T *argvars, typval_T *rettv)
12442{
12443 colnr_T vcol = 0;
12444 pos_T *fp;
12445 int fnum = curbuf->b_fnum;
12446
12447 fp = var2fpos(&argvars[0], FALSE, &fnum);
12448 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
12449 && fnum == curbuf->b_fnum)
12450 {
12451 getvvcol(curwin, fp, NULL, NULL, &vcol);
12452 ++vcol;
12453 }
12454
12455 rettv->vval.v_number = vcol;
12456}
12457
12458/*
12459 * "visualmode()" function
12460 */
12461 static void
12462f_visualmode(typval_T *argvars, typval_T *rettv)
12463{
12464 char_u str[2];
12465
12466 rettv->v_type = VAR_STRING;
12467 str[0] = curbuf->b_visual_mode_eval;
12468 str[1] = NUL;
12469 rettv->vval.v_string = vim_strsave(str);
12470
12471 /* A non-zero number or non-empty string argument: reset mode. */
12472 if (non_zero_arg(&argvars[0]))
12473 curbuf->b_visual_mode_eval = NUL;
12474}
12475
12476/*
12477 * "wildmenumode()" function
12478 */
12479 static void
12480f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
12481{
12482#ifdef FEAT_WILDMENU
12483 if (wild_menu_showing)
12484 rettv->vval.v_number = 1;
12485#endif
12486}
12487
12488/*
12489 * "winbufnr(nr)" function
12490 */
12491 static void
12492f_winbufnr(typval_T *argvars, typval_T *rettv)
12493{
12494 win_T *wp;
12495
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012496 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012497 if (wp == NULL)
12498 rettv->vval.v_number = -1;
12499 else
12500 rettv->vval.v_number = wp->w_buffer->b_fnum;
12501}
12502
12503/*
12504 * "wincol()" function
12505 */
12506 static void
12507f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
12508{
12509 validate_cursor();
12510 rettv->vval.v_number = curwin->w_wcol + 1;
12511}
12512
12513/*
12514 * "winheight(nr)" function
12515 */
12516 static void
12517f_winheight(typval_T *argvars, typval_T *rettv)
12518{
12519 win_T *wp;
12520
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012521 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012522 if (wp == NULL)
12523 rettv->vval.v_number = -1;
12524 else
12525 rettv->vval.v_number = wp->w_height;
12526}
12527
12528/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012529 * "winlayout()" function
12530 */
12531 static void
12532f_winlayout(typval_T *argvars, typval_T *rettv)
12533{
12534 tabpage_T *tp;
12535
12536 if (rettv_list_alloc(rettv) != OK)
12537 return;
12538
12539 if (argvars[0].v_type == VAR_UNKNOWN)
12540 tp = curtab;
12541 else
12542 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012543 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020012544 if (tp == NULL)
12545 return;
12546 }
12547
12548 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
12549}
12550
12551/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012552 * "winline()" function
12553 */
12554 static void
12555f_winline(typval_T *argvars UNUSED, typval_T *rettv)
12556{
12557 validate_cursor();
12558 rettv->vval.v_number = curwin->w_wrow + 1;
12559}
12560
12561/*
12562 * "winnr()" function
12563 */
12564 static void
12565f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
12566{
12567 int nr = 1;
12568
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012569 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012570 rettv->vval.v_number = nr;
12571}
12572
12573/*
12574 * "winrestcmd()" function
12575 */
12576 static void
12577f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
12578{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012579 win_T *wp;
12580 int winnr = 1;
12581 garray_T ga;
12582 char_u buf[50];
12583
12584 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020012585 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012586 {
12587 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
12588 ga_concat(&ga, buf);
12589 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
12590 ga_concat(&ga, buf);
12591 ++winnr;
12592 }
12593 ga_append(&ga, NUL);
12594
12595 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012596 rettv->v_type = VAR_STRING;
12597}
12598
12599/*
12600 * "winrestview()" function
12601 */
12602 static void
12603f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
12604{
12605 dict_T *dict;
12606
12607 if (argvars[0].v_type != VAR_DICT
12608 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012609 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012610 else
12611 {
12612 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012613 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012614 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012615 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012616 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012617 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012618 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
12619 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010012620 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012621 curwin->w_set_curswant = FALSE;
12622 }
12623
12624 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012625 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012626#ifdef FEAT_DIFF
12627 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012628 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012629#endif
12630 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012631 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012632 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010012633 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012634
12635 check_cursor();
12636 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020012637 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012638 changed_window_setting();
12639
12640 if (curwin->w_topline <= 0)
12641 curwin->w_topline = 1;
12642 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
12643 curwin->w_topline = curbuf->b_ml.ml_line_count;
12644#ifdef FEAT_DIFF
12645 check_topfill(curwin, TRUE);
12646#endif
12647 }
12648}
12649
12650/*
12651 * "winsaveview()" function
12652 */
12653 static void
12654f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
12655{
12656 dict_T *dict;
12657
12658 if (rettv_dict_alloc(rettv) == FAIL)
12659 return;
12660 dict = rettv->vval.v_dict;
12661
Bram Moolenaare0be1672018-07-08 16:50:37 +020012662 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
12663 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020012664 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012665 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020012666 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012667
Bram Moolenaare0be1672018-07-08 16:50:37 +020012668 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012669#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020012670 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012671#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020012672 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
12673 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012674}
12675
12676/*
12677 * "winwidth(nr)" function
12678 */
12679 static void
12680f_winwidth(typval_T *argvars, typval_T *rettv)
12681{
12682 win_T *wp;
12683
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020012684 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012685 if (wp == NULL)
12686 rettv->vval.v_number = -1;
12687 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012688 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012689}
12690
12691/*
12692 * "wordcount()" function
12693 */
12694 static void
12695f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
12696{
12697 if (rettv_dict_alloc(rettv) == FAIL)
12698 return;
12699 cursor_pos_info(rettv->vval.v_dict);
12700}
12701
12702/*
12703 * "writefile()" function
12704 */
12705 static void
12706f_writefile(typval_T *argvars, typval_T *rettv)
12707{
12708 int binary = FALSE;
12709 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012710#ifdef HAVE_FSYNC
12711 int do_fsync = p_fs;
12712#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012713 char_u *fname;
12714 FILE *fd;
12715 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012716 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012717 list_T *list = NULL;
12718 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012719
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012720 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010012721 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012722 return;
12723
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012724 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012725 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012726 list = argvars[0].vval.v_list;
12727 if (list == NULL)
12728 return;
12729 for (li = list->lv_first; li != NULL; li = li->li_next)
12730 if (tv_get_string_chk(&li->li_tv) == NULL)
12731 return;
12732 }
12733 else if (argvars[0].v_type == VAR_BLOB)
12734 {
12735 blob = argvars[0].vval.v_blob;
12736 if (blob == NULL)
12737 return;
12738 }
12739 else
12740 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012741 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012742 return;
12743 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012744
12745 if (argvars[2].v_type != VAR_UNKNOWN)
12746 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012747 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012748
12749 if (arg2 == NULL)
12750 return;
12751 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012752 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012753 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012754 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012755#ifdef HAVE_FSYNC
12756 if (vim_strchr(arg2, 's') != NULL)
12757 do_fsync = TRUE;
12758 else if (vim_strchr(arg2, 'S') != NULL)
12759 do_fsync = FALSE;
12760#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 }
12762
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012763 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012764 if (fname == NULL)
12765 return;
12766
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012767 /* Always open the file in binary mode, library functions have a mind of
12768 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012769 if (*fname == NUL || (fd = mch_fopen((char *)fname,
12770 append ? APPENDBIN : WRITEBIN)) == NULL)
12771 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012772 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012773 ret = -1;
12774 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012775 else if (blob)
12776 {
12777 if (write_blob(fd, blob) == FAIL)
12778 ret = -1;
12779#ifdef HAVE_FSYNC
12780 else if (do_fsync)
12781 // Ignore the error, the user wouldn't know what to do about it.
12782 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010012783 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010012784#endif
12785 fclose(fd);
12786 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012787 else
12788 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020012789 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012790 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012791#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010012792 else if (do_fsync)
12793 /* Ignore the error, the user wouldn't know what to do about it.
12794 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010012795 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010012796#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012797 fclose(fd);
12798 }
12799
12800 rettv->vval.v_number = ret;
12801}
12802
12803/*
12804 * "xor(expr, expr)" function
12805 */
12806 static void
12807f_xor(typval_T *argvars, typval_T *rettv)
12808{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012809 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
12810 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012811}
12812
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012813#endif /* FEAT_EVAL */