blob: 524031e0cd37d6f0f8679b96535d3755786f102f [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
19#ifdef AMIGA
20# include <time.h> /* for strftime() */
21#endif
22
23#ifdef VMS
24# include <float.h>
25#endif
26
Bram Moolenaard0573012017-10-28 21:11:06 +020027#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028# include <time.h> /* for time_t */
29#endif
30
31static char *e_listarg = N_("E686: Argument of %s must be a List");
Bram Moolenaarbf821bc2019-01-23 21:15:02 +010032static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020033static char *e_stringreq = N_("E928: String required");
Bram Moolenaaraff74912019-03-30 18:11:49 +010034static char *e_invalwindow = N_("E957: Invalid window number");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020035
36#ifdef FEAT_FLOAT
37static void f_abs(typval_T *argvars, typval_T *rettv);
38static void f_acos(typval_T *argvars, typval_T *rettv);
39#endif
40static void f_add(typval_T *argvars, typval_T *rettv);
41static void f_and(typval_T *argvars, typval_T *rettv);
42static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020043static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_argc(typval_T *argvars, typval_T *rettv);
45static void f_argidx(typval_T *argvars, typval_T *rettv);
46static void f_arglistid(typval_T *argvars, typval_T *rettv);
47static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010048static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020049static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010050static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_assert_exception(typval_T *argvars, typval_T *rettv);
52static void f_assert_fails(typval_T *argvars, typval_T *rettv);
53static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020054static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_assert_match(typval_T *argvars, typval_T *rettv);
56static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
57static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010058static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020059static void f_assert_true(typval_T *argvars, typval_T *rettv);
60#ifdef FEAT_FLOAT
61static void f_asin(typval_T *argvars, typval_T *rettv);
62static void f_atan(typval_T *argvars, typval_T *rettv);
63static void f_atan2(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010065#ifdef FEAT_BEVAL
66static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010067# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010068static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010069# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010070#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020071static void f_browse(typval_T *argvars, typval_T *rettv);
72static void f_browsedir(typval_T *argvars, typval_T *rettv);
73static void f_bufexists(typval_T *argvars, typval_T *rettv);
74static void f_buflisted(typval_T *argvars, typval_T *rettv);
75static void f_bufloaded(typval_T *argvars, typval_T *rettv);
76static void f_bufname(typval_T *argvars, typval_T *rettv);
77static void f_bufnr(typval_T *argvars, typval_T *rettv);
78static void f_bufwinid(typval_T *argvars, typval_T *rettv);
79static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
80static void f_byte2line(typval_T *argvars, typval_T *rettv);
81static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
82static void f_byteidx(typval_T *argvars, typval_T *rettv);
83static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
84static void f_call(typval_T *argvars, typval_T *rettv);
85#ifdef FEAT_FLOAT
86static void f_ceil(typval_T *argvars, typval_T *rettv);
87#endif
88#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010089static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020090static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020091static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
93static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
94static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
95static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
96static void f_ch_info(typval_T *argvars, typval_T *rettv);
97static void f_ch_log(typval_T *argvars, typval_T *rettv);
98static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
99static void f_ch_open(typval_T *argvars, typval_T *rettv);
100static void f_ch_read(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100101static void f_ch_readblob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200102static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
103static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
104static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
105static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
106static void f_ch_status(typval_T *argvars, typval_T *rettv);
107#endif
108static void f_changenr(typval_T *argvars, typval_T *rettv);
109static void f_char2nr(typval_T *argvars, typval_T *rettv);
110static void f_cindent(typval_T *argvars, typval_T *rettv);
111static void f_clearmatches(typval_T *argvars, typval_T *rettv);
112static void f_col(typval_T *argvars, typval_T *rettv);
113#if defined(FEAT_INS_EXPAND)
114static void f_complete(typval_T *argvars, typval_T *rettv);
115static void f_complete_add(typval_T *argvars, typval_T *rettv);
116static void f_complete_check(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfd133322019-03-29 12:20:27 +0100117static void f_complete_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118#endif
119static void f_confirm(typval_T *argvars, typval_T *rettv);
120static void f_copy(typval_T *argvars, typval_T *rettv);
121#ifdef FEAT_FLOAT
122static void f_cos(typval_T *argvars, typval_T *rettv);
123static void f_cosh(typval_T *argvars, typval_T *rettv);
124#endif
125static void f_count(typval_T *argvars, typval_T *rettv);
126static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
127static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +0100128#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200129static void f_debugbreak(typval_T *argvars, typval_T *rettv);
130#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200131static void f_deepcopy(typval_T *argvars, typval_T *rettv);
132static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200133static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200134static void f_did_filetype(typval_T *argvars, typval_T *rettv);
135static void f_diff_filler(typval_T *argvars, typval_T *rettv);
136static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
137static void f_empty(typval_T *argvars, typval_T *rettv);
138static void f_escape(typval_T *argvars, typval_T *rettv);
139static void f_eval(typval_T *argvars, typval_T *rettv);
140static void f_eventhandler(typval_T *argvars, typval_T *rettv);
141static void f_executable(typval_T *argvars, typval_T *rettv);
142static void f_execute(typval_T *argvars, typval_T *rettv);
143static void f_exepath(typval_T *argvars, typval_T *rettv);
144static void f_exists(typval_T *argvars, typval_T *rettv);
145#ifdef FEAT_FLOAT
146static void f_exp(typval_T *argvars, typval_T *rettv);
147#endif
148static void f_expand(typval_T *argvars, typval_T *rettv);
149static void f_extend(typval_T *argvars, typval_T *rettv);
150static void f_feedkeys(typval_T *argvars, typval_T *rettv);
151static void f_filereadable(typval_T *argvars, typval_T *rettv);
152static void f_filewritable(typval_T *argvars, typval_T *rettv);
153static void f_filter(typval_T *argvars, typval_T *rettv);
154static void f_finddir(typval_T *argvars, typval_T *rettv);
155static void f_findfile(typval_T *argvars, typval_T *rettv);
156#ifdef FEAT_FLOAT
157static void f_float2nr(typval_T *argvars, typval_T *rettv);
158static void f_floor(typval_T *argvars, typval_T *rettv);
159static void f_fmod(typval_T *argvars, typval_T *rettv);
160#endif
161static void f_fnameescape(typval_T *argvars, typval_T *rettv);
162static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
163static void f_foldclosed(typval_T *argvars, typval_T *rettv);
164static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
165static void f_foldlevel(typval_T *argvars, typval_T *rettv);
166static void f_foldtext(typval_T *argvars, typval_T *rettv);
167static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
168static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200169static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_function(typval_T *argvars, typval_T *rettv);
171static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
172static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200173static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200174static void f_getbufline(typval_T *argvars, typval_T *rettv);
175static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100176static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_getchar(typval_T *argvars, typval_T *rettv);
178static void f_getcharmod(typval_T *argvars, typval_T *rettv);
179static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
180static void f_getcmdline(typval_T *argvars, typval_T *rettv);
181#if defined(FEAT_CMDL_COMPL)
182static void f_getcompletion(typval_T *argvars, typval_T *rettv);
183#endif
184static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
185static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
186static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
187static void f_getcwd(typval_T *argvars, typval_T *rettv);
188static void f_getfontname(typval_T *argvars, typval_T *rettv);
189static void f_getfperm(typval_T *argvars, typval_T *rettv);
190static void f_getfsize(typval_T *argvars, typval_T *rettv);
191static void f_getftime(typval_T *argvars, typval_T *rettv);
192static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100193static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200195static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_getmatches(typval_T *argvars, typval_T *rettv);
197static void f_getpid(typval_T *argvars, typval_T *rettv);
198static void f_getcurpos(typval_T *argvars, typval_T *rettv);
199static void f_getpos(typval_T *argvars, typval_T *rettv);
200static void f_getqflist(typval_T *argvars, typval_T *rettv);
201static void f_getreg(typval_T *argvars, typval_T *rettv);
202static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200203static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204static void f_gettabvar(typval_T *argvars, typval_T *rettv);
205static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100206static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200207static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100208static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_getwinposx(typval_T *argvars, typval_T *rettv);
210static void f_getwinposy(typval_T *argvars, typval_T *rettv);
211static void f_getwinvar(typval_T *argvars, typval_T *rettv);
212static void f_glob(typval_T *argvars, typval_T *rettv);
213static void f_globpath(typval_T *argvars, typval_T *rettv);
214static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
215static void f_has(typval_T *argvars, typval_T *rettv);
216static void f_has_key(typval_T *argvars, typval_T *rettv);
217static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
218static void f_hasmapto(typval_T *argvars, typval_T *rettv);
219static void f_histadd(typval_T *argvars, typval_T *rettv);
220static void f_histdel(typval_T *argvars, typval_T *rettv);
221static void f_histget(typval_T *argvars, typval_T *rettv);
222static void f_histnr(typval_T *argvars, typval_T *rettv);
223static void f_hlID(typval_T *argvars, typval_T *rettv);
224static void f_hlexists(typval_T *argvars, typval_T *rettv);
225static void f_hostname(typval_T *argvars, typval_T *rettv);
226static void f_iconv(typval_T *argvars, typval_T *rettv);
227static void f_indent(typval_T *argvars, typval_T *rettv);
228static void f_index(typval_T *argvars, typval_T *rettv);
229static void f_input(typval_T *argvars, typval_T *rettv);
230static void f_inputdialog(typval_T *argvars, typval_T *rettv);
231static void f_inputlist(typval_T *argvars, typval_T *rettv);
232static void f_inputrestore(typval_T *argvars, typval_T *rettv);
233static void f_inputsave(typval_T *argvars, typval_T *rettv);
234static void f_inputsecret(typval_T *argvars, typval_T *rettv);
235static void f_insert(typval_T *argvars, typval_T *rettv);
236static void f_invert(typval_T *argvars, typval_T *rettv);
237static void f_isdirectory(typval_T *argvars, typval_T *rettv);
238static void f_islocked(typval_T *argvars, typval_T *rettv);
239#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
240static void f_isnan(typval_T *argvars, typval_T *rettv);
241#endif
242static void f_items(typval_T *argvars, typval_T *rettv);
243#ifdef FEAT_JOB_CHANNEL
244static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
245static void f_job_info(typval_T *argvars, typval_T *rettv);
246static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
247static void f_job_start(typval_T *argvars, typval_T *rettv);
248static void f_job_stop(typval_T *argvars, typval_T *rettv);
249static void f_job_status(typval_T *argvars, typval_T *rettv);
250#endif
251static void f_join(typval_T *argvars, typval_T *rettv);
252static void f_js_decode(typval_T *argvars, typval_T *rettv);
253static void f_js_encode(typval_T *argvars, typval_T *rettv);
254static void f_json_decode(typval_T *argvars, typval_T *rettv);
255static void f_json_encode(typval_T *argvars, typval_T *rettv);
256static void f_keys(typval_T *argvars, typval_T *rettv);
257static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
258static void f_len(typval_T *argvars, typval_T *rettv);
259static void f_libcall(typval_T *argvars, typval_T *rettv);
260static void f_libcallnr(typval_T *argvars, typval_T *rettv);
261static void f_line(typval_T *argvars, typval_T *rettv);
262static void f_line2byte(typval_T *argvars, typval_T *rettv);
263static void f_lispindent(typval_T *argvars, typval_T *rettv);
264static void f_localtime(typval_T *argvars, typval_T *rettv);
265#ifdef FEAT_FLOAT
266static void f_log(typval_T *argvars, typval_T *rettv);
267static void f_log10(typval_T *argvars, typval_T *rettv);
268#endif
269#ifdef FEAT_LUA
270static void f_luaeval(typval_T *argvars, typval_T *rettv);
271#endif
272static void f_map(typval_T *argvars, typval_T *rettv);
273static void f_maparg(typval_T *argvars, typval_T *rettv);
274static void f_mapcheck(typval_T *argvars, typval_T *rettv);
275static void f_match(typval_T *argvars, typval_T *rettv);
276static void f_matchadd(typval_T *argvars, typval_T *rettv);
277static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
278static void f_matcharg(typval_T *argvars, typval_T *rettv);
279static void f_matchdelete(typval_T *argvars, typval_T *rettv);
280static void f_matchend(typval_T *argvars, typval_T *rettv);
281static void f_matchlist(typval_T *argvars, typval_T *rettv);
282static void f_matchstr(typval_T *argvars, typval_T *rettv);
283static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
284static void f_max(typval_T *argvars, typval_T *rettv);
285static void f_min(typval_T *argvars, typval_T *rettv);
286#ifdef vim_mkdir
287static void f_mkdir(typval_T *argvars, typval_T *rettv);
288#endif
289static void f_mode(typval_T *argvars, typval_T *rettv);
290#ifdef FEAT_MZSCHEME
291static void f_mzeval(typval_T *argvars, typval_T *rettv);
292#endif
293static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
294static void f_nr2char(typval_T *argvars, typval_T *rettv);
295static void f_or(typval_T *argvars, typval_T *rettv);
296static void f_pathshorten(typval_T *argvars, typval_T *rettv);
297#ifdef FEAT_PERL
298static void f_perleval(typval_T *argvars, typval_T *rettv);
299#endif
300#ifdef FEAT_FLOAT
301static void f_pow(typval_T *argvars, typval_T *rettv);
302#endif
303static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
304static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200305#ifdef FEAT_JOB_CHANNEL
306static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200307static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200308static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
309#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200310static void f_pumvisible(typval_T *argvars, typval_T *rettv);
311#ifdef FEAT_PYTHON3
312static void f_py3eval(typval_T *argvars, typval_T *rettv);
313#endif
314#ifdef FEAT_PYTHON
315static void f_pyeval(typval_T *argvars, typval_T *rettv);
316#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100317#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
318static void f_pyxeval(typval_T *argvars, typval_T *rettv);
319#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200320static void f_range(typval_T *argvars, typval_T *rettv);
321static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200322static void f_reg_executing(typval_T *argvars, typval_T *rettv);
323static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200324static void f_reltime(typval_T *argvars, typval_T *rettv);
325#ifdef FEAT_FLOAT
326static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
327#endif
328static void f_reltimestr(typval_T *argvars, typval_T *rettv);
329static void f_remote_expr(typval_T *argvars, typval_T *rettv);
330static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
331static void f_remote_peek(typval_T *argvars, typval_T *rettv);
332static void f_remote_read(typval_T *argvars, typval_T *rettv);
333static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100334static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200335static void f_remove(typval_T *argvars, typval_T *rettv);
336static void f_rename(typval_T *argvars, typval_T *rettv);
337static void f_repeat(typval_T *argvars, typval_T *rettv);
338static void f_resolve(typval_T *argvars, typval_T *rettv);
339static void f_reverse(typval_T *argvars, typval_T *rettv);
340#ifdef FEAT_FLOAT
341static void f_round(typval_T *argvars, typval_T *rettv);
342#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100343#ifdef FEAT_RUBY
344static void f_rubyeval(typval_T *argvars, typval_T *rettv);
345#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200346static void f_screenattr(typval_T *argvars, typval_T *rettv);
347static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100348static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200349static void f_screencol(typval_T *argvars, typval_T *rettv);
350static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100351static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352static void f_search(typval_T *argvars, typval_T *rettv);
353static void f_searchdecl(typval_T *argvars, typval_T *rettv);
354static void f_searchpair(typval_T *argvars, typval_T *rettv);
355static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
356static void f_searchpos(typval_T *argvars, typval_T *rettv);
357static void f_server2client(typval_T *argvars, typval_T *rettv);
358static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200359static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200360static void f_setbufvar(typval_T *argvars, typval_T *rettv);
361static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
362static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
363static void f_setfperm(typval_T *argvars, typval_T *rettv);
364static void f_setline(typval_T *argvars, typval_T *rettv);
365static void f_setloclist(typval_T *argvars, typval_T *rettv);
366static void f_setmatches(typval_T *argvars, typval_T *rettv);
367static void f_setpos(typval_T *argvars, typval_T *rettv);
368static void f_setqflist(typval_T *argvars, typval_T *rettv);
369static void f_setreg(typval_T *argvars, typval_T *rettv);
370static void f_settabvar(typval_T *argvars, typval_T *rettv);
371static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100372static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200373static void f_setwinvar(typval_T *argvars, typval_T *rettv);
374#ifdef FEAT_CRYPT
375static void f_sha256(typval_T *argvars, typval_T *rettv);
376#endif /* FEAT_CRYPT */
377static void f_shellescape(typval_T *argvars, typval_T *rettv);
378static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100379#ifdef FEAT_SIGNS
380static void f_sign_define(typval_T *argvars, typval_T *rettv);
381static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
382static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100383static void f_sign_jump(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100384static void f_sign_place(typval_T *argvars, typval_T *rettv);
385static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
386static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
387#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200388static void f_simplify(typval_T *argvars, typval_T *rettv);
389#ifdef FEAT_FLOAT
390static void f_sin(typval_T *argvars, typval_T *rettv);
391static void f_sinh(typval_T *argvars, typval_T *rettv);
392#endif
393static void f_sort(typval_T *argvars, typval_T *rettv);
394static void f_soundfold(typval_T *argvars, typval_T *rettv);
395static void f_spellbadword(typval_T *argvars, typval_T *rettv);
396static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
397static void f_split(typval_T *argvars, typval_T *rettv);
398#ifdef FEAT_FLOAT
399static void f_sqrt(typval_T *argvars, typval_T *rettv);
400static void f_str2float(typval_T *argvars, typval_T *rettv);
401#endif
402static void f_str2nr(typval_T *argvars, typval_T *rettv);
403static void f_strchars(typval_T *argvars, typval_T *rettv);
404#ifdef HAVE_STRFTIME
405static void f_strftime(typval_T *argvars, typval_T *rettv);
406#endif
407static void f_strgetchar(typval_T *argvars, typval_T *rettv);
408static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409static void f_strlen(typval_T *argvars, typval_T *rettv);
410static void f_strcharpart(typval_T *argvars, typval_T *rettv);
411static void f_strpart(typval_T *argvars, typval_T *rettv);
412static void f_strridx(typval_T *argvars, typval_T *rettv);
413static void f_strtrans(typval_T *argvars, typval_T *rettv);
414static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
415static void f_strwidth(typval_T *argvars, typval_T *rettv);
416static void f_submatch(typval_T *argvars, typval_T *rettv);
417static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200418static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200419static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200420static void f_synID(typval_T *argvars, typval_T *rettv);
421static void f_synIDattr(typval_T *argvars, typval_T *rettv);
422static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
423static void f_synstack(typval_T *argvars, typval_T *rettv);
424static void f_synconcealed(typval_T *argvars, typval_T *rettv);
425static void f_system(typval_T *argvars, typval_T *rettv);
426static void f_systemlist(typval_T *argvars, typval_T *rettv);
427static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
428static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
429static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
430static void f_taglist(typval_T *argvars, typval_T *rettv);
431static void f_tagfiles(typval_T *argvars, typval_T *rettv);
432static void f_tempname(typval_T *argvars, typval_T *rettv);
433static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
434static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200435static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200436static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100437static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100438static void f_test_refcount(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100440static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100441static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200442#ifdef FEAT_JOB_CHANNEL
443static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
444#endif
445static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
446#ifdef FEAT_JOB_CHANNEL
447static void f_test_null_job(typval_T *argvars, typval_T *rettv);
448#endif
449static void f_test_null_list(typval_T *argvars, typval_T *rettv);
450static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
451static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200452#ifdef FEAT_GUI
453static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
454#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200455static void f_test_settime(typval_T *argvars, typval_T *rettv);
456#ifdef FEAT_FLOAT
457static void f_tan(typval_T *argvars, typval_T *rettv);
458static void f_tanh(typval_T *argvars, typval_T *rettv);
459#endif
460#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200461static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200462static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200463static void f_timer_start(typval_T *argvars, typval_T *rettv);
464static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200465static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200466#endif
467static void f_tolower(typval_T *argvars, typval_T *rettv);
468static void f_toupper(typval_T *argvars, typval_T *rettv);
469static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100470static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200471#ifdef FEAT_FLOAT
472static void f_trunc(typval_T *argvars, typval_T *rettv);
473#endif
474static void f_type(typval_T *argvars, typval_T *rettv);
475static void f_undofile(typval_T *argvars, typval_T *rettv);
476static void f_undotree(typval_T *argvars, typval_T *rettv);
477static void f_uniq(typval_T *argvars, typval_T *rettv);
478static void f_values(typval_T *argvars, typval_T *rettv);
479static void f_virtcol(typval_T *argvars, typval_T *rettv);
480static void f_visualmode(typval_T *argvars, typval_T *rettv);
481static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
482static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
483static void f_win_getid(typval_T *argvars, typval_T *rettv);
484static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
485static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
486static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100487static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200488static void f_winbufnr(typval_T *argvars, typval_T *rettv);
489static void f_wincol(typval_T *argvars, typval_T *rettv);
490static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200491static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200492static void f_winline(typval_T *argvars, typval_T *rettv);
493static void f_winnr(typval_T *argvars, typval_T *rettv);
494static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
495static void f_winrestview(typval_T *argvars, typval_T *rettv);
496static void f_winsaveview(typval_T *argvars, typval_T *rettv);
497static void f_winwidth(typval_T *argvars, typval_T *rettv);
498static void f_writefile(typval_T *argvars, typval_T *rettv);
499static void f_wordcount(typval_T *argvars, typval_T *rettv);
500static void f_xor(typval_T *argvars, typval_T *rettv);
501
502/*
503 * Array with names and number of arguments of all internal functions
504 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
505 */
506static struct fst
507{
508 char *f_name; /* function name */
509 char f_min_argc; /* minimal number of arguments */
510 char f_max_argc; /* maximal number of arguments */
511 void (*f_func)(typval_T *args, typval_T *rvar);
512 /* implementation of function */
513} functions[] =
514{
515#ifdef FEAT_FLOAT
516 {"abs", 1, 1, f_abs},
517 {"acos", 1, 1, f_acos}, /* WJMc */
518#endif
519 {"add", 2, 2, f_add},
520 {"and", 2, 2, f_and},
521 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200522 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200523 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200524 {"argidx", 0, 0, f_argidx},
525 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200526 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527#ifdef FEAT_FLOAT
528 {"asin", 1, 1, f_asin}, /* WJMc */
529#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100530 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200531 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100532 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200534 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200535 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100536 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537 {"assert_match", 2, 3, f_assert_match},
538 {"assert_notequal", 2, 3, f_assert_notequal},
539 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100540 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200541 {"assert_true", 1, 2, f_assert_true},
542#ifdef FEAT_FLOAT
543 {"atan", 1, 1, f_atan},
544 {"atan2", 2, 2, f_atan2},
545#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100546#ifdef FEAT_BEVAL
547 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100548# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100549 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100550# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100551#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200552 {"browse", 4, 4, f_browse},
553 {"browsedir", 2, 2, f_browsedir},
554 {"bufexists", 1, 1, f_bufexists},
555 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
556 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
557 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
558 {"buflisted", 1, 1, f_buflisted},
559 {"bufloaded", 1, 1, f_bufloaded},
560 {"bufname", 1, 1, f_bufname},
561 {"bufnr", 1, 2, f_bufnr},
562 {"bufwinid", 1, 1, f_bufwinid},
563 {"bufwinnr", 1, 1, f_bufwinnr},
564 {"byte2line", 1, 1, f_byte2line},
565 {"byteidx", 2, 2, f_byteidx},
566 {"byteidxcomp", 2, 2, f_byteidxcomp},
567 {"call", 2, 3, f_call},
568#ifdef FEAT_FLOAT
569 {"ceil", 1, 1, f_ceil},
570#endif
571#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100572 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200573 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200574 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200575 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
576 {"ch_evalraw", 2, 3, f_ch_evalraw},
577 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
578 {"ch_getjob", 1, 1, f_ch_getjob},
579 {"ch_info", 1, 1, f_ch_info},
580 {"ch_log", 1, 2, f_ch_log},
581 {"ch_logfile", 1, 2, f_ch_logfile},
582 {"ch_open", 1, 2, f_ch_open},
583 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100584 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200585 {"ch_readraw", 1, 2, f_ch_readraw},
586 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
587 {"ch_sendraw", 2, 3, f_ch_sendraw},
588 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200589 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200590#endif
591 {"changenr", 0, 0, f_changenr},
592 {"char2nr", 1, 2, f_char2nr},
593 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100594 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200595 {"col", 1, 1, f_col},
596#if defined(FEAT_INS_EXPAND)
597 {"complete", 2, 2, f_complete},
598 {"complete_add", 1, 1, f_complete_add},
599 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100600 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
602 {"confirm", 1, 4, f_confirm},
603 {"copy", 1, 1, f_copy},
604#ifdef FEAT_FLOAT
605 {"cos", 1, 1, f_cos},
606 {"cosh", 1, 1, f_cosh},
607#endif
608 {"count", 2, 4, f_count},
609 {"cscope_connection",0,3, f_cscope_connection},
610 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100611#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200612 {"debugbreak", 1, 1, f_debugbreak},
613#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200614 {"deepcopy", 1, 2, f_deepcopy},
615 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200616 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200617 {"did_filetype", 0, 0, f_did_filetype},
618 {"diff_filler", 1, 1, f_diff_filler},
619 {"diff_hlID", 2, 2, f_diff_hlID},
620 {"empty", 1, 1, f_empty},
621 {"escape", 2, 2, f_escape},
622 {"eval", 1, 1, f_eval},
623 {"eventhandler", 0, 0, f_eventhandler},
624 {"executable", 1, 1, f_executable},
625 {"execute", 1, 2, f_execute},
626 {"exepath", 1, 1, f_exepath},
627 {"exists", 1, 1, f_exists},
628#ifdef FEAT_FLOAT
629 {"exp", 1, 1, f_exp},
630#endif
631 {"expand", 1, 3, f_expand},
632 {"extend", 2, 3, f_extend},
633 {"feedkeys", 1, 2, f_feedkeys},
634 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
635 {"filereadable", 1, 1, f_filereadable},
636 {"filewritable", 1, 1, f_filewritable},
637 {"filter", 2, 2, f_filter},
638 {"finddir", 1, 3, f_finddir},
639 {"findfile", 1, 3, f_findfile},
640#ifdef FEAT_FLOAT
641 {"float2nr", 1, 1, f_float2nr},
642 {"floor", 1, 1, f_floor},
643 {"fmod", 2, 2, f_fmod},
644#endif
645 {"fnameescape", 1, 1, f_fnameescape},
646 {"fnamemodify", 2, 2, f_fnamemodify},
647 {"foldclosed", 1, 1, f_foldclosed},
648 {"foldclosedend", 1, 1, f_foldclosedend},
649 {"foldlevel", 1, 1, f_foldlevel},
650 {"foldtext", 0, 0, f_foldtext},
651 {"foldtextresult", 1, 1, f_foldtextresult},
652 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200653 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200654 {"function", 1, 3, f_function},
655 {"garbagecollect", 0, 1, f_garbagecollect},
656 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200657 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658 {"getbufline", 2, 3, f_getbufline},
659 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100660 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200661 {"getchar", 0, 1, f_getchar},
662 {"getcharmod", 0, 0, f_getcharmod},
663 {"getcharsearch", 0, 0, f_getcharsearch},
664 {"getcmdline", 0, 0, f_getcmdline},
665 {"getcmdpos", 0, 0, f_getcmdpos},
666 {"getcmdtype", 0, 0, f_getcmdtype},
667 {"getcmdwintype", 0, 0, f_getcmdwintype},
668#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200669 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200670#endif
671 {"getcurpos", 0, 0, f_getcurpos},
672 {"getcwd", 0, 2, f_getcwd},
673 {"getfontname", 0, 1, f_getfontname},
674 {"getfperm", 1, 1, f_getfperm},
675 {"getfsize", 1, 1, f_getfsize},
676 {"getftime", 1, 1, f_getftime},
677 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100678 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200679 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200680 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100681 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200682 {"getpid", 0, 0, f_getpid},
683 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200684 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685 {"getreg", 0, 3, f_getreg},
686 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200687 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688 {"gettabvar", 2, 3, f_gettabvar},
689 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100690 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200691 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100692 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693 {"getwinposx", 0, 0, f_getwinposx},
694 {"getwinposy", 0, 0, f_getwinposy},
695 {"getwinvar", 2, 3, f_getwinvar},
696 {"glob", 1, 4, f_glob},
697 {"glob2regpat", 1, 1, f_glob2regpat},
698 {"globpath", 2, 5, f_globpath},
699 {"has", 1, 1, f_has},
700 {"has_key", 2, 2, f_has_key},
701 {"haslocaldir", 0, 2, f_haslocaldir},
702 {"hasmapto", 1, 3, f_hasmapto},
703 {"highlightID", 1, 1, f_hlID}, /* obsolete */
704 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
705 {"histadd", 2, 2, f_histadd},
706 {"histdel", 1, 2, f_histdel},
707 {"histget", 1, 2, f_histget},
708 {"histnr", 1, 1, f_histnr},
709 {"hlID", 1, 1, f_hlID},
710 {"hlexists", 1, 1, f_hlexists},
711 {"hostname", 0, 0, f_hostname},
712 {"iconv", 3, 3, f_iconv},
713 {"indent", 1, 1, f_indent},
714 {"index", 2, 4, f_index},
715 {"input", 1, 3, f_input},
716 {"inputdialog", 1, 3, f_inputdialog},
717 {"inputlist", 1, 1, f_inputlist},
718 {"inputrestore", 0, 0, f_inputrestore},
719 {"inputsave", 0, 0, f_inputsave},
720 {"inputsecret", 1, 2, f_inputsecret},
721 {"insert", 2, 3, f_insert},
722 {"invert", 1, 1, f_invert},
723 {"isdirectory", 1, 1, f_isdirectory},
724 {"islocked", 1, 1, f_islocked},
725#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
726 {"isnan", 1, 1, f_isnan},
727#endif
728 {"items", 1, 1, f_items},
729#ifdef FEAT_JOB_CHANNEL
730 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200731 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200732 {"job_setoptions", 2, 2, f_job_setoptions},
733 {"job_start", 1, 2, f_job_start},
734 {"job_status", 1, 1, f_job_status},
735 {"job_stop", 1, 2, f_job_stop},
736#endif
737 {"join", 1, 2, f_join},
738 {"js_decode", 1, 1, f_js_decode},
739 {"js_encode", 1, 1, f_js_encode},
740 {"json_decode", 1, 1, f_json_decode},
741 {"json_encode", 1, 1, f_json_encode},
742 {"keys", 1, 1, f_keys},
743 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
744 {"len", 1, 1, f_len},
745 {"libcall", 3, 3, f_libcall},
746 {"libcallnr", 3, 3, f_libcallnr},
747 {"line", 1, 1, f_line},
748 {"line2byte", 1, 1, f_line2byte},
749 {"lispindent", 1, 1, f_lispindent},
750 {"localtime", 0, 0, f_localtime},
751#ifdef FEAT_FLOAT
752 {"log", 1, 1, f_log},
753 {"log10", 1, 1, f_log10},
754#endif
755#ifdef FEAT_LUA
756 {"luaeval", 1, 2, f_luaeval},
757#endif
758 {"map", 2, 2, f_map},
759 {"maparg", 1, 4, f_maparg},
760 {"mapcheck", 1, 3, f_mapcheck},
761 {"match", 2, 4, f_match},
762 {"matchadd", 2, 5, f_matchadd},
763 {"matchaddpos", 2, 5, f_matchaddpos},
764 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100765 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200766 {"matchend", 2, 4, f_matchend},
767 {"matchlist", 2, 4, f_matchlist},
768 {"matchstr", 2, 4, f_matchstr},
769 {"matchstrpos", 2, 4, f_matchstrpos},
770 {"max", 1, 1, f_max},
771 {"min", 1, 1, f_min},
772#ifdef vim_mkdir
773 {"mkdir", 1, 3, f_mkdir},
774#endif
775 {"mode", 0, 1, f_mode},
776#ifdef FEAT_MZSCHEME
777 {"mzeval", 1, 1, f_mzeval},
778#endif
779 {"nextnonblank", 1, 1, f_nextnonblank},
780 {"nr2char", 1, 2, f_nr2char},
781 {"or", 2, 2, f_or},
782 {"pathshorten", 1, 1, f_pathshorten},
783#ifdef FEAT_PERL
784 {"perleval", 1, 1, f_perleval},
785#endif
786#ifdef FEAT_FLOAT
787 {"pow", 2, 2, f_pow},
788#endif
789 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100790 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200791#ifdef FEAT_JOB_CHANNEL
792 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200793 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200794 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
795#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100796#ifdef FEAT_TEXT_PROP
797 {"prop_add", 3, 3, f_prop_add},
798 {"prop_clear", 1, 3, f_prop_clear},
799 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100800 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100801 {"prop_type_add", 2, 2, f_prop_type_add},
802 {"prop_type_change", 2, 2, f_prop_type_change},
803 {"prop_type_delete", 1, 2, f_prop_type_delete},
804 {"prop_type_get", 1, 2, f_prop_type_get},
805 {"prop_type_list", 0, 1, f_prop_type_list},
806#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807 {"pumvisible", 0, 0, f_pumvisible},
808#ifdef FEAT_PYTHON3
809 {"py3eval", 1, 1, f_py3eval},
810#endif
811#ifdef FEAT_PYTHON
812 {"pyeval", 1, 1, f_pyeval},
813#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100814#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
815 {"pyxeval", 1, 1, f_pyxeval},
816#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817 {"range", 1, 3, f_range},
818 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200819 {"reg_executing", 0, 0, f_reg_executing},
820 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821 {"reltime", 0, 2, f_reltime},
822#ifdef FEAT_FLOAT
823 {"reltimefloat", 1, 1, f_reltimefloat},
824#endif
825 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100826 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827 {"remote_foreground", 1, 1, f_remote_foreground},
828 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100829 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200830 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100831 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200832 {"remove", 2, 3, f_remove},
833 {"rename", 2, 2, f_rename},
834 {"repeat", 2, 2, f_repeat},
835 {"resolve", 1, 1, f_resolve},
836 {"reverse", 1, 1, f_reverse},
837#ifdef FEAT_FLOAT
838 {"round", 1, 1, f_round},
839#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100840#ifdef FEAT_RUBY
841 {"rubyeval", 1, 1, f_rubyeval},
842#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200843 {"screenattr", 2, 2, f_screenattr},
844 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100845 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200846 {"screencol", 0, 0, f_screencol},
847 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100848 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849 {"search", 1, 4, f_search},
850 {"searchdecl", 1, 3, f_searchdecl},
851 {"searchpair", 3, 7, f_searchpair},
852 {"searchpairpos", 3, 7, f_searchpairpos},
853 {"searchpos", 1, 4, f_searchpos},
854 {"server2client", 2, 2, f_server2client},
855 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200856 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200857 {"setbufvar", 3, 3, f_setbufvar},
858 {"setcharsearch", 1, 1, f_setcharsearch},
859 {"setcmdpos", 1, 1, f_setcmdpos},
860 {"setfperm", 2, 2, f_setfperm},
861 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200862 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100863 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200864 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200865 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200866 {"setreg", 2, 3, f_setreg},
867 {"settabvar", 3, 3, f_settabvar},
868 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100869 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200870 {"setwinvar", 3, 3, f_setwinvar},
871#ifdef FEAT_CRYPT
872 {"sha256", 1, 1, f_sha256},
873#endif
874 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100875 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100876#ifdef FEAT_SIGNS
877 {"sign_define", 1, 2, f_sign_define},
878 {"sign_getdefined", 0, 1, f_sign_getdefined},
879 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100880 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100881 {"sign_place", 4, 5, f_sign_place},
882 {"sign_undefine", 0, 1, f_sign_undefine},
883 {"sign_unplace", 1, 2, f_sign_unplace},
884#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200885 {"simplify", 1, 1, f_simplify},
886#ifdef FEAT_FLOAT
887 {"sin", 1, 1, f_sin},
888 {"sinh", 1, 1, f_sinh},
889#endif
890 {"sort", 1, 3, f_sort},
891 {"soundfold", 1, 1, f_soundfold},
892 {"spellbadword", 0, 1, f_spellbadword},
893 {"spellsuggest", 1, 3, f_spellsuggest},
894 {"split", 1, 3, f_split},
895#ifdef FEAT_FLOAT
896 {"sqrt", 1, 1, f_sqrt},
897 {"str2float", 1, 1, f_str2float},
898#endif
899 {"str2nr", 1, 2, f_str2nr},
900 {"strcharpart", 2, 3, f_strcharpart},
901 {"strchars", 1, 2, f_strchars},
902 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
903#ifdef HAVE_STRFTIME
904 {"strftime", 1, 2, f_strftime},
905#endif
906 {"strgetchar", 2, 2, f_strgetchar},
907 {"stridx", 2, 3, f_stridx},
908 {"string", 1, 1, f_string},
909 {"strlen", 1, 1, f_strlen},
910 {"strpart", 2, 3, f_strpart},
911 {"strridx", 2, 3, f_strridx},
912 {"strtrans", 1, 1, f_strtrans},
913 {"strwidth", 1, 1, f_strwidth},
914 {"submatch", 1, 2, f_submatch},
915 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200916 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200917 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918 {"synID", 3, 3, f_synID},
919 {"synIDattr", 2, 3, f_synIDattr},
920 {"synIDtrans", 1, 1, f_synIDtrans},
921 {"synconcealed", 2, 2, f_synconcealed},
922 {"synstack", 2, 2, f_synstack},
923 {"system", 1, 2, f_system},
924 {"systemlist", 1, 2, f_systemlist},
925 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
926 {"tabpagenr", 0, 1, f_tabpagenr},
927 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
928 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100929 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200930#ifdef FEAT_FLOAT
931 {"tan", 1, 1, f_tan},
932 {"tanh", 1, 1, f_tanh},
933#endif
934 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200935#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100936 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
937 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100938 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200939 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200940# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
941 {"term_getansicolors", 1, 1, f_term_getansicolors},
942# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200943 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200944 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200945 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200946 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200947 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200948 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200949 {"term_getstatus", 1, 1, f_term_getstatus},
950 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200951 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200952 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200953 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200954 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200955# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
956 {"term_setansicolors", 2, 2, f_term_setansicolors},
957# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100958 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100959 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200960 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200961 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200962 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200963#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200964 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
965 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200966 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200967 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100968 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100969 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200970#ifdef FEAT_JOB_CHANNEL
971 {"test_null_channel", 0, 0, f_test_null_channel},
972#endif
973 {"test_null_dict", 0, 0, f_test_null_dict},
974#ifdef FEAT_JOB_CHANNEL
975 {"test_null_job", 0, 0, f_test_null_job},
976#endif
977 {"test_null_list", 0, 0, f_test_null_list},
978 {"test_null_partial", 0, 0, f_test_null_partial},
979 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200980 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100981 {"test_override", 2, 2, f_test_override},
982 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200983#ifdef FEAT_GUI
984 {"test_scrollbar", 3, 3, f_test_scrollbar},
985#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200986 {"test_settime", 1, 1, f_test_settime},
987#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200988 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200989 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200990 {"timer_start", 2, 3, f_timer_start},
991 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200992 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200993#endif
994 {"tolower", 1, 1, f_tolower},
995 {"toupper", 1, 1, f_toupper},
996 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100997 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200998#ifdef FEAT_FLOAT
999 {"trunc", 1, 1, f_trunc},
1000#endif
1001 {"type", 1, 1, f_type},
1002 {"undofile", 1, 1, f_undofile},
1003 {"undotree", 0, 0, f_undotree},
1004 {"uniq", 1, 3, f_uniq},
1005 {"values", 1, 1, f_values},
1006 {"virtcol", 1, 1, f_virtcol},
1007 {"visualmode", 0, 1, f_visualmode},
1008 {"wildmenumode", 0, 0, f_wildmenumode},
1009 {"win_findbuf", 1, 1, f_win_findbuf},
1010 {"win_getid", 0, 2, f_win_getid},
1011 {"win_gotoid", 1, 1, f_win_gotoid},
1012 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1013 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001014 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001015 {"winbufnr", 1, 1, f_winbufnr},
1016 {"wincol", 0, 0, f_wincol},
1017 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001018 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019 {"winline", 0, 0, f_winline},
1020 {"winnr", 0, 1, f_winnr},
1021 {"winrestcmd", 0, 0, f_winrestcmd},
1022 {"winrestview", 1, 1, f_winrestview},
1023 {"winsaveview", 0, 0, f_winsaveview},
1024 {"winwidth", 1, 1, f_winwidth},
1025 {"wordcount", 0, 0, f_wordcount},
1026 {"writefile", 2, 3, f_writefile},
1027 {"xor", 2, 2, f_xor},
1028};
1029
1030#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1031
1032/*
1033 * Function given to ExpandGeneric() to obtain the list of internal
1034 * or user defined function names.
1035 */
1036 char_u *
1037get_function_name(expand_T *xp, int idx)
1038{
1039 static int intidx = -1;
1040 char_u *name;
1041
1042 if (idx == 0)
1043 intidx = -1;
1044 if (intidx < 0)
1045 {
1046 name = get_user_func_name(xp, idx);
1047 if (name != NULL)
1048 return name;
1049 }
1050 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1051 {
1052 STRCPY(IObuff, functions[intidx].f_name);
1053 STRCAT(IObuff, "(");
1054 if (functions[intidx].f_max_argc == 0)
1055 STRCAT(IObuff, ")");
1056 return IObuff;
1057 }
1058
1059 return NULL;
1060}
1061
1062/*
1063 * Function given to ExpandGeneric() to obtain the list of internal or
1064 * user defined variable or function names.
1065 */
1066 char_u *
1067get_expr_name(expand_T *xp, int idx)
1068{
1069 static int intidx = -1;
1070 char_u *name;
1071
1072 if (idx == 0)
1073 intidx = -1;
1074 if (intidx < 0)
1075 {
1076 name = get_function_name(xp, idx);
1077 if (name != NULL)
1078 return name;
1079 }
1080 return get_user_var_name(xp, ++intidx);
1081}
1082
1083#endif /* FEAT_CMDL_COMPL */
1084
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001085/*
1086 * Find internal function in table above.
1087 * Return index, or -1 if not found
1088 */
1089 int
1090find_internal_func(
1091 char_u *name) /* name of the function */
1092{
1093 int first = 0;
1094 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1095 int cmp;
1096 int x;
1097
1098 /*
1099 * Find the function name in the table. Binary search.
1100 */
1101 while (first <= last)
1102 {
1103 x = first + ((unsigned)(last - first) >> 1);
1104 cmp = STRCMP(name, functions[x].f_name);
1105 if (cmp < 0)
1106 last = x - 1;
1107 else if (cmp > 0)
1108 first = x + 1;
1109 else
1110 return x;
1111 }
1112 return -1;
1113}
1114
1115 int
1116call_internal_func(
1117 char_u *name,
1118 int argcount,
1119 typval_T *argvars,
1120 typval_T *rettv)
1121{
1122 int i;
1123
1124 i = find_internal_func(name);
1125 if (i < 0)
1126 return ERROR_UNKNOWN;
1127 if (argcount < functions[i].f_min_argc)
1128 return ERROR_TOOFEW;
1129 if (argcount > functions[i].f_max_argc)
1130 return ERROR_TOOMANY;
1131 argvars[argcount].v_type = VAR_UNKNOWN;
1132 functions[i].f_func(argvars, rettv);
1133 return ERROR_NONE;
1134}
1135
1136/*
1137 * Return TRUE for a non-zero Number and a non-empty String.
1138 */
1139 static int
1140non_zero_arg(typval_T *argvars)
1141{
1142 return ((argvars[0].v_type == VAR_NUMBER
1143 && argvars[0].vval.v_number != 0)
1144 || (argvars[0].v_type == VAR_SPECIAL
1145 && argvars[0].vval.v_number == VVAL_TRUE)
1146 || (argvars[0].v_type == VAR_STRING
1147 && argvars[0].vval.v_string != NULL
1148 && *argvars[0].vval.v_string != NUL));
1149}
1150
1151/*
1152 * Get the lnum from the first argument.
1153 * Also accepts ".", "$", etc., but that only works for the current buffer.
1154 * Returns -1 on error.
1155 */
1156 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001157tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001158{
1159 typval_T rettv;
1160 linenr_T lnum;
1161
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001162 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001163 if (lnum == 0) /* no valid number, try using line() */
1164 {
1165 rettv.v_type = VAR_NUMBER;
1166 f_line(argvars, &rettv);
1167 lnum = (linenr_T)rettv.vval.v_number;
1168 clear_tv(&rettv);
1169 }
1170 return lnum;
1171}
1172
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001173/*
1174 * Get the lnum from the first argument.
1175 * Also accepts "$", then "buf" is used.
1176 * Returns 0 on error.
1177 */
1178 static linenr_T
1179tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1180{
1181 if (argvars[0].v_type == VAR_STRING
1182 && argvars[0].vval.v_string != NULL
1183 && argvars[0].vval.v_string[0] == '$'
1184 && buf != NULL)
1185 return buf->b_ml.ml_line_count;
1186 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1187}
1188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001189#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001190/*
1191 * Get the float value of "argvars[0]" into "f".
1192 * Returns FAIL when the argument is not a Number or Float.
1193 */
1194 static int
1195get_float_arg(typval_T *argvars, float_T *f)
1196{
1197 if (argvars[0].v_type == VAR_FLOAT)
1198 {
1199 *f = argvars[0].vval.v_float;
1200 return OK;
1201 }
1202 if (argvars[0].v_type == VAR_NUMBER)
1203 {
1204 *f = (float_T)argvars[0].vval.v_number;
1205 return OK;
1206 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001207 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001208 return FAIL;
1209}
1210
1211/*
1212 * "abs(expr)" function
1213 */
1214 static void
1215f_abs(typval_T *argvars, typval_T *rettv)
1216{
1217 if (argvars[0].v_type == VAR_FLOAT)
1218 {
1219 rettv->v_type = VAR_FLOAT;
1220 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1221 }
1222 else
1223 {
1224 varnumber_T n;
1225 int error = FALSE;
1226
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001227 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001228 if (error)
1229 rettv->vval.v_number = -1;
1230 else if (n > 0)
1231 rettv->vval.v_number = n;
1232 else
1233 rettv->vval.v_number = -n;
1234 }
1235}
1236
1237/*
1238 * "acos()" function
1239 */
1240 static void
1241f_acos(typval_T *argvars, typval_T *rettv)
1242{
1243 float_T f = 0.0;
1244
1245 rettv->v_type = VAR_FLOAT;
1246 if (get_float_arg(argvars, &f) == OK)
1247 rettv->vval.v_float = acos(f);
1248 else
1249 rettv->vval.v_float = 0.0;
1250}
1251#endif
1252
1253/*
1254 * "add(list, item)" function
1255 */
1256 static void
1257f_add(typval_T *argvars, typval_T *rettv)
1258{
1259 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001260 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001261
1262 rettv->vval.v_number = 1; /* Default: Failed */
1263 if (argvars[0].v_type == VAR_LIST)
1264 {
1265 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001266 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001267 (char_u *)N_("add() argument"), TRUE)
1268 && list_append_tv(l, &argvars[1]) == OK)
1269 copy_tv(&argvars[0], rettv);
1270 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001271 else if (argvars[0].v_type == VAR_BLOB)
1272 {
1273 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001274 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001275 (char_u *)N_("add() argument"), TRUE))
1276 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001277 int error = FALSE;
1278 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1279
1280 if (!error)
1281 {
1282 ga_append(&b->bv_ga, (int)n);
1283 copy_tv(&argvars[0], rettv);
1284 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001285 }
1286 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001287 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001288 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001289}
1290
1291/*
1292 * "and(expr, expr)" function
1293 */
1294 static void
1295f_and(typval_T *argvars, typval_T *rettv)
1296{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001297 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1298 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001299}
1300
1301/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001302 * If there is a window for "curbuf", make it the current window.
1303 */
1304 static void
1305find_win_for_curbuf(void)
1306{
1307 wininfo_T *wip;
1308
1309 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1310 {
1311 if (wip->wi_win != NULL)
1312 {
1313 curwin = wip->wi_win;
1314 break;
1315 }
1316 }
1317}
1318
1319/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001320 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001321 */
1322 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001323set_buffer_lines(
1324 buf_T *buf,
1325 linenr_T lnum_arg,
1326 int append,
1327 typval_T *lines,
1328 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001329{
Bram Moolenaarca851592018-06-06 21:04:07 +02001330 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1331 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001332 list_T *l = NULL;
1333 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001334 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001335 linenr_T append_lnum;
1336 buf_T *curbuf_save = NULL;
1337 win_T *curwin_save = NULL;
1338 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001339
Bram Moolenaarca851592018-06-06 21:04:07 +02001340 /* When using the current buffer ml_mfp will be set if needed. Useful when
1341 * setline() is used on startup. For other buffers the buffer must be
1342 * loaded. */
1343 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001344 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001345 rettv->vval.v_number = 1; /* FAIL */
1346 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347 }
1348
Bram Moolenaarca851592018-06-06 21:04:07 +02001349 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001350 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001351 curbuf_save = curbuf;
1352 curwin_save = curwin;
1353 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001354 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001355 }
1356
1357 if (append)
1358 // appendbufline() uses the line number below which we insert
1359 append_lnum = lnum - 1;
1360 else
1361 // setbufline() uses the line number above which we insert, we only
1362 // append if it's below the last line
1363 append_lnum = curbuf->b_ml.ml_line_count;
1364
1365 if (lines->v_type == VAR_LIST)
1366 {
1367 l = lines->vval.v_list;
1368 li = l->lv_first;
1369 }
1370 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001371 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001372
1373 /* default result is zero == OK */
1374 for (;;)
1375 {
1376 if (l != NULL)
1377 {
1378 /* list argument, get next string */
1379 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001380 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001381 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382 li = li->li_next;
1383 }
1384
Bram Moolenaarca851592018-06-06 21:04:07 +02001385 rettv->vval.v_number = 1; /* FAIL */
1386 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1387 break;
1388
1389 /* When coming here from Insert mode, sync undo, so that this can be
1390 * undone separately from what was previously inserted. */
1391 if (u_sync_once == 2)
1392 {
1393 u_sync_once = 1; /* notify that u_sync() was called */
1394 u_sync(TRUE);
1395 }
1396
1397 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1398 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001399 // Existing line, replace it.
1400 // Removes any existing text properties.
1401 if (u_savesub(lnum) == OK && ml_replace_len(
1402 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001403 {
1404 changed_bytes(lnum, 0);
1405 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1406 check_cursor_col();
1407 rettv->vval.v_number = 0; /* OK */
1408 }
1409 }
1410 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1411 {
1412 /* append the line */
1413 ++added;
1414 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1415 rettv->vval.v_number = 0; /* OK */
1416 }
1417
1418 if (l == NULL) /* only one string argument */
1419 break;
1420 ++lnum;
1421 }
1422
1423 if (added > 0)
1424 {
1425 win_T *wp;
1426 tabpage_T *tp;
1427
1428 appended_lines_mark(append_lnum, added);
1429 FOR_ALL_TAB_WINDOWS(tp, wp)
1430 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1431 wp->w_cursor.lnum += added;
1432 check_cursor_col();
1433
Bram Moolenaarf2732452018-06-03 14:47:35 +02001434#ifdef FEAT_JOB_CHANNEL
1435 if (bt_prompt(curbuf) && (State & INSERT))
1436 // show the line with the prompt
1437 update_topline();
1438#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001439 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001440
1441 if (!is_curbuf)
1442 {
1443 curbuf = curbuf_save;
1444 curwin = curwin_save;
1445 }
1446}
1447
1448/*
1449 * "append(lnum, string/list)" function
1450 */
1451 static void
1452f_append(typval_T *argvars, typval_T *rettv)
1453{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001454 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001455
1456 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1457}
1458
1459/*
1460 * "appendbufline(buf, lnum, string/list)" function
1461 */
1462 static void
1463f_appendbufline(typval_T *argvars, typval_T *rettv)
1464{
1465 linenr_T lnum;
1466 buf_T *buf;
1467
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001468 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001469 if (buf == NULL)
1470 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001471 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001472 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001473 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001474 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1475 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001476}
1477
1478/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001479 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480 */
1481 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001482f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001484 win_T *wp;
1485
1486 if (argvars[0].v_type == VAR_UNKNOWN)
1487 // use the current window
1488 rettv->vval.v_number = ARGCOUNT;
1489 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001490 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001491 // use the global argument list
1492 rettv->vval.v_number = GARGCOUNT;
1493 else
1494 {
1495 // use the argument list of the specified window
1496 wp = find_win_by_nr_or_id(&argvars[0]);
1497 if (wp != NULL)
1498 rettv->vval.v_number = WARGCOUNT(wp);
1499 else
1500 rettv->vval.v_number = -1;
1501 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502}
1503
1504/*
1505 * "argidx()" function
1506 */
1507 static void
1508f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1509{
1510 rettv->vval.v_number = curwin->w_arg_idx;
1511}
1512
1513/*
1514 * "arglistid()" function
1515 */
1516 static void
1517f_arglistid(typval_T *argvars, typval_T *rettv)
1518{
1519 win_T *wp;
1520
1521 rettv->vval.v_number = -1;
1522 wp = find_tabwin(&argvars[0], &argvars[1]);
1523 if (wp != NULL)
1524 rettv->vval.v_number = wp->w_alist->id;
1525}
1526
1527/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001528 * Get the argument list for a given window
1529 */
1530 static void
1531get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1532{
1533 int idx;
1534
1535 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1536 for (idx = 0; idx < argcount; ++idx)
1537 list_append_string(rettv->vval.v_list,
1538 alist_name(&arglist[idx]), -1);
1539}
1540
1541/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542 * "argv(nr)" function
1543 */
1544 static void
1545f_argv(typval_T *argvars, typval_T *rettv)
1546{
1547 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001548 aentry_T *arglist = NULL;
1549 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001550
1551 if (argvars[0].v_type != VAR_UNKNOWN)
1552 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001553 if (argvars[1].v_type == VAR_UNKNOWN)
1554 {
1555 arglist = ARGLIST;
1556 argcount = ARGCOUNT;
1557 }
1558 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001559 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001560 {
1561 arglist = GARGLIST;
1562 argcount = GARGCOUNT;
1563 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001564 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001565 {
1566 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1567
1568 if (wp != NULL)
1569 {
1570 /* Use the argument list of the specified window */
1571 arglist = WARGLIST(wp);
1572 argcount = WARGCOUNT(wp);
1573 }
1574 }
1575
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001577 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001578 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001579 if (arglist != NULL && idx >= 0 && idx < argcount)
1580 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1581 else if (idx == -1)
1582 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001583 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001584 else
1585 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001586}
1587
1588/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001589 * "assert_beeps(cmd [, error])" function
1590 */
1591 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001592f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001593{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001594 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001595}
1596
1597/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001598 * "assert_equal(expected, actual[, msg])" function
1599 */
1600 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001601f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001602{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001603 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001604}
1605
1606/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001607 * "assert_equalfile(fname-one, fname-two)" function
1608 */
1609 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001610f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001611{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001612 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001613}
1614
1615/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616 * "assert_notequal(expected, actual[, msg])" function
1617 */
1618 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001619f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001620{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001621 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622}
1623
1624/*
1625 * "assert_exception(string[, msg])" function
1626 */
1627 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001628f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001629{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001630 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001631}
1632
1633/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001634 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001635 */
1636 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001637f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001638{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001639 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001640}
1641
1642/*
1643 * "assert_false(actual[, msg])" function
1644 */
1645 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001646f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001647{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001648 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649}
1650
1651/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001652 * "assert_inrange(lower, upper[, msg])" function
1653 */
1654 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001655f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001656{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001657 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001658}
1659
1660/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661 * "assert_match(pattern, actual[, msg])" function
1662 */
1663 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001664f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001665{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001666 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667}
1668
1669/*
1670 * "assert_notmatch(pattern, actual[, msg])" function
1671 */
1672 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001673f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001674{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001675 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001676}
1677
1678/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001679 * "assert_report(msg)" function
1680 */
1681 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001682f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001683{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001684 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001685}
1686
1687/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 * "assert_true(actual[, msg])" function
1689 */
1690 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001691f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001692{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001693 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001694}
1695
1696#ifdef FEAT_FLOAT
1697/*
1698 * "asin()" function
1699 */
1700 static void
1701f_asin(typval_T *argvars, typval_T *rettv)
1702{
1703 float_T f = 0.0;
1704
1705 rettv->v_type = VAR_FLOAT;
1706 if (get_float_arg(argvars, &f) == OK)
1707 rettv->vval.v_float = asin(f);
1708 else
1709 rettv->vval.v_float = 0.0;
1710}
1711
1712/*
1713 * "atan()" function
1714 */
1715 static void
1716f_atan(typval_T *argvars, typval_T *rettv)
1717{
1718 float_T f = 0.0;
1719
1720 rettv->v_type = VAR_FLOAT;
1721 if (get_float_arg(argvars, &f) == OK)
1722 rettv->vval.v_float = atan(f);
1723 else
1724 rettv->vval.v_float = 0.0;
1725}
1726
1727/*
1728 * "atan2()" function
1729 */
1730 static void
1731f_atan2(typval_T *argvars, typval_T *rettv)
1732{
1733 float_T fx = 0.0, fy = 0.0;
1734
1735 rettv->v_type = VAR_FLOAT;
1736 if (get_float_arg(argvars, &fx) == OK
1737 && get_float_arg(&argvars[1], &fy) == OK)
1738 rettv->vval.v_float = atan2(fx, fy);
1739 else
1740 rettv->vval.v_float = 0.0;
1741}
1742#endif
1743
1744/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001745 * "balloon_show()" function
1746 */
1747#ifdef FEAT_BEVAL
1748 static void
1749f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1750{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001751 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001752 {
1753 if (argvars[0].v_type == VAR_LIST
1754# ifdef FEAT_GUI
1755 && !gui.in_use
1756# endif
1757 )
1758 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1759 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001760 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001761 }
1762}
1763
Bram Moolenaar669a8282017-11-19 20:13:05 +01001764# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001765 static void
1766f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1767{
1768 if (rettv_list_alloc(rettv) == OK)
1769 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001770 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001771
1772 if (msg != NULL)
1773 {
1774 pumitem_T *array;
1775 int size = split_message(msg, &array);
1776 int i;
1777
1778 /* Skip the first and last item, they are always empty. */
1779 for (i = 1; i < size - 1; ++i)
1780 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001781 while (size > 0)
1782 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001783 vim_free(array);
1784 }
1785 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001786}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001787# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001788#endif
1789
1790/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001791 * "browse(save, title, initdir, default)" function
1792 */
1793 static void
1794f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1795{
1796#ifdef FEAT_BROWSE
1797 int save;
1798 char_u *title;
1799 char_u *initdir;
1800 char_u *defname;
1801 char_u buf[NUMBUFLEN];
1802 char_u buf2[NUMBUFLEN];
1803 int error = FALSE;
1804
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001805 save = (int)tv_get_number_chk(&argvars[0], &error);
1806 title = tv_get_string_chk(&argvars[1]);
1807 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1808 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001809
1810 if (error || title == NULL || initdir == NULL || defname == NULL)
1811 rettv->vval.v_string = NULL;
1812 else
1813 rettv->vval.v_string =
1814 do_browse(save ? BROWSE_SAVE : 0,
1815 title, defname, NULL, initdir, NULL, curbuf);
1816#else
1817 rettv->vval.v_string = NULL;
1818#endif
1819 rettv->v_type = VAR_STRING;
1820}
1821
1822/*
1823 * "browsedir(title, initdir)" function
1824 */
1825 static void
1826f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1827{
1828#ifdef FEAT_BROWSE
1829 char_u *title;
1830 char_u *initdir;
1831 char_u buf[NUMBUFLEN];
1832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001833 title = tv_get_string_chk(&argvars[0]);
1834 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835
1836 if (title == NULL || initdir == NULL)
1837 rettv->vval.v_string = NULL;
1838 else
1839 rettv->vval.v_string = do_browse(BROWSE_DIR,
1840 title, NULL, NULL, initdir, NULL, curbuf);
1841#else
1842 rettv->vval.v_string = NULL;
1843#endif
1844 rettv->v_type = VAR_STRING;
1845}
1846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001847/*
1848 * Find a buffer by number or exact name.
1849 */
1850 static buf_T *
1851find_buffer(typval_T *avar)
1852{
1853 buf_T *buf = NULL;
1854
1855 if (avar->v_type == VAR_NUMBER)
1856 buf = buflist_findnr((int)avar->vval.v_number);
1857 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1858 {
1859 buf = buflist_findname_exp(avar->vval.v_string);
1860 if (buf == NULL)
1861 {
1862 /* No full path name match, try a match with a URL or a "nofile"
1863 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001864 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001865 if (buf->b_fname != NULL
1866 && (path_with_url(buf->b_fname)
1867#ifdef FEAT_QUICKFIX
1868 || bt_nofile(buf)
1869#endif
1870 )
1871 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1872 break;
1873 }
1874 }
1875 return buf;
1876}
1877
1878/*
1879 * "bufexists(expr)" function
1880 */
1881 static void
1882f_bufexists(typval_T *argvars, typval_T *rettv)
1883{
1884 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1885}
1886
1887/*
1888 * "buflisted(expr)" function
1889 */
1890 static void
1891f_buflisted(typval_T *argvars, typval_T *rettv)
1892{
1893 buf_T *buf;
1894
1895 buf = find_buffer(&argvars[0]);
1896 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1897}
1898
1899/*
1900 * "bufloaded(expr)" function
1901 */
1902 static void
1903f_bufloaded(typval_T *argvars, typval_T *rettv)
1904{
1905 buf_T *buf;
1906
1907 buf = find_buffer(&argvars[0]);
1908 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1909}
1910
1911 buf_T *
1912buflist_find_by_name(char_u *name, int curtab_only)
1913{
1914 int save_magic;
1915 char_u *save_cpo;
1916 buf_T *buf;
1917
1918 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1919 save_magic = p_magic;
1920 p_magic = TRUE;
1921 save_cpo = p_cpo;
1922 p_cpo = (char_u *)"";
1923
1924 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1925 TRUE, FALSE, curtab_only));
1926
1927 p_magic = save_magic;
1928 p_cpo = save_cpo;
1929 return buf;
1930}
1931
1932/*
1933 * Get buffer by number or pattern.
1934 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001935 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001936tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001937{
1938 char_u *name = tv->vval.v_string;
1939 buf_T *buf;
1940
1941 if (tv->v_type == VAR_NUMBER)
1942 return buflist_findnr((int)tv->vval.v_number);
1943 if (tv->v_type != VAR_STRING)
1944 return NULL;
1945 if (name == NULL || *name == NUL)
1946 return curbuf;
1947 if (name[0] == '$' && name[1] == NUL)
1948 return lastbuf;
1949
1950 buf = buflist_find_by_name(name, curtab_only);
1951
1952 /* If not found, try expanding the name, like done for bufexists(). */
1953 if (buf == NULL)
1954 buf = find_buffer(tv);
1955
1956 return buf;
1957}
1958
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001959#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001960/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001961 * Get the buffer from "arg" and give an error and return NULL if it is not
1962 * valid.
1963 */
1964 static buf_T *
1965get_buf_arg(typval_T *arg)
1966{
1967 buf_T *buf;
1968
1969 ++emsg_off;
1970 buf = tv_get_buf(arg, FALSE);
1971 --emsg_off;
1972 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001973 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001974 return buf;
1975}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001976#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001977
1978/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001979 * "bufname(expr)" function
1980 */
1981 static void
1982f_bufname(typval_T *argvars, typval_T *rettv)
1983{
1984 buf_T *buf;
1985
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001986 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001988 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001989 rettv->v_type = VAR_STRING;
1990 if (buf != NULL && buf->b_fname != NULL)
1991 rettv->vval.v_string = vim_strsave(buf->b_fname);
1992 else
1993 rettv->vval.v_string = NULL;
1994 --emsg_off;
1995}
1996
1997/*
1998 * "bufnr(expr)" function
1999 */
2000 static void
2001f_bufnr(typval_T *argvars, typval_T *rettv)
2002{
2003 buf_T *buf;
2004 int error = FALSE;
2005 char_u *name;
2006
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002007 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002008 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002009 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 --emsg_off;
2011
2012 /* If the buffer isn't found and the second argument is not zero create a
2013 * new buffer. */
2014 if (buf == NULL
2015 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002016 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002017 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002018 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002019 && !error)
2020 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2021
2022 if (buf != NULL)
2023 rettv->vval.v_number = buf->b_fnum;
2024 else
2025 rettv->vval.v_number = -1;
2026}
2027
2028 static void
2029buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2030{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002031 win_T *wp;
2032 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002033 buf_T *buf;
2034
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002035 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002036 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002037 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002038 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039 {
2040 ++winnr;
2041 if (wp->w_buffer == buf)
2042 break;
2043 }
2044 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002045 --emsg_off;
2046}
2047
2048/*
2049 * "bufwinid(nr)" function
2050 */
2051 static void
2052f_bufwinid(typval_T *argvars, typval_T *rettv)
2053{
2054 buf_win_common(argvars, rettv, FALSE);
2055}
2056
2057/*
2058 * "bufwinnr(nr)" function
2059 */
2060 static void
2061f_bufwinnr(typval_T *argvars, typval_T *rettv)
2062{
2063 buf_win_common(argvars, rettv, TRUE);
2064}
2065
2066/*
2067 * "byte2line(byte)" function
2068 */
2069 static void
2070f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2071{
2072#ifndef FEAT_BYTEOFF
2073 rettv->vval.v_number = -1;
2074#else
2075 long boff = 0;
2076
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002077 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002078 if (boff < 0)
2079 rettv->vval.v_number = -1;
2080 else
2081 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2082 (linenr_T)0, &boff);
2083#endif
2084}
2085
2086 static void
2087byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2088{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002089 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002090 char_u *str;
2091 varnumber_T idx;
2092
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002093 str = tv_get_string_chk(&argvars[0]);
2094 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095 rettv->vval.v_number = -1;
2096 if (str == NULL || idx < 0)
2097 return;
2098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002099 t = str;
2100 for ( ; idx > 0; idx--)
2101 {
2102 if (*t == NUL) /* EOL reached */
2103 return;
2104 if (enc_utf8 && comp)
2105 t += utf_ptr2len(t);
2106 else
2107 t += (*mb_ptr2len)(t);
2108 }
2109 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002110}
2111
2112/*
2113 * "byteidx()" function
2114 */
2115 static void
2116f_byteidx(typval_T *argvars, typval_T *rettv)
2117{
2118 byteidx(argvars, rettv, FALSE);
2119}
2120
2121/*
2122 * "byteidxcomp()" function
2123 */
2124 static void
2125f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2126{
2127 byteidx(argvars, rettv, TRUE);
2128}
2129
2130/*
2131 * "call(func, arglist [, dict])" function
2132 */
2133 static void
2134f_call(typval_T *argvars, typval_T *rettv)
2135{
2136 char_u *func;
2137 partial_T *partial = NULL;
2138 dict_T *selfdict = NULL;
2139
2140 if (argvars[1].v_type != VAR_LIST)
2141 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002142 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002143 return;
2144 }
2145 if (argvars[1].vval.v_list == NULL)
2146 return;
2147
2148 if (argvars[0].v_type == VAR_FUNC)
2149 func = argvars[0].vval.v_string;
2150 else if (argvars[0].v_type == VAR_PARTIAL)
2151 {
2152 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002153 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 }
2155 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002156 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002157 if (*func == NUL)
2158 return; /* type error or empty name */
2159
2160 if (argvars[2].v_type != VAR_UNKNOWN)
2161 {
2162 if (argvars[2].v_type != VAR_DICT)
2163 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002164 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002165 return;
2166 }
2167 selfdict = argvars[2].vval.v_dict;
2168 }
2169
2170 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2171}
2172
2173#ifdef FEAT_FLOAT
2174/*
2175 * "ceil({float})" function
2176 */
2177 static void
2178f_ceil(typval_T *argvars, typval_T *rettv)
2179{
2180 float_T f = 0.0;
2181
2182 rettv->v_type = VAR_FLOAT;
2183 if (get_float_arg(argvars, &f) == OK)
2184 rettv->vval.v_float = ceil(f);
2185 else
2186 rettv->vval.v_float = 0.0;
2187}
2188#endif
2189
2190#ifdef FEAT_JOB_CHANNEL
2191/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002192 * "ch_canread()" function
2193 */
2194 static void
2195f_ch_canread(typval_T *argvars, typval_T *rettv)
2196{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002197 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002198
2199 rettv->vval.v_number = 0;
2200 if (channel != NULL)
2201 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2202 || channel_has_readahead(channel, PART_OUT)
2203 || channel_has_readahead(channel, PART_ERR);
2204}
2205
2206/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207 * "ch_close()" function
2208 */
2209 static void
2210f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2211{
2212 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2213
2214 if (channel != NULL)
2215 {
2216 channel_close(channel, FALSE);
2217 channel_clear(channel);
2218 }
2219}
2220
2221/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002222 * "ch_close()" function
2223 */
2224 static void
2225f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2226{
2227 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2228
2229 if (channel != NULL)
2230 channel_close_in(channel);
2231}
2232
2233/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002234 * "ch_getbufnr()" function
2235 */
2236 static void
2237f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2238{
2239 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2240
2241 rettv->vval.v_number = -1;
2242 if (channel != NULL)
2243 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002244 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002245 int part;
2246
2247 if (STRCMP(what, "err") == 0)
2248 part = PART_ERR;
2249 else if (STRCMP(what, "out") == 0)
2250 part = PART_OUT;
2251 else if (STRCMP(what, "in") == 0)
2252 part = PART_IN;
2253 else
2254 part = PART_SOCK;
2255 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2256 rettv->vval.v_number =
2257 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2258 }
2259}
2260
2261/*
2262 * "ch_getjob()" function
2263 */
2264 static void
2265f_ch_getjob(typval_T *argvars, typval_T *rettv)
2266{
2267 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2268
2269 if (channel != NULL)
2270 {
2271 rettv->v_type = VAR_JOB;
2272 rettv->vval.v_job = channel->ch_job;
2273 if (channel->ch_job != NULL)
2274 ++channel->ch_job->jv_refcount;
2275 }
2276}
2277
2278/*
2279 * "ch_info()" function
2280 */
2281 static void
2282f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2283{
2284 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2285
2286 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2287 channel_info(channel, rettv->vval.v_dict);
2288}
2289
2290/*
2291 * "ch_log()" function
2292 */
2293 static void
2294f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2295{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002296 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 channel_T *channel = NULL;
2298
2299 if (argvars[1].v_type != VAR_UNKNOWN)
2300 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2301
Bram Moolenaard5359b22018-04-05 22:44:39 +02002302 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303}
2304
2305/*
2306 * "ch_logfile()" function
2307 */
2308 static void
2309f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2310{
2311 char_u *fname;
2312 char_u *opt = (char_u *)"";
2313 char_u buf[NUMBUFLEN];
2314
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002315 /* Don't open a file in restricted mode. */
2316 if (check_restricted() || check_secure())
2317 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002318 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002319 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002320 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002321 ch_logfile(fname, opt);
2322}
2323
2324/*
2325 * "ch_open()" function
2326 */
2327 static void
2328f_ch_open(typval_T *argvars, typval_T *rettv)
2329{
2330 rettv->v_type = VAR_CHANNEL;
2331 if (check_restricted() || check_secure())
2332 return;
2333 rettv->vval.v_channel = channel_open_func(argvars);
2334}
2335
2336/*
2337 * "ch_read()" function
2338 */
2339 static void
2340f_ch_read(typval_T *argvars, typval_T *rettv)
2341{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002342 common_channel_read(argvars, rettv, FALSE, FALSE);
2343}
2344
2345/*
2346 * "ch_readblob()" function
2347 */
2348 static void
2349f_ch_readblob(typval_T *argvars, typval_T *rettv)
2350{
2351 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002352}
2353
2354/*
2355 * "ch_readraw()" function
2356 */
2357 static void
2358f_ch_readraw(typval_T *argvars, typval_T *rettv)
2359{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002360 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002361}
2362
2363/*
2364 * "ch_evalexpr()" function
2365 */
2366 static void
2367f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2368{
2369 ch_expr_common(argvars, rettv, TRUE);
2370}
2371
2372/*
2373 * "ch_sendexpr()" function
2374 */
2375 static void
2376f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2377{
2378 ch_expr_common(argvars, rettv, FALSE);
2379}
2380
2381/*
2382 * "ch_evalraw()" function
2383 */
2384 static void
2385f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2386{
2387 ch_raw_common(argvars, rettv, TRUE);
2388}
2389
2390/*
2391 * "ch_sendraw()" function
2392 */
2393 static void
2394f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2395{
2396 ch_raw_common(argvars, rettv, FALSE);
2397}
2398
2399/*
2400 * "ch_setoptions()" function
2401 */
2402 static void
2403f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2404{
2405 channel_T *channel;
2406 jobopt_T opt;
2407
2408 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2409 if (channel == NULL)
2410 return;
2411 clear_job_options(&opt);
2412 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002413 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414 channel_set_options(channel, &opt);
2415 free_job_options(&opt);
2416}
2417
2418/*
2419 * "ch_status()" function
2420 */
2421 static void
2422f_ch_status(typval_T *argvars, typval_T *rettv)
2423{
2424 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002425 jobopt_T opt;
2426 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002427
2428 /* return an empty string by default */
2429 rettv->v_type = VAR_STRING;
2430 rettv->vval.v_string = NULL;
2431
2432 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002433
2434 if (argvars[1].v_type != VAR_UNKNOWN)
2435 {
2436 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002437 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002438 && (opt.jo_set & JO_PART))
2439 part = opt.jo_part;
2440 }
2441
2442 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002443}
2444#endif
2445
2446/*
2447 * "changenr()" function
2448 */
2449 static void
2450f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2451{
2452 rettv->vval.v_number = curbuf->b_u_seq_cur;
2453}
2454
2455/*
2456 * "char2nr(string)" function
2457 */
2458 static void
2459f_char2nr(typval_T *argvars, typval_T *rettv)
2460{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 if (has_mbyte)
2462 {
2463 int utf8 = 0;
2464
2465 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002466 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467
2468 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002469 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002470 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002471 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002472 }
2473 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002474 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002475}
2476
2477/*
2478 * "cindent(lnum)" function
2479 */
2480 static void
2481f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2482{
2483#ifdef FEAT_CINDENT
2484 pos_T pos;
2485 linenr_T lnum;
2486
2487 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002488 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002489 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2490 {
2491 curwin->w_cursor.lnum = lnum;
2492 rettv->vval.v_number = get_c_indent();
2493 curwin->w_cursor = pos;
2494 }
2495 else
2496#endif
2497 rettv->vval.v_number = -1;
2498}
2499
Bram Moolenaaraff74912019-03-30 18:11:49 +01002500 static win_T *
2501get_optional_window(typval_T *argvars, int idx)
2502{
2503 win_T *win = curwin;
2504
2505 if (argvars[idx].v_type != VAR_UNKNOWN)
2506 {
2507 win = find_win_by_nr_or_id(&argvars[idx]);
2508 if (win == NULL)
2509 {
2510 emsg(_(e_invalwindow));
2511 return NULL;
2512 }
2513 }
2514 return win;
2515}
2516
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517/*
2518 * "clearmatches()" function
2519 */
2520 static void
2521f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2522{
2523#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01002524 win_T *win = get_optional_window(argvars, 0);
2525
2526 if (win != NULL)
2527 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528#endif
2529}
2530
2531/*
2532 * "col(string)" function
2533 */
2534 static void
2535f_col(typval_T *argvars, typval_T *rettv)
2536{
2537 colnr_T col = 0;
2538 pos_T *fp;
2539 int fnum = curbuf->b_fnum;
2540
2541 fp = var2fpos(&argvars[0], FALSE, &fnum);
2542 if (fp != NULL && fnum == curbuf->b_fnum)
2543 {
2544 if (fp->col == MAXCOL)
2545 {
2546 /* '> can be MAXCOL, get the length of the line then */
2547 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2548 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2549 else
2550 col = MAXCOL;
2551 }
2552 else
2553 {
2554 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002555 /* col(".") when the cursor is on the NUL at the end of the line
2556 * because of "coladd" can be seen as an extra column. */
2557 if (virtual_active() && fp == &curwin->w_cursor)
2558 {
2559 char_u *p = ml_get_cursor();
2560
2561 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2562 curwin->w_virtcol - curwin->w_cursor.coladd))
2563 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002564 int l;
2565
2566 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2567 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002568 }
2569 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002570 }
2571 }
2572 rettv->vval.v_number = col;
2573}
2574
2575#if defined(FEAT_INS_EXPAND)
2576/*
2577 * "complete()" function
2578 */
2579 static void
2580f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2581{
2582 int startcol;
2583
2584 if ((State & INSERT) == 0)
2585 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002586 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587 return;
2588 }
2589
2590 /* Check for undo allowed here, because if something was already inserted
2591 * the line was already saved for undo and this check isn't done. */
2592 if (!undo_allowed())
2593 return;
2594
2595 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2596 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002597 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002598 return;
2599 }
2600
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002601 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 if (startcol <= 0)
2603 return;
2604
2605 set_completion(startcol - 1, argvars[1].vval.v_list);
2606}
2607
2608/*
2609 * "complete_add()" function
2610 */
2611 static void
2612f_complete_add(typval_T *argvars, typval_T *rettv)
2613{
2614 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2615}
2616
2617/*
2618 * "complete_check()" function
2619 */
2620 static void
2621f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2622{
2623 int saved = RedrawingDisabled;
2624
2625 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002626 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002627 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002628 RedrawingDisabled = saved;
2629}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002630
2631/*
2632 * "complete_info()" function
2633 */
2634 static void
2635f_complete_info(typval_T *argvars, typval_T *rettv)
2636{
2637 list_T *what_list = NULL;
2638
2639 if (rettv_dict_alloc(rettv) != OK)
2640 return;
2641
2642 if (argvars[0].v_type != VAR_UNKNOWN)
2643 {
2644 if (argvars[0].v_type != VAR_LIST)
2645 {
2646 emsg(_(e_listreq));
2647 return;
2648 }
2649 what_list = argvars[0].vval.v_list;
2650 }
2651 get_complete_info(what_list, rettv->vval.v_dict);
2652}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653#endif
2654
2655/*
2656 * "confirm(message, buttons[, default [, type]])" function
2657 */
2658 static void
2659f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2660{
2661#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2662 char_u *message;
2663 char_u *buttons = NULL;
2664 char_u buf[NUMBUFLEN];
2665 char_u buf2[NUMBUFLEN];
2666 int def = 1;
2667 int type = VIM_GENERIC;
2668 char_u *typestr;
2669 int error = FALSE;
2670
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002671 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002672 if (message == NULL)
2673 error = TRUE;
2674 if (argvars[1].v_type != VAR_UNKNOWN)
2675 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002676 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 if (buttons == NULL)
2678 error = TRUE;
2679 if (argvars[2].v_type != VAR_UNKNOWN)
2680 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002681 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 if (argvars[3].v_type != VAR_UNKNOWN)
2683 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002684 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002685 if (typestr == NULL)
2686 error = TRUE;
2687 else
2688 {
2689 switch (TOUPPER_ASC(*typestr))
2690 {
2691 case 'E': type = VIM_ERROR; break;
2692 case 'Q': type = VIM_QUESTION; break;
2693 case 'I': type = VIM_INFO; break;
2694 case 'W': type = VIM_WARNING; break;
2695 case 'G': type = VIM_GENERIC; break;
2696 }
2697 }
2698 }
2699 }
2700 }
2701
2702 if (buttons == NULL || *buttons == NUL)
2703 buttons = (char_u *)_("&Ok");
2704
2705 if (!error)
2706 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2707 def, NULL, FALSE);
2708#endif
2709}
2710
2711/*
2712 * "copy()" function
2713 */
2714 static void
2715f_copy(typval_T *argvars, typval_T *rettv)
2716{
2717 item_copy(&argvars[0], rettv, FALSE, 0);
2718}
2719
2720#ifdef FEAT_FLOAT
2721/*
2722 * "cos()" function
2723 */
2724 static void
2725f_cos(typval_T *argvars, typval_T *rettv)
2726{
2727 float_T f = 0.0;
2728
2729 rettv->v_type = VAR_FLOAT;
2730 if (get_float_arg(argvars, &f) == OK)
2731 rettv->vval.v_float = cos(f);
2732 else
2733 rettv->vval.v_float = 0.0;
2734}
2735
2736/*
2737 * "cosh()" function
2738 */
2739 static void
2740f_cosh(typval_T *argvars, typval_T *rettv)
2741{
2742 float_T f = 0.0;
2743
2744 rettv->v_type = VAR_FLOAT;
2745 if (get_float_arg(argvars, &f) == OK)
2746 rettv->vval.v_float = cosh(f);
2747 else
2748 rettv->vval.v_float = 0.0;
2749}
2750#endif
2751
2752/*
2753 * "count()" function
2754 */
2755 static void
2756f_count(typval_T *argvars, typval_T *rettv)
2757{
2758 long n = 0;
2759 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002760 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002761
Bram Moolenaar9966b212017-07-28 16:46:57 +02002762 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002763 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002764
2765 if (argvars[0].v_type == VAR_STRING)
2766 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002767 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002768 char_u *p = argvars[0].vval.v_string;
2769 char_u *next;
2770
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002771 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002772 {
2773 if (ic)
2774 {
2775 size_t len = STRLEN(expr);
2776
2777 while (*p != NUL)
2778 {
2779 if (MB_STRNICMP(p, expr, len) == 0)
2780 {
2781 ++n;
2782 p += len;
2783 }
2784 else
2785 MB_PTR_ADV(p);
2786 }
2787 }
2788 else
2789 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2790 != NULL)
2791 {
2792 ++n;
2793 p = next + STRLEN(expr);
2794 }
2795 }
2796
2797 }
2798 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002799 {
2800 listitem_T *li;
2801 list_T *l;
2802 long idx;
2803
2804 if ((l = argvars[0].vval.v_list) != NULL)
2805 {
2806 li = l->lv_first;
2807 if (argvars[2].v_type != VAR_UNKNOWN)
2808 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002809 if (argvars[3].v_type != VAR_UNKNOWN)
2810 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002811 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002812 if (!error)
2813 {
2814 li = list_find(l, idx);
2815 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002816 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002817 }
2818 }
2819 if (error)
2820 li = NULL;
2821 }
2822
2823 for ( ; li != NULL; li = li->li_next)
2824 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2825 ++n;
2826 }
2827 }
2828 else if (argvars[0].v_type == VAR_DICT)
2829 {
2830 int todo;
2831 dict_T *d;
2832 hashitem_T *hi;
2833
2834 if ((d = argvars[0].vval.v_dict) != NULL)
2835 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002836 if (argvars[2].v_type != VAR_UNKNOWN)
2837 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002838 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002839 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 }
2841
2842 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2843 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2844 {
2845 if (!HASHITEM_EMPTY(hi))
2846 {
2847 --todo;
2848 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2849 ++n;
2850 }
2851 }
2852 }
2853 }
2854 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002855 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002856 rettv->vval.v_number = n;
2857}
2858
2859/*
2860 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2861 *
2862 * Checks the existence of a cscope connection.
2863 */
2864 static void
2865f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2866{
2867#ifdef FEAT_CSCOPE
2868 int num = 0;
2869 char_u *dbpath = NULL;
2870 char_u *prepend = NULL;
2871 char_u buf[NUMBUFLEN];
2872
2873 if (argvars[0].v_type != VAR_UNKNOWN
2874 && argvars[1].v_type != VAR_UNKNOWN)
2875 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002876 num = (int)tv_get_number(&argvars[0]);
2877 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002878 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002879 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002880 }
2881
2882 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2883#endif
2884}
2885
2886/*
2887 * "cursor(lnum, col)" function, or
2888 * "cursor(list)"
2889 *
2890 * Moves the cursor to the specified line and column.
2891 * Returns 0 when the position could be set, -1 otherwise.
2892 */
2893 static void
2894f_cursor(typval_T *argvars, typval_T *rettv)
2895{
2896 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002897 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002898 int set_curswant = TRUE;
2899
2900 rettv->vval.v_number = -1;
2901 if (argvars[1].v_type == VAR_UNKNOWN)
2902 {
2903 pos_T pos;
2904 colnr_T curswant = -1;
2905
2906 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2907 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002908 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002909 return;
2910 }
2911 line = pos.lnum;
2912 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002913 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002914 if (curswant >= 0)
2915 {
2916 curwin->w_curswant = curswant - 1;
2917 set_curswant = FALSE;
2918 }
2919 }
2920 else
2921 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002922 line = tv_get_lnum(argvars);
2923 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002924 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002925 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002926 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002927 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002928 return; /* type error; errmsg already given */
2929 if (line > 0)
2930 curwin->w_cursor.lnum = line;
2931 if (col > 0)
2932 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002933 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002934
2935 /* Make sure the cursor is in a valid position. */
2936 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002937 /* Correct cursor for multi-byte character. */
2938 if (has_mbyte)
2939 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940
2941 curwin->w_set_curswant = set_curswant;
2942 rettv->vval.v_number = 0;
2943}
2944
Bram Moolenaar4f974752019-02-17 17:44:42 +01002945#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002946/*
2947 * "debugbreak()" function
2948 */
2949 static void
2950f_debugbreak(typval_T *argvars, typval_T *rettv)
2951{
2952 int pid;
2953
2954 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002955 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002956 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002957 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002958 else
2959 {
2960 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2961
2962 if (hProcess != NULL)
2963 {
2964 DebugBreakProcess(hProcess);
2965 CloseHandle(hProcess);
2966 rettv->vval.v_number = OK;
2967 }
2968 }
2969}
2970#endif
2971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002972/*
2973 * "deepcopy()" function
2974 */
2975 static void
2976f_deepcopy(typval_T *argvars, typval_T *rettv)
2977{
2978 int noref = 0;
2979 int copyID;
2980
2981 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002982 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002983 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002984 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002985 else
2986 {
2987 copyID = get_copyID();
2988 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2989 }
2990}
2991
2992/*
2993 * "delete()" function
2994 */
2995 static void
2996f_delete(typval_T *argvars, typval_T *rettv)
2997{
2998 char_u nbuf[NUMBUFLEN];
2999 char_u *name;
3000 char_u *flags;
3001
3002 rettv->vval.v_number = -1;
3003 if (check_restricted() || check_secure())
3004 return;
3005
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003006 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003007 if (name == NULL || *name == NUL)
3008 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003009 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003010 return;
3011 }
3012
3013 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003014 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003015 else
3016 flags = (char_u *)"";
3017
3018 if (*flags == NUL)
3019 /* delete a file */
3020 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
3021 else if (STRCMP(flags, "d") == 0)
3022 /* delete an empty directory */
3023 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
3024 else if (STRCMP(flags, "rf") == 0)
3025 /* delete a directory recursively */
3026 rettv->vval.v_number = delete_recursive(name);
3027 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003028 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003029}
3030
3031/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02003032 * "deletebufline()" function
3033 */
3034 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02003035f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02003036{
3037 buf_T *buf;
3038 linenr_T first, last;
3039 linenr_T lnum;
3040 long count;
3041 int is_curbuf;
3042 buf_T *curbuf_save = NULL;
3043 win_T *curwin_save = NULL;
3044 tabpage_T *tp;
3045 win_T *wp;
3046
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003047 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003048 if (buf == NULL)
3049 {
3050 rettv->vval.v_number = 1; /* FAIL */
3051 return;
3052 }
3053 is_curbuf = buf == curbuf;
3054
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003055 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003056 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003057 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003058 else
3059 last = first;
3060
3061 if (buf->b_ml.ml_mfp == NULL || first < 1
3062 || first > buf->b_ml.ml_line_count || last < first)
3063 {
3064 rettv->vval.v_number = 1; /* FAIL */
3065 return;
3066 }
3067
3068 if (!is_curbuf)
3069 {
3070 curbuf_save = curbuf;
3071 curwin_save = curwin;
3072 curbuf = buf;
3073 find_win_for_curbuf();
3074 }
3075 if (last > curbuf->b_ml.ml_line_count)
3076 last = curbuf->b_ml.ml_line_count;
3077 count = last - first + 1;
3078
3079 // When coming here from Insert mode, sync undo, so that this can be
3080 // undone separately from what was previously inserted.
3081 if (u_sync_once == 2)
3082 {
3083 u_sync_once = 1; // notify that u_sync() was called
3084 u_sync(TRUE);
3085 }
3086
3087 if (u_save(first - 1, last + 1) == FAIL)
3088 {
3089 rettv->vval.v_number = 1; /* FAIL */
3090 return;
3091 }
3092
3093 for (lnum = first; lnum <= last; ++lnum)
3094 ml_delete(first, TRUE);
3095
3096 FOR_ALL_TAB_WINDOWS(tp, wp)
3097 if (wp->w_buffer == buf)
3098 {
3099 if (wp->w_cursor.lnum > last)
3100 wp->w_cursor.lnum -= count;
3101 else if (wp->w_cursor.lnum> first)
3102 wp->w_cursor.lnum = first;
3103 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3104 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3105 }
3106 check_cursor_col();
3107 deleted_lines_mark(first, count);
3108
3109 if (!is_curbuf)
3110 {
3111 curbuf = curbuf_save;
3112 curwin = curwin_save;
3113 }
3114}
3115
3116/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003117 * "did_filetype()" function
3118 */
3119 static void
3120f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3121{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003122 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003123}
3124
3125/*
3126 * "diff_filler()" function
3127 */
3128 static void
3129f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3130{
3131#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003132 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003133#endif
3134}
3135
3136/*
3137 * "diff_hlID()" function
3138 */
3139 static void
3140f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3141{
3142#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003143 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003144 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003145 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003146 static int fnum = 0;
3147 static int change_start = 0;
3148 static int change_end = 0;
3149 static hlf_T hlID = (hlf_T)0;
3150 int filler_lines;
3151 int col;
3152
3153 if (lnum < 0) /* ignore type error in {lnum} arg */
3154 lnum = 0;
3155 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003156 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003157 || fnum != curbuf->b_fnum)
3158 {
3159 /* New line, buffer, change: need to get the values. */
3160 filler_lines = diff_check(curwin, lnum);
3161 if (filler_lines < 0)
3162 {
3163 if (filler_lines == -1)
3164 {
3165 change_start = MAXCOL;
3166 change_end = -1;
3167 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3168 hlID = HLF_ADD; /* added line */
3169 else
3170 hlID = HLF_CHD; /* changed line */
3171 }
3172 else
3173 hlID = HLF_ADD; /* added line */
3174 }
3175 else
3176 hlID = (hlf_T)0;
3177 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003178 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003179 fnum = curbuf->b_fnum;
3180 }
3181
3182 if (hlID == HLF_CHD || hlID == HLF_TXD)
3183 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003184 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003185 if (col >= change_start && col <= change_end)
3186 hlID = HLF_TXD; /* changed text */
3187 else
3188 hlID = HLF_CHD; /* changed line */
3189 }
3190 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3191#endif
3192}
3193
3194/*
3195 * "empty({expr})" function
3196 */
3197 static void
3198f_empty(typval_T *argvars, typval_T *rettv)
3199{
3200 int n = FALSE;
3201
3202 switch (argvars[0].v_type)
3203 {
3204 case VAR_STRING:
3205 case VAR_FUNC:
3206 n = argvars[0].vval.v_string == NULL
3207 || *argvars[0].vval.v_string == NUL;
3208 break;
3209 case VAR_PARTIAL:
3210 n = FALSE;
3211 break;
3212 case VAR_NUMBER:
3213 n = argvars[0].vval.v_number == 0;
3214 break;
3215 case VAR_FLOAT:
3216#ifdef FEAT_FLOAT
3217 n = argvars[0].vval.v_float == 0.0;
3218 break;
3219#endif
3220 case VAR_LIST:
3221 n = argvars[0].vval.v_list == NULL
3222 || argvars[0].vval.v_list->lv_first == NULL;
3223 break;
3224 case VAR_DICT:
3225 n = argvars[0].vval.v_dict == NULL
3226 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3227 break;
3228 case VAR_SPECIAL:
3229 n = argvars[0].vval.v_number != VVAL_TRUE;
3230 break;
3231
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003232 case VAR_BLOB:
3233 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003234 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3235 break;
3236
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003237 case VAR_JOB:
3238#ifdef FEAT_JOB_CHANNEL
3239 n = argvars[0].vval.v_job == NULL
3240 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3241 break;
3242#endif
3243 case VAR_CHANNEL:
3244#ifdef FEAT_JOB_CHANNEL
3245 n = argvars[0].vval.v_channel == NULL
3246 || !channel_is_open(argvars[0].vval.v_channel);
3247 break;
3248#endif
3249 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003250 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003251 n = TRUE;
3252 break;
3253 }
3254
3255 rettv->vval.v_number = n;
3256}
3257
3258/*
3259 * "escape({string}, {chars})" function
3260 */
3261 static void
3262f_escape(typval_T *argvars, typval_T *rettv)
3263{
3264 char_u buf[NUMBUFLEN];
3265
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003266 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3267 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003268 rettv->v_type = VAR_STRING;
3269}
3270
3271/*
3272 * "eval()" function
3273 */
3274 static void
3275f_eval(typval_T *argvars, typval_T *rettv)
3276{
3277 char_u *s, *p;
3278
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003279 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003280 if (s != NULL)
3281 s = skipwhite(s);
3282
3283 p = s;
3284 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3285 {
3286 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003287 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003288 need_clr_eos = FALSE;
3289 rettv->v_type = VAR_NUMBER;
3290 rettv->vval.v_number = 0;
3291 }
3292 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003293 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003294}
3295
3296/*
3297 * "eventhandler()" function
3298 */
3299 static void
3300f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3301{
3302 rettv->vval.v_number = vgetc_busy;
3303}
3304
3305/*
3306 * "executable()" function
3307 */
3308 static void
3309f_executable(typval_T *argvars, typval_T *rettv)
3310{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003311 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003312
3313 /* Check in $PATH and also check directly if there is a directory name. */
3314 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3315 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3316}
3317
3318static garray_T redir_execute_ga;
3319
3320/*
3321 * Append "value[value_len]" to the execute() output.
3322 */
3323 void
3324execute_redir_str(char_u *value, int value_len)
3325{
3326 int len;
3327
3328 if (value_len == -1)
3329 len = (int)STRLEN(value); /* Append the entire string */
3330 else
3331 len = value_len; /* Append only "value_len" characters */
3332 if (ga_grow(&redir_execute_ga, len) == OK)
3333 {
3334 mch_memmove((char *)redir_execute_ga.ga_data
3335 + redir_execute_ga.ga_len, value, len);
3336 redir_execute_ga.ga_len += len;
3337 }
3338}
3339
3340/*
3341 * Get next line from a list.
3342 * Called by do_cmdline() to get the next line.
3343 * Returns allocated string, or NULL for end of function.
3344 */
3345
3346 static char_u *
3347get_list_line(
3348 int c UNUSED,
3349 void *cookie,
3350 int indent UNUSED)
3351{
3352 listitem_T **p = (listitem_T **)cookie;
3353 listitem_T *item = *p;
3354 char_u buf[NUMBUFLEN];
3355 char_u *s;
3356
3357 if (item == NULL)
3358 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003359 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003360 *p = item->li_next;
3361 return s == NULL ? NULL : vim_strsave(s);
3362}
3363
3364/*
3365 * "execute()" function
3366 */
3367 static void
3368f_execute(typval_T *argvars, typval_T *rettv)
3369{
3370 char_u *cmd = NULL;
3371 list_T *list = NULL;
3372 int save_msg_silent = msg_silent;
3373 int save_emsg_silent = emsg_silent;
3374 int save_emsg_noredir = emsg_noredir;
3375 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003376 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003378 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003379 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003380
3381 rettv->vval.v_string = NULL;
3382 rettv->v_type = VAR_STRING;
3383
3384 if (argvars[0].v_type == VAR_LIST)
3385 {
3386 list = argvars[0].vval.v_list;
3387 if (list == NULL || list->lv_first == NULL)
3388 /* empty list, no commands, empty output */
3389 return;
3390 ++list->lv_refcount;
3391 }
3392 else
3393 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003394 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003395 if (cmd == NULL)
3396 return;
3397 }
3398
3399 if (argvars[1].v_type != VAR_UNKNOWN)
3400 {
3401 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003402 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403
3404 if (s == NULL)
3405 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003406 if (*s == NUL)
3407 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003408 if (STRNCMP(s, "silent", 6) == 0)
3409 ++msg_silent;
3410 if (STRCMP(s, "silent!") == 0)
3411 {
3412 emsg_silent = TRUE;
3413 emsg_noredir = TRUE;
3414 }
3415 }
3416 else
3417 ++msg_silent;
3418
3419 if (redir_execute)
3420 save_ga = redir_execute_ga;
3421 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3422 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003423 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003424 if (!echo_output)
3425 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003426
3427 if (cmd != NULL)
3428 do_cmdline_cmd(cmd);
3429 else
3430 {
3431 listitem_T *item = list->lv_first;
3432
3433 do_cmdline(NULL, get_list_line, (void *)&item,
3434 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3435 --list->lv_refcount;
3436 }
3437
Bram Moolenaard297f352017-01-29 20:31:21 +01003438 /* Need to append a NUL to the result. */
3439 if (ga_grow(&redir_execute_ga, 1) == OK)
3440 {
3441 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3442 rettv->vval.v_string = redir_execute_ga.ga_data;
3443 }
3444 else
3445 {
3446 ga_clear(&redir_execute_ga);
3447 rettv->vval.v_string = NULL;
3448 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003449 msg_silent = save_msg_silent;
3450 emsg_silent = save_emsg_silent;
3451 emsg_noredir = save_emsg_noredir;
3452
3453 redir_execute = save_redir_execute;
3454 if (redir_execute)
3455 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003456 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003458 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003459 if (echo_output)
3460 // When not working silently: put it in column zero. A following
3461 // "echon" will overwrite the message, unavoidably.
3462 msg_col = 0;
3463 else
3464 // When working silently: Put it back where it was, since nothing
3465 // should have been written.
3466 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003467}
3468
3469/*
3470 * "exepath()" function
3471 */
3472 static void
3473f_exepath(typval_T *argvars, typval_T *rettv)
3474{
3475 char_u *p = NULL;
3476
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003477 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003478 rettv->v_type = VAR_STRING;
3479 rettv->vval.v_string = p;
3480}
3481
3482/*
3483 * "exists()" function
3484 */
3485 static void
3486f_exists(typval_T *argvars, typval_T *rettv)
3487{
3488 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003489 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003490
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003491 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492 if (*p == '$') /* environment variable */
3493 {
3494 /* first try "normal" environment variables (fast) */
3495 if (mch_getenv(p + 1) != NULL)
3496 n = TRUE;
3497 else
3498 {
3499 /* try expanding things like $VIM and ${HOME} */
3500 p = expand_env_save(p);
3501 if (p != NULL && *p != '$')
3502 n = TRUE;
3503 vim_free(p);
3504 }
3505 }
3506 else if (*p == '&' || *p == '+') /* option */
3507 {
3508 n = (get_option_tv(&p, NULL, TRUE) == OK);
3509 if (*skipwhite(p) != NUL)
3510 n = FALSE; /* trailing garbage */
3511 }
3512 else if (*p == '*') /* internal or user defined function */
3513 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003514 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003515 }
3516 else if (*p == ':')
3517 {
3518 n = cmd_exists(p + 1);
3519 }
3520 else if (*p == '#')
3521 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003522 if (p[1] == '#')
3523 n = autocmd_supported(p + 2);
3524 else
3525 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003526 }
3527 else /* internal variable */
3528 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003529 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003530 }
3531
3532 rettv->vval.v_number = n;
3533}
3534
3535#ifdef FEAT_FLOAT
3536/*
3537 * "exp()" function
3538 */
3539 static void
3540f_exp(typval_T *argvars, typval_T *rettv)
3541{
3542 float_T f = 0.0;
3543
3544 rettv->v_type = VAR_FLOAT;
3545 if (get_float_arg(argvars, &f) == OK)
3546 rettv->vval.v_float = exp(f);
3547 else
3548 rettv->vval.v_float = 0.0;
3549}
3550#endif
3551
3552/*
3553 * "expand()" function
3554 */
3555 static void
3556f_expand(typval_T *argvars, typval_T *rettv)
3557{
3558 char_u *s;
3559 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003560 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3562 expand_T xpc;
3563 int error = FALSE;
3564 char_u *result;
3565
3566 rettv->v_type = VAR_STRING;
3567 if (argvars[1].v_type != VAR_UNKNOWN
3568 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003569 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003570 && !error)
3571 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003572 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003573 }
3574
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003575 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003576 if (*s == '%' || *s == '#' || *s == '<')
3577 {
3578 ++emsg_off;
3579 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3580 --emsg_off;
3581 if (rettv->v_type == VAR_LIST)
3582 {
3583 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3584 list_append_string(rettv->vval.v_list, result, -1);
3585 else
3586 vim_free(result);
3587 }
3588 else
3589 rettv->vval.v_string = result;
3590 }
3591 else
3592 {
3593 /* When the optional second argument is non-zero, don't remove matches
3594 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3595 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003596 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003597 options |= WILD_KEEP_ALL;
3598 if (!error)
3599 {
3600 ExpandInit(&xpc);
3601 xpc.xp_context = EXPAND_FILES;
3602 if (p_wic)
3603 options += WILD_ICASE;
3604 if (rettv->v_type == VAR_STRING)
3605 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3606 options, WILD_ALL);
3607 else if (rettv_list_alloc(rettv) != FAIL)
3608 {
3609 int i;
3610
3611 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3612 for (i = 0; i < xpc.xp_numfiles; i++)
3613 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3614 ExpandCleanup(&xpc);
3615 }
3616 }
3617 else
3618 rettv->vval.v_string = NULL;
3619 }
3620}
3621
3622/*
3623 * "extend(list, list [, idx])" function
3624 * "extend(dict, dict [, action])" function
3625 */
3626 static void
3627f_extend(typval_T *argvars, typval_T *rettv)
3628{
3629 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3630
3631 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3632 {
3633 list_T *l1, *l2;
3634 listitem_T *item;
3635 long before;
3636 int error = FALSE;
3637
3638 l1 = argvars[0].vval.v_list;
3639 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003640 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003641 && l2 != NULL)
3642 {
3643 if (argvars[2].v_type != VAR_UNKNOWN)
3644 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003645 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003646 if (error)
3647 return; /* type error; errmsg already given */
3648
3649 if (before == l1->lv_len)
3650 item = NULL;
3651 else
3652 {
3653 item = list_find(l1, before);
3654 if (item == NULL)
3655 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003656 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003657 return;
3658 }
3659 }
3660 }
3661 else
3662 item = NULL;
3663 list_extend(l1, l2, item);
3664
3665 copy_tv(&argvars[0], rettv);
3666 }
3667 }
3668 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3669 {
3670 dict_T *d1, *d2;
3671 char_u *action;
3672 int i;
3673
3674 d1 = argvars[0].vval.v_dict;
3675 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003676 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003677 && d2 != NULL)
3678 {
3679 /* Check the third argument. */
3680 if (argvars[2].v_type != VAR_UNKNOWN)
3681 {
3682 static char *(av[]) = {"keep", "force", "error"};
3683
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003684 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003685 if (action == NULL)
3686 return; /* type error; errmsg already given */
3687 for (i = 0; i < 3; ++i)
3688 if (STRCMP(action, av[i]) == 0)
3689 break;
3690 if (i == 3)
3691 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003692 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003693 return;
3694 }
3695 }
3696 else
3697 action = (char_u *)"force";
3698
3699 dict_extend(d1, d2, action);
3700
3701 copy_tv(&argvars[0], rettv);
3702 }
3703 }
3704 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003705 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003706}
3707
3708/*
3709 * "feedkeys()" function
3710 */
3711 static void
3712f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3713{
3714 int remap = TRUE;
3715 int insert = FALSE;
3716 char_u *keys, *flags;
3717 char_u nbuf[NUMBUFLEN];
3718 int typed = FALSE;
3719 int execute = FALSE;
3720 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003721 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003722 char_u *keys_esc;
3723
3724 /* This is not allowed in the sandbox. If the commands would still be
3725 * executed in the sandbox it would be OK, but it probably happens later,
3726 * when "sandbox" is no longer set. */
3727 if (check_secure())
3728 return;
3729
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003730 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003731
3732 if (argvars[1].v_type != VAR_UNKNOWN)
3733 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003734 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003735 for ( ; *flags != NUL; ++flags)
3736 {
3737 switch (*flags)
3738 {
3739 case 'n': remap = FALSE; break;
3740 case 'm': remap = TRUE; break;
3741 case 't': typed = TRUE; break;
3742 case 'i': insert = TRUE; break;
3743 case 'x': execute = TRUE; break;
3744 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003745 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003746 }
3747 }
3748 }
3749
3750 if (*keys != NUL || execute)
3751 {
3752 /* Need to escape K_SPECIAL and CSI before putting the string in the
3753 * typeahead buffer. */
3754 keys_esc = vim_strsave_escape_csi(keys);
3755 if (keys_esc != NULL)
3756 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003757 if (lowlevel)
3758 {
3759#ifdef USE_INPUT_BUF
3760 add_to_input_buf(keys, (int)STRLEN(keys));
3761#else
3762 emsg(_("E980: lowlevel input not supported"));
3763#endif
3764 }
3765 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003766 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003767 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003768 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003769 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003770#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003771 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003772#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003773 )
3774 typebuf_was_filled = TRUE;
3775 }
3776 vim_free(keys_esc);
3777
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003778 if (execute)
3779 {
3780 int save_msg_scroll = msg_scroll;
3781
3782 /* Avoid a 1 second delay when the keys start Insert mode. */
3783 msg_scroll = FALSE;
3784
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003785 if (!dangerous)
3786 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003787 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003788 if (!dangerous)
3789 --ex_normal_busy;
3790
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003791 msg_scroll |= save_msg_scroll;
3792 }
3793 }
3794 }
3795}
3796
3797/*
3798 * "filereadable()" function
3799 */
3800 static void
3801f_filereadable(typval_T *argvars, typval_T *rettv)
3802{
3803 int fd;
3804 char_u *p;
3805 int n;
3806
3807#ifndef O_NONBLOCK
3808# define O_NONBLOCK 0
3809#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003810 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003811 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3812 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3813 {
3814 n = TRUE;
3815 close(fd);
3816 }
3817 else
3818 n = FALSE;
3819
3820 rettv->vval.v_number = n;
3821}
3822
3823/*
3824 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3825 * rights to write into.
3826 */
3827 static void
3828f_filewritable(typval_T *argvars, typval_T *rettv)
3829{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003830 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003831}
3832
3833 static void
3834findfilendir(
3835 typval_T *argvars UNUSED,
3836 typval_T *rettv,
3837 int find_what UNUSED)
3838{
3839#ifdef FEAT_SEARCHPATH
3840 char_u *fname;
3841 char_u *fresult = NULL;
3842 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3843 char_u *p;
3844 char_u pathbuf[NUMBUFLEN];
3845 int count = 1;
3846 int first = TRUE;
3847 int error = FALSE;
3848#endif
3849
3850 rettv->vval.v_string = NULL;
3851 rettv->v_type = VAR_STRING;
3852
3853#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003854 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003855
3856 if (argvars[1].v_type != VAR_UNKNOWN)
3857 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003858 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003859 if (p == NULL)
3860 error = TRUE;
3861 else
3862 {
3863 if (*p != NUL)
3864 path = p;
3865
3866 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003867 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003868 }
3869 }
3870
3871 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3872 error = TRUE;
3873
3874 if (*fname != NUL && !error)
3875 {
3876 do
3877 {
3878 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3879 vim_free(fresult);
3880 fresult = find_file_in_path_option(first ? fname : NULL,
3881 first ? (int)STRLEN(fname) : 0,
3882 0, first, path,
3883 find_what,
3884 curbuf->b_ffname,
3885 find_what == FINDFILE_DIR
3886 ? (char_u *)"" : curbuf->b_p_sua);
3887 first = FALSE;
3888
3889 if (fresult != NULL && rettv->v_type == VAR_LIST)
3890 list_append_string(rettv->vval.v_list, fresult, -1);
3891
3892 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3893 }
3894
3895 if (rettv->v_type == VAR_STRING)
3896 rettv->vval.v_string = fresult;
3897#endif
3898}
3899
3900/*
3901 * "filter()" function
3902 */
3903 static void
3904f_filter(typval_T *argvars, typval_T *rettv)
3905{
3906 filter_map(argvars, rettv, FALSE);
3907}
3908
3909/*
3910 * "finddir({fname}[, {path}[, {count}]])" function
3911 */
3912 static void
3913f_finddir(typval_T *argvars, typval_T *rettv)
3914{
3915 findfilendir(argvars, rettv, FINDFILE_DIR);
3916}
3917
3918/*
3919 * "findfile({fname}[, {path}[, {count}]])" function
3920 */
3921 static void
3922f_findfile(typval_T *argvars, typval_T *rettv)
3923{
3924 findfilendir(argvars, rettv, FINDFILE_FILE);
3925}
3926
3927#ifdef FEAT_FLOAT
3928/*
3929 * "float2nr({float})" function
3930 */
3931 static void
3932f_float2nr(typval_T *argvars, typval_T *rettv)
3933{
3934 float_T f = 0.0;
3935
3936 if (get_float_arg(argvars, &f) == OK)
3937 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003938 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003939 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003940 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003941 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003942 else
3943 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003944 }
3945}
3946
3947/*
3948 * "floor({float})" function
3949 */
3950 static void
3951f_floor(typval_T *argvars, typval_T *rettv)
3952{
3953 float_T f = 0.0;
3954
3955 rettv->v_type = VAR_FLOAT;
3956 if (get_float_arg(argvars, &f) == OK)
3957 rettv->vval.v_float = floor(f);
3958 else
3959 rettv->vval.v_float = 0.0;
3960}
3961
3962/*
3963 * "fmod()" function
3964 */
3965 static void
3966f_fmod(typval_T *argvars, typval_T *rettv)
3967{
3968 float_T fx = 0.0, fy = 0.0;
3969
3970 rettv->v_type = VAR_FLOAT;
3971 if (get_float_arg(argvars, &fx) == OK
3972 && get_float_arg(&argvars[1], &fy) == OK)
3973 rettv->vval.v_float = fmod(fx, fy);
3974 else
3975 rettv->vval.v_float = 0.0;
3976}
3977#endif
3978
3979/*
3980 * "fnameescape({string})" function
3981 */
3982 static void
3983f_fnameescape(typval_T *argvars, typval_T *rettv)
3984{
3985 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003986 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003987 rettv->v_type = VAR_STRING;
3988}
3989
3990/*
3991 * "fnamemodify({fname}, {mods})" function
3992 */
3993 static void
3994f_fnamemodify(typval_T *argvars, typval_T *rettv)
3995{
3996 char_u *fname;
3997 char_u *mods;
3998 int usedlen = 0;
3999 int len;
4000 char_u *fbuf = NULL;
4001 char_u buf[NUMBUFLEN];
4002
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004003 fname = tv_get_string_chk(&argvars[0]);
4004 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004005 if (fname == NULL || mods == NULL)
4006 fname = NULL;
4007 else
4008 {
4009 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02004010 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004011 }
4012
4013 rettv->v_type = VAR_STRING;
4014 if (fname == NULL)
4015 rettv->vval.v_string = NULL;
4016 else
4017 rettv->vval.v_string = vim_strnsave(fname, len);
4018 vim_free(fbuf);
4019}
4020
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004021/*
4022 * "foldclosed()" function
4023 */
4024 static void
4025foldclosed_both(
4026 typval_T *argvars UNUSED,
4027 typval_T *rettv,
4028 int end UNUSED)
4029{
4030#ifdef FEAT_FOLDING
4031 linenr_T lnum;
4032 linenr_T first, last;
4033
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004034 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004035 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4036 {
4037 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
4038 {
4039 if (end)
4040 rettv->vval.v_number = (varnumber_T)last;
4041 else
4042 rettv->vval.v_number = (varnumber_T)first;
4043 return;
4044 }
4045 }
4046#endif
4047 rettv->vval.v_number = -1;
4048}
4049
4050/*
4051 * "foldclosed()" function
4052 */
4053 static void
4054f_foldclosed(typval_T *argvars, typval_T *rettv)
4055{
4056 foldclosed_both(argvars, rettv, FALSE);
4057}
4058
4059/*
4060 * "foldclosedend()" function
4061 */
4062 static void
4063f_foldclosedend(typval_T *argvars, typval_T *rettv)
4064{
4065 foldclosed_both(argvars, rettv, TRUE);
4066}
4067
4068/*
4069 * "foldlevel()" function
4070 */
4071 static void
4072f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4073{
4074#ifdef FEAT_FOLDING
4075 linenr_T lnum;
4076
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004077 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004078 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4079 rettv->vval.v_number = foldLevel(lnum);
4080#endif
4081}
4082
4083/*
4084 * "foldtext()" function
4085 */
4086 static void
4087f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4088{
4089#ifdef FEAT_FOLDING
4090 linenr_T foldstart;
4091 linenr_T foldend;
4092 char_u *dashes;
4093 linenr_T lnum;
4094 char_u *s;
4095 char_u *r;
4096 int len;
4097 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004098 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004099#endif
4100
4101 rettv->v_type = VAR_STRING;
4102 rettv->vval.v_string = NULL;
4103#ifdef FEAT_FOLDING
4104 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4105 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4106 dashes = get_vim_var_str(VV_FOLDDASHES);
4107 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4108 && dashes != NULL)
4109 {
4110 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004111 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004112 if (!linewhite(lnum))
4113 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004114
4115 /* Find interesting text in this line. */
4116 s = skipwhite(ml_get(lnum));
4117 /* skip C comment-start */
4118 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4119 {
4120 s = skipwhite(s + 2);
4121 if (*skipwhite(s) == NUL
4122 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4123 {
4124 s = skipwhite(ml_get(lnum + 1));
4125 if (*s == '*')
4126 s = skipwhite(s + 1);
4127 }
4128 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004129 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004130 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004131 r = alloc((unsigned)(STRLEN(txt)
4132 + STRLEN(dashes) /* for %s */
4133 + 20 /* for %3ld */
4134 + STRLEN(s))); /* concatenated */
4135 if (r != NULL)
4136 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004137 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004138 len = (int)STRLEN(r);
4139 STRCAT(r, s);
4140 /* remove 'foldmarker' and 'commentstring' */
4141 foldtext_cleanup(r + len);
4142 rettv->vval.v_string = r;
4143 }
4144 }
4145#endif
4146}
4147
4148/*
4149 * "foldtextresult(lnum)" function
4150 */
4151 static void
4152f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4153{
4154#ifdef FEAT_FOLDING
4155 linenr_T lnum;
4156 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004157 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004158 foldinfo_T foldinfo;
4159 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004160 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004161#endif
4162
4163 rettv->v_type = VAR_STRING;
4164 rettv->vval.v_string = NULL;
4165#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004166 if (entered)
4167 return; /* reject recursive use */
4168 entered = TRUE;
4169
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004170 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004171 /* treat illegal types and illegal string values for {lnum} the same */
4172 if (lnum < 0)
4173 lnum = 0;
4174 fold_count = foldedCount(curwin, lnum, &foldinfo);
4175 if (fold_count > 0)
4176 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004177 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4178 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004179 if (text == buf)
4180 text = vim_strsave(text);
4181 rettv->vval.v_string = text;
4182 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004183
4184 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004185#endif
4186}
4187
4188/*
4189 * "foreground()" function
4190 */
4191 static void
4192f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4193{
4194#ifdef FEAT_GUI
4195 if (gui.in_use)
4196 gui_mch_set_foreground();
4197#else
Bram Moolenaar4f974752019-02-17 17:44:42 +01004198# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004199 win32_set_foreground();
4200# endif
4201#endif
4202}
4203
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004204 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004205common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004206{
4207 char_u *s;
4208 char_u *name;
4209 int use_string = FALSE;
4210 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004211 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004212
4213 if (argvars[0].v_type == VAR_FUNC)
4214 {
4215 /* function(MyFunc, [arg], dict) */
4216 s = argvars[0].vval.v_string;
4217 }
4218 else if (argvars[0].v_type == VAR_PARTIAL
4219 && argvars[0].vval.v_partial != NULL)
4220 {
4221 /* function(dict.MyFunc, [arg]) */
4222 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004223 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004224 }
4225 else
4226 {
4227 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004228 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004229 use_string = TRUE;
4230 }
4231
Bram Moolenaar843b8842016-08-21 14:36:15 +02004232 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004233 {
4234 name = s;
4235 trans_name = trans_function_name(&name, FALSE,
4236 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4237 if (*name != NUL)
4238 s = NULL;
4239 }
4240
Bram Moolenaar843b8842016-08-21 14:36:15 +02004241 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4242 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004243 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004244 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004245 else if (trans_name != NULL && (is_funcref
4246 ? find_func(trans_name) == NULL
4247 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004248 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004249 else
4250 {
4251 int dict_idx = 0;
4252 int arg_idx = 0;
4253 list_T *list = NULL;
4254
4255 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4256 {
4257 char sid_buf[25];
4258 int off = *s == 's' ? 2 : 5;
4259
4260 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4261 * also be called from another script. Using trans_function_name()
4262 * would also work, but some plugins depend on the name being
4263 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004264 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004265 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4266 if (name != NULL)
4267 {
4268 STRCPY(name, sid_buf);
4269 STRCAT(name, s + off);
4270 }
4271 }
4272 else
4273 name = vim_strsave(s);
4274
4275 if (argvars[1].v_type != VAR_UNKNOWN)
4276 {
4277 if (argvars[2].v_type != VAR_UNKNOWN)
4278 {
4279 /* function(name, [args], dict) */
4280 arg_idx = 1;
4281 dict_idx = 2;
4282 }
4283 else if (argvars[1].v_type == VAR_DICT)
4284 /* function(name, dict) */
4285 dict_idx = 1;
4286 else
4287 /* function(name, [args]) */
4288 arg_idx = 1;
4289 if (dict_idx > 0)
4290 {
4291 if (argvars[dict_idx].v_type != VAR_DICT)
4292 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004293 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004294 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004295 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004296 }
4297 if (argvars[dict_idx].vval.v_dict == NULL)
4298 dict_idx = 0;
4299 }
4300 if (arg_idx > 0)
4301 {
4302 if (argvars[arg_idx].v_type != VAR_LIST)
4303 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004304 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004305 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004306 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004307 }
4308 list = argvars[arg_idx].vval.v_list;
4309 if (list == NULL || list->lv_len == 0)
4310 arg_idx = 0;
4311 }
4312 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004313 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004314 {
4315 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4316
4317 /* result is a VAR_PARTIAL */
4318 if (pt == NULL)
4319 vim_free(name);
4320 else
4321 {
4322 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4323 {
4324 listitem_T *li;
4325 int i = 0;
4326 int arg_len = 0;
4327 int lv_len = 0;
4328
4329 if (arg_pt != NULL)
4330 arg_len = arg_pt->pt_argc;
4331 if (list != NULL)
4332 lv_len = list->lv_len;
4333 pt->pt_argc = arg_len + lv_len;
4334 pt->pt_argv = (typval_T *)alloc(
4335 sizeof(typval_T) * pt->pt_argc);
4336 if (pt->pt_argv == NULL)
4337 {
4338 vim_free(pt);
4339 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004340 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004341 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004342 for (i = 0; i < arg_len; i++)
4343 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4344 if (lv_len > 0)
4345 for (li = list->lv_first; li != NULL;
4346 li = li->li_next)
4347 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004348 }
4349
4350 /* For "function(dict.func, [], dict)" and "func" is a partial
4351 * use "dict". That is backwards compatible. */
4352 if (dict_idx > 0)
4353 {
4354 /* The dict is bound explicitly, pt_auto is FALSE. */
4355 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4356 ++pt->pt_dict->dv_refcount;
4357 }
4358 else if (arg_pt != NULL)
4359 {
4360 /* If the dict was bound automatically the result is also
4361 * bound automatically. */
4362 pt->pt_dict = arg_pt->pt_dict;
4363 pt->pt_auto = arg_pt->pt_auto;
4364 if (pt->pt_dict != NULL)
4365 ++pt->pt_dict->dv_refcount;
4366 }
4367
4368 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004369 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4370 {
4371 pt->pt_func = arg_pt->pt_func;
4372 func_ptr_ref(pt->pt_func);
4373 vim_free(name);
4374 }
4375 else if (is_funcref)
4376 {
4377 pt->pt_func = find_func(trans_name);
4378 func_ptr_ref(pt->pt_func);
4379 vim_free(name);
4380 }
4381 else
4382 {
4383 pt->pt_name = name;
4384 func_ref(name);
4385 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004386 }
4387 rettv->v_type = VAR_PARTIAL;
4388 rettv->vval.v_partial = pt;
4389 }
4390 else
4391 {
4392 /* result is a VAR_FUNC */
4393 rettv->v_type = VAR_FUNC;
4394 rettv->vval.v_string = name;
4395 func_ref(name);
4396 }
4397 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004398theend:
4399 vim_free(trans_name);
4400}
4401
4402/*
4403 * "funcref()" function
4404 */
4405 static void
4406f_funcref(typval_T *argvars, typval_T *rettv)
4407{
4408 common_function(argvars, rettv, TRUE);
4409}
4410
4411/*
4412 * "function()" function
4413 */
4414 static void
4415f_function(typval_T *argvars, typval_T *rettv)
4416{
4417 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004418}
4419
4420/*
4421 * "garbagecollect()" function
4422 */
4423 static void
4424f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4425{
4426 /* This is postponed until we are back at the toplevel, because we may be
4427 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4428 want_garbage_collect = TRUE;
4429
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004430 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004431 garbage_collect_at_exit = TRUE;
4432}
4433
4434/*
4435 * "get()" function
4436 */
4437 static void
4438f_get(typval_T *argvars, typval_T *rettv)
4439{
4440 listitem_T *li;
4441 list_T *l;
4442 dictitem_T *di;
4443 dict_T *d;
4444 typval_T *tv = NULL;
4445
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004446 if (argvars[0].v_type == VAR_BLOB)
4447 {
4448 int error = FALSE;
4449 int idx = tv_get_number_chk(&argvars[1], &error);
4450
4451 if (!error)
4452 {
4453 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004454 if (idx < 0)
4455 idx = blob_len(argvars[0].vval.v_blob) + idx;
4456 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4457 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004458 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004459 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004460 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004461 tv = rettv;
4462 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004463 }
4464 }
4465 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004466 {
4467 if ((l = argvars[0].vval.v_list) != NULL)
4468 {
4469 int error = FALSE;
4470
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004471 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004472 if (!error && li != NULL)
4473 tv = &li->li_tv;
4474 }
4475 }
4476 else if (argvars[0].v_type == VAR_DICT)
4477 {
4478 if ((d = argvars[0].vval.v_dict) != NULL)
4479 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004480 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004481 if (di != NULL)
4482 tv = &di->di_tv;
4483 }
4484 }
4485 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4486 {
4487 partial_T *pt;
4488 partial_T fref_pt;
4489
4490 if (argvars[0].v_type == VAR_PARTIAL)
4491 pt = argvars[0].vval.v_partial;
4492 else
4493 {
4494 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4495 fref_pt.pt_name = argvars[0].vval.v_string;
4496 pt = &fref_pt;
4497 }
4498
4499 if (pt != NULL)
4500 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004501 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004502 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004503
4504 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4505 {
4506 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004507 n = partial_name(pt);
4508 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004509 rettv->vval.v_string = NULL;
4510 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004511 {
4512 rettv->vval.v_string = vim_strsave(n);
4513 if (rettv->v_type == VAR_FUNC)
4514 func_ref(rettv->vval.v_string);
4515 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004516 }
4517 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004518 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004519 else if (STRCMP(what, "args") == 0)
4520 {
4521 rettv->v_type = VAR_LIST;
4522 if (rettv_list_alloc(rettv) == OK)
4523 {
4524 int i;
4525
4526 for (i = 0; i < pt->pt_argc; ++i)
4527 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4528 }
4529 }
4530 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004531 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004532 return;
4533 }
4534 }
4535 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004536 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004537
4538 if (tv == NULL)
4539 {
4540 if (argvars[2].v_type != VAR_UNKNOWN)
4541 copy_tv(&argvars[2], rettv);
4542 }
4543 else
4544 copy_tv(tv, rettv);
4545}
4546
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004547/*
4548 * Returns buffer options, variables and other attributes in a dictionary.
4549 */
4550 static dict_T *
4551get_buffer_info(buf_T *buf)
4552{
4553 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004554 tabpage_T *tp;
4555 win_T *wp;
4556 list_T *windows;
4557
4558 dict = dict_alloc();
4559 if (dict == NULL)
4560 return NULL;
4561
Bram Moolenaare0be1672018-07-08 16:50:37 +02004562 dict_add_number(dict, "bufnr", buf->b_fnum);
4563 dict_add_string(dict, "name", buf->b_ffname);
4564 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4565 : buflist_findlnum(buf));
4566 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4567 dict_add_number(dict, "listed", buf->b_p_bl);
4568 dict_add_number(dict, "changed", bufIsChanged(buf));
4569 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4570 dict_add_number(dict, "hidden",
4571 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004572
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004573 /* Get a reference to buffer variables */
4574 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004575
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004576 /* List of windows displaying this buffer */
4577 windows = list_alloc();
4578 if (windows != NULL)
4579 {
4580 FOR_ALL_TAB_WINDOWS(tp, wp)
4581 if (wp->w_buffer == buf)
4582 list_append_number(windows, (varnumber_T)wp->w_id);
4583 dict_add_list(dict, "windows", windows);
4584 }
4585
4586#ifdef FEAT_SIGNS
4587 if (buf->b_signlist != NULL)
4588 {
4589 /* List of signs placed in this buffer */
4590 list_T *signs = list_alloc();
4591 if (signs != NULL)
4592 {
4593 get_buffer_signs(buf, signs);
4594 dict_add_list(dict, "signs", signs);
4595 }
4596 }
4597#endif
4598
4599 return dict;
4600}
4601
4602/*
4603 * "getbufinfo()" function
4604 */
4605 static void
4606f_getbufinfo(typval_T *argvars, typval_T *rettv)
4607{
4608 buf_T *buf = NULL;
4609 buf_T *argbuf = NULL;
4610 dict_T *d;
4611 int filtered = FALSE;
4612 int sel_buflisted = FALSE;
4613 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004614 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004615
4616 if (rettv_list_alloc(rettv) != OK)
4617 return;
4618
4619 /* List of all the buffers or selected buffers */
4620 if (argvars[0].v_type == VAR_DICT)
4621 {
4622 dict_T *sel_d = argvars[0].vval.v_dict;
4623
4624 if (sel_d != NULL)
4625 {
4626 dictitem_T *di;
4627
4628 filtered = TRUE;
4629
4630 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004631 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004632 sel_buflisted = TRUE;
4633
4634 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004635 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004636 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004637
4638 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004639 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004640 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004641 }
4642 }
4643 else if (argvars[0].v_type != VAR_UNKNOWN)
4644 {
4645 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004646 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004647 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004648 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004649 --emsg_off;
4650 if (argbuf == NULL)
4651 return;
4652 }
4653
4654 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004655 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004656 {
4657 if (argbuf != NULL && argbuf != buf)
4658 continue;
4659 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004660 || (sel_buflisted && !buf->b_p_bl)
4661 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004662 continue;
4663
4664 d = get_buffer_info(buf);
4665 if (d != NULL)
4666 list_append_dict(rettv->vval.v_list, d);
4667 if (argbuf != NULL)
4668 return;
4669 }
4670}
4671
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004672/*
4673 * Get line or list of lines from buffer "buf" into "rettv".
4674 * Return a range (from start to end) of lines in rettv from the specified
4675 * buffer.
4676 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4677 */
4678 static void
4679get_buffer_lines(
4680 buf_T *buf,
4681 linenr_T start,
4682 linenr_T end,
4683 int retlist,
4684 typval_T *rettv)
4685{
4686 char_u *p;
4687
4688 rettv->v_type = VAR_STRING;
4689 rettv->vval.v_string = NULL;
4690 if (retlist && rettv_list_alloc(rettv) == FAIL)
4691 return;
4692
4693 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4694 return;
4695
4696 if (!retlist)
4697 {
4698 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4699 p = ml_get_buf(buf, start, FALSE);
4700 else
4701 p = (char_u *)"";
4702 rettv->vval.v_string = vim_strsave(p);
4703 }
4704 else
4705 {
4706 if (end < start)
4707 return;
4708
4709 if (start < 1)
4710 start = 1;
4711 if (end > buf->b_ml.ml_line_count)
4712 end = buf->b_ml.ml_line_count;
4713 while (start <= end)
4714 if (list_append_string(rettv->vval.v_list,
4715 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4716 break;
4717 }
4718}
4719
4720/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004721 * "getbufline()" function
4722 */
4723 static void
4724f_getbufline(typval_T *argvars, typval_T *rettv)
4725{
4726 linenr_T lnum;
4727 linenr_T end;
4728 buf_T *buf;
4729
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004730 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004731 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004732 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733 --emsg_off;
4734
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004735 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004736 if (argvars[2].v_type == VAR_UNKNOWN)
4737 end = lnum;
4738 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004739 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004740
4741 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4742}
4743
4744/*
4745 * "getbufvar()" function
4746 */
4747 static void
4748f_getbufvar(typval_T *argvars, typval_T *rettv)
4749{
4750 buf_T *buf;
4751 buf_T *save_curbuf;
4752 char_u *varname;
4753 dictitem_T *v;
4754 int done = FALSE;
4755
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004756 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4757 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004758 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004759 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004760
4761 rettv->v_type = VAR_STRING;
4762 rettv->vval.v_string = NULL;
4763
4764 if (buf != NULL && varname != NULL)
4765 {
4766 /* set curbuf to be our buf, temporarily */
4767 save_curbuf = curbuf;
4768 curbuf = buf;
4769
Bram Moolenaar30567352016-08-27 21:25:44 +02004770 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004771 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004772 if (varname[1] == NUL)
4773 {
4774 /* get all buffer-local options in a dict */
4775 dict_T *opts = get_winbuf_options(TRUE);
4776
4777 if (opts != NULL)
4778 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004779 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004780 done = TRUE;
4781 }
4782 }
4783 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4784 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004785 done = TRUE;
4786 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004787 else
4788 {
4789 /* Look up the variable. */
4790 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4791 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4792 'b', varname, FALSE);
4793 if (v != NULL)
4794 {
4795 copy_tv(&v->di_tv, rettv);
4796 done = TRUE;
4797 }
4798 }
4799
4800 /* restore previous notion of curbuf */
4801 curbuf = save_curbuf;
4802 }
4803
4804 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4805 /* use the default value */
4806 copy_tv(&argvars[2], rettv);
4807
4808 --emsg_off;
4809}
4810
4811/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004812 * "getchangelist()" function
4813 */
4814 static void
4815f_getchangelist(typval_T *argvars, typval_T *rettv)
4816{
4817#ifdef FEAT_JUMPLIST
4818 buf_T *buf;
4819 int i;
4820 list_T *l;
4821 dict_T *d;
4822#endif
4823
4824 if (rettv_list_alloc(rettv) != OK)
4825 return;
4826
4827#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004828 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004829 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004830 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004831 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004832 if (buf == NULL)
4833 return;
4834
4835 l = list_alloc();
4836 if (l == NULL)
4837 return;
4838
4839 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4840 return;
4841 /*
4842 * The current window change list index tracks only the position in the
4843 * current buffer change list. For other buffers, use the change list
4844 * length as the current index.
4845 */
4846 list_append_number(rettv->vval.v_list,
4847 (varnumber_T)((buf == curwin->w_buffer)
4848 ? curwin->w_changelistidx : buf->b_changelistlen));
4849
4850 for (i = 0; i < buf->b_changelistlen; ++i)
4851 {
4852 if (buf->b_changelist[i].lnum == 0)
4853 continue;
4854 if ((d = dict_alloc()) == NULL)
4855 return;
4856 if (list_append_dict(l, d) == FAIL)
4857 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004858 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4859 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004860 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004861 }
4862#endif
4863}
4864/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004865 * "getchar()" function
4866 */
4867 static void
4868f_getchar(typval_T *argvars, typval_T *rettv)
4869{
4870 varnumber_T n;
4871 int error = FALSE;
4872
Bram Moolenaar84d93902018-09-11 20:10:20 +02004873#ifdef MESSAGE_QUEUE
4874 // vpeekc() used to check for messages, but that caused problems, invoking
4875 // a callback where it was not expected. Some plugins use getchar(1) in a
4876 // loop to await a message, therefore make sure we check for messages here.
4877 parse_queued_messages();
4878#endif
4879
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004880 /* Position the cursor. Needed after a message that ends in a space. */
4881 windgoto(msg_row, msg_col);
4882
4883 ++no_mapping;
4884 ++allow_keys;
4885 for (;;)
4886 {
4887 if (argvars[0].v_type == VAR_UNKNOWN)
4888 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004889 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004890 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004891 /* getchar(1): only check if char avail */
4892 n = vpeekc_any();
4893 else if (error || vpeekc_any() == NUL)
4894 /* illegal argument or getchar(0) and no char avail: return zero */
4895 n = 0;
4896 else
4897 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004898 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004899
4900 if (n == K_IGNORE)
4901 continue;
4902 break;
4903 }
4904 --no_mapping;
4905 --allow_keys;
4906
4907 set_vim_var_nr(VV_MOUSE_WIN, 0);
4908 set_vim_var_nr(VV_MOUSE_WINID, 0);
4909 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4910 set_vim_var_nr(VV_MOUSE_COL, 0);
4911
4912 rettv->vval.v_number = n;
4913 if (IS_SPECIAL(n) || mod_mask != 0)
4914 {
4915 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4916 int i = 0;
4917
4918 /* Turn a special key into three bytes, plus modifier. */
4919 if (mod_mask != 0)
4920 {
4921 temp[i++] = K_SPECIAL;
4922 temp[i++] = KS_MODIFIER;
4923 temp[i++] = mod_mask;
4924 }
4925 if (IS_SPECIAL(n))
4926 {
4927 temp[i++] = K_SPECIAL;
4928 temp[i++] = K_SECOND(n);
4929 temp[i++] = K_THIRD(n);
4930 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931 else if (has_mbyte)
4932 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004933 else
4934 temp[i++] = n;
4935 temp[i++] = NUL;
4936 rettv->v_type = VAR_STRING;
4937 rettv->vval.v_string = vim_strsave(temp);
4938
4939#ifdef FEAT_MOUSE
4940 if (is_mouse_key(n))
4941 {
4942 int row = mouse_row;
4943 int col = mouse_col;
4944 win_T *win;
4945 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004946 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004947 int winnr = 1;
4948
4949 if (row >= 0 && col >= 0)
4950 {
4951 /* Find the window at the mouse coordinates and compute the
4952 * text position. */
4953 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004954 if (win == NULL)
4955 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004956 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004957 for (wp = firstwin; wp != win; wp = wp->w_next)
4958 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004959 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4960 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4961 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4962 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4963 }
4964 }
4965#endif
4966 }
4967}
4968
4969/*
4970 * "getcharmod()" function
4971 */
4972 static void
4973f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4974{
4975 rettv->vval.v_number = mod_mask;
4976}
4977
4978/*
4979 * "getcharsearch()" function
4980 */
4981 static void
4982f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4983{
4984 if (rettv_dict_alloc(rettv) != FAIL)
4985 {
4986 dict_T *dict = rettv->vval.v_dict;
4987
Bram Moolenaare0be1672018-07-08 16:50:37 +02004988 dict_add_string(dict, "char", last_csearch());
4989 dict_add_number(dict, "forward", last_csearch_forward());
4990 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004991 }
4992}
4993
4994/*
4995 * "getcmdline()" function
4996 */
4997 static void
4998f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4999{
5000 rettv->v_type = VAR_STRING;
5001 rettv->vval.v_string = get_cmdline_str();
5002}
5003
5004/*
5005 * "getcmdpos()" function
5006 */
5007 static void
5008f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
5009{
5010 rettv->vval.v_number = get_cmdline_pos() + 1;
5011}
5012
5013/*
5014 * "getcmdtype()" function
5015 */
5016 static void
5017f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
5018{
5019 rettv->v_type = VAR_STRING;
5020 rettv->vval.v_string = alloc(2);
5021 if (rettv->vval.v_string != NULL)
5022 {
5023 rettv->vval.v_string[0] = get_cmdline_type();
5024 rettv->vval.v_string[1] = NUL;
5025 }
5026}
5027
5028/*
5029 * "getcmdwintype()" function
5030 */
5031 static void
5032f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
5033{
5034 rettv->v_type = VAR_STRING;
5035 rettv->vval.v_string = NULL;
5036#ifdef FEAT_CMDWIN
5037 rettv->vval.v_string = alloc(2);
5038 if (rettv->vval.v_string != NULL)
5039 {
5040 rettv->vval.v_string[0] = cmdwin_type;
5041 rettv->vval.v_string[1] = NUL;
5042 }
5043#endif
5044}
5045
5046#if defined(FEAT_CMDL_COMPL)
5047/*
5048 * "getcompletion()" function
5049 */
5050 static void
5051f_getcompletion(typval_T *argvars, typval_T *rettv)
5052{
5053 char_u *pat;
5054 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005055 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005056 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5057 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005058
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005059 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005060 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005061
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005062 if (p_wic)
5063 options |= WILD_ICASE;
5064
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005065 /* For filtered results, 'wildignore' is used */
5066 if (!filtered)
5067 options |= WILD_KEEP_ALL;
5068
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005069 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005070 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005071 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005072 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005073 if (xpc.xp_context == EXPAND_NOTHING)
5074 {
5075 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005076 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005078 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005079 return;
5080 }
5081
5082# if defined(FEAT_MENU)
5083 if (xpc.xp_context == EXPAND_MENUS)
5084 {
5085 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5086 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5087 }
5088# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005089#ifdef FEAT_CSCOPE
5090 if (xpc.xp_context == EXPAND_CSCOPE)
5091 {
5092 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5093 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5094 }
5095#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005096#ifdef FEAT_SIGNS
5097 if (xpc.xp_context == EXPAND_SIGN)
5098 {
5099 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5100 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5101 }
5102#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005103
5104 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5105 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5106 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005107 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005108
5109 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5110
5111 for (i = 0; i < xpc.xp_numfiles; i++)
5112 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5113 }
5114 vim_free(pat);
5115 ExpandCleanup(&xpc);
5116}
5117#endif
5118
5119/*
5120 * "getcwd()" function
5121 */
5122 static void
5123f_getcwd(typval_T *argvars, typval_T *rettv)
5124{
5125 win_T *wp = NULL;
5126 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005127 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005128
5129 rettv->v_type = VAR_STRING;
5130 rettv->vval.v_string = NULL;
5131
Bram Moolenaar54591292018-02-09 20:53:59 +01005132 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5133 global = TRUE;
5134 else
5135 wp = find_tabwin(&argvars[0], &argvars[1]);
5136
5137 if (wp != NULL && wp->w_localdir != NULL)
5138 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5139 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005140 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005141 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005142 rettv->vval.v_string = vim_strsave(globaldir);
5143 else
5144 {
5145 cwd = alloc(MAXPATHL);
5146 if (cwd != NULL)
5147 {
5148 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5149 rettv->vval.v_string = vim_strsave(cwd);
5150 vim_free(cwd);
5151 }
5152 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005153 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005154#ifdef BACKSLASH_IN_FILENAME
5155 if (rettv->vval.v_string != NULL)
5156 slash_adjust(rettv->vval.v_string);
5157#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005158}
5159
5160/*
5161 * "getfontname()" function
5162 */
5163 static void
5164f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5165{
5166 rettv->v_type = VAR_STRING;
5167 rettv->vval.v_string = NULL;
5168#ifdef FEAT_GUI
5169 if (gui.in_use)
5170 {
5171 GuiFont font;
5172 char_u *name = NULL;
5173
5174 if (argvars[0].v_type == VAR_UNKNOWN)
5175 {
5176 /* Get the "Normal" font. Either the name saved by
5177 * hl_set_font_name() or from the font ID. */
5178 font = gui.norm_font;
5179 name = hl_get_font_name();
5180 }
5181 else
5182 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005183 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005184 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5185 return;
5186 font = gui_mch_get_font(name, FALSE);
5187 if (font == NOFONT)
5188 return; /* Invalid font name, return empty string. */
5189 }
5190 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5191 if (argvars[0].v_type != VAR_UNKNOWN)
5192 gui_mch_free_font(font);
5193 }
5194#endif
5195}
5196
5197/*
5198 * "getfperm({fname})" function
5199 */
5200 static void
5201f_getfperm(typval_T *argvars, typval_T *rettv)
5202{
5203 char_u *fname;
5204 stat_T st;
5205 char_u *perm = NULL;
5206 char_u flags[] = "rwx";
5207 int i;
5208
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005209 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005210
5211 rettv->v_type = VAR_STRING;
5212 if (mch_stat((char *)fname, &st) >= 0)
5213 {
5214 perm = vim_strsave((char_u *)"---------");
5215 if (perm != NULL)
5216 {
5217 for (i = 0; i < 9; i++)
5218 {
5219 if (st.st_mode & (1 << (8 - i)))
5220 perm[i] = flags[i % 3];
5221 }
5222 }
5223 }
5224 rettv->vval.v_string = perm;
5225}
5226
5227/*
5228 * "getfsize({fname})" function
5229 */
5230 static void
5231f_getfsize(typval_T *argvars, typval_T *rettv)
5232{
5233 char_u *fname;
5234 stat_T st;
5235
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005236 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005237
5238 rettv->v_type = VAR_NUMBER;
5239
5240 if (mch_stat((char *)fname, &st) >= 0)
5241 {
5242 if (mch_isdir(fname))
5243 rettv->vval.v_number = 0;
5244 else
5245 {
5246 rettv->vval.v_number = (varnumber_T)st.st_size;
5247
5248 /* non-perfect check for overflow */
5249 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5250 rettv->vval.v_number = -2;
5251 }
5252 }
5253 else
5254 rettv->vval.v_number = -1;
5255}
5256
5257/*
5258 * "getftime({fname})" function
5259 */
5260 static void
5261f_getftime(typval_T *argvars, typval_T *rettv)
5262{
5263 char_u *fname;
5264 stat_T st;
5265
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005266 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005267
5268 if (mch_stat((char *)fname, &st) >= 0)
5269 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5270 else
5271 rettv->vval.v_number = -1;
5272}
5273
5274/*
5275 * "getftype({fname})" function
5276 */
5277 static void
5278f_getftype(typval_T *argvars, typval_T *rettv)
5279{
5280 char_u *fname;
5281 stat_T st;
5282 char_u *type = NULL;
5283 char *t;
5284
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005285 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005286
5287 rettv->v_type = VAR_STRING;
5288 if (mch_lstat((char *)fname, &st) >= 0)
5289 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005290 if (S_ISREG(st.st_mode))
5291 t = "file";
5292 else if (S_ISDIR(st.st_mode))
5293 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005294 else if (S_ISLNK(st.st_mode))
5295 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296 else if (S_ISBLK(st.st_mode))
5297 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 else if (S_ISCHR(st.st_mode))
5299 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005300 else if (S_ISFIFO(st.st_mode))
5301 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005302 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005303 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005304 else
5305 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005306 type = vim_strsave((char_u *)t);
5307 }
5308 rettv->vval.v_string = type;
5309}
5310
5311/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005312 * "getjumplist()" function
5313 */
5314 static void
5315f_getjumplist(typval_T *argvars, typval_T *rettv)
5316{
5317#ifdef FEAT_JUMPLIST
5318 win_T *wp;
5319 int i;
5320 list_T *l;
5321 dict_T *d;
5322#endif
5323
5324 if (rettv_list_alloc(rettv) != OK)
5325 return;
5326
5327#ifdef FEAT_JUMPLIST
5328 wp = find_tabwin(&argvars[0], &argvars[1]);
5329 if (wp == NULL)
5330 return;
5331
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005332 cleanup_jumplist(wp, TRUE);
5333
Bram Moolenaar4f505882018-02-10 21:06:32 +01005334 l = list_alloc();
5335 if (l == NULL)
5336 return;
5337
5338 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5339 return;
5340 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5341
5342 for (i = 0; i < wp->w_jumplistlen; ++i)
5343 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005344 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5345 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005346 if ((d = dict_alloc()) == NULL)
5347 return;
5348 if (list_append_dict(l, d) == FAIL)
5349 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005350 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5351 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005352 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005353 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005354 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005355 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005356 }
5357#endif
5358}
5359
5360/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005361 * "getline(lnum, [end])" function
5362 */
5363 static void
5364f_getline(typval_T *argvars, typval_T *rettv)
5365{
5366 linenr_T lnum;
5367 linenr_T end;
5368 int retlist;
5369
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005370 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005371 if (argvars[1].v_type == VAR_UNKNOWN)
5372 {
5373 end = 0;
5374 retlist = FALSE;
5375 }
5376 else
5377 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005378 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005379 retlist = TRUE;
5380 }
5381
5382 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5383}
5384
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005385#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005386 static void
5387get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5388{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005389 if (what_arg->v_type == VAR_UNKNOWN)
5390 {
5391 if (rettv_list_alloc(rettv) == OK)
5392 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005393 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005394 }
5395 else
5396 {
5397 if (rettv_dict_alloc(rettv) == OK)
5398 if (is_qf || (wp != NULL))
5399 {
5400 if (what_arg->v_type == VAR_DICT)
5401 {
5402 dict_T *d = what_arg->vval.v_dict;
5403
5404 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005405 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005406 }
5407 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005408 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005409 }
5410 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005411}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005412#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005413
5414/*
5415 * "getloclist()" function
5416 */
5417 static void
5418f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5419{
5420#ifdef FEAT_QUICKFIX
5421 win_T *wp;
5422
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005423 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005424 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5425#endif
5426}
5427
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005428/*
5429 * "getmatches()" function
5430 */
5431 static void
5432f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5433{
5434#ifdef FEAT_SEARCH_EXTRA
5435 dict_T *dict;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005436 matchitem_T *cur;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005437 int i;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005438 win_T *win = get_optional_window(argvars, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005439
Bram Moolenaaraff74912019-03-30 18:11:49 +01005440 if (rettv_list_alloc(rettv) == FAIL || win == NULL)
5441 return;
5442
5443 cur = win->w_match_head;
5444 while (cur != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005445 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005446 dict = dict_alloc();
5447 if (dict == NULL)
5448 return;
5449 if (cur->match.regprog == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005450 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005451 /* match added with matchaddpos() */
5452 for (i = 0; i < MAXPOSMATCH; ++i)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005453 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005454 llpos_T *llpos;
5455 char buf[6];
5456 list_T *l;
5457
5458 llpos = &cur->pos.pos[i];
5459 if (llpos->lnum == 0)
5460 break;
5461 l = list_alloc();
5462 if (l == NULL)
5463 break;
5464 list_append_number(l, (varnumber_T)llpos->lnum);
5465 if (llpos->col > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005466 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005467 list_append_number(l, (varnumber_T)llpos->col);
5468 list_append_number(l, (varnumber_T)llpos->len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005469 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005470 sprintf(buf, "pos%d", i + 1);
5471 dict_add_list(dict, buf, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005472 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005473 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005474 else
5475 {
5476 dict_add_string(dict, "pattern", cur->pattern);
5477 }
5478 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5479 dict_add_number(dict, "priority", (long)cur->priority);
5480 dict_add_number(dict, "id", (long)cur->id);
5481# if defined(FEAT_CONCEAL)
5482 if (cur->conceal_char)
5483 {
5484 char_u buf[MB_MAXBYTES + 1];
5485
5486 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5487 dict_add_string(dict, "conceal", (char_u *)&buf);
5488 }
5489# endif
5490 list_append_dict(rettv->vval.v_list, dict);
5491 cur = cur->next;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005492 }
5493#endif
5494}
5495
5496/*
5497 * "getpid()" function
5498 */
5499 static void
5500f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5501{
5502 rettv->vval.v_number = mch_get_pid();
5503}
5504
5505 static void
5506getpos_both(
5507 typval_T *argvars,
5508 typval_T *rettv,
5509 int getcurpos)
5510{
5511 pos_T *fp;
5512 list_T *l;
5513 int fnum = -1;
5514
5515 if (rettv_list_alloc(rettv) == OK)
5516 {
5517 l = rettv->vval.v_list;
5518 if (getcurpos)
5519 fp = &curwin->w_cursor;
5520 else
5521 fp = var2fpos(&argvars[0], TRUE, &fnum);
5522 if (fnum != -1)
5523 list_append_number(l, (varnumber_T)fnum);
5524 else
5525 list_append_number(l, (varnumber_T)0);
5526 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5527 : (varnumber_T)0);
5528 list_append_number(l, (fp != NULL)
5529 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5530 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005531 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005532 (varnumber_T)0);
5533 if (getcurpos)
5534 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005535 int save_set_curswant = curwin->w_set_curswant;
5536 colnr_T save_curswant = curwin->w_curswant;
5537 colnr_T save_virtcol = curwin->w_virtcol;
5538
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005539 update_curswant();
5540 list_append_number(l, curwin->w_curswant == MAXCOL ?
5541 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005542
5543 // Do not change "curswant", as it is unexpected that a get
5544 // function has a side effect.
5545 if (save_set_curswant)
5546 {
5547 curwin->w_set_curswant = save_set_curswant;
5548 curwin->w_curswant = save_curswant;
5549 curwin->w_virtcol = save_virtcol;
5550 curwin->w_valid &= ~VALID_VIRTCOL;
5551 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005552 }
5553 }
5554 else
5555 rettv->vval.v_number = FALSE;
5556}
5557
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005558/*
5559 * "getcurpos()" function
5560 */
5561 static void
5562f_getcurpos(typval_T *argvars, typval_T *rettv)
5563{
5564 getpos_both(argvars, rettv, TRUE);
5565}
5566
5567/*
5568 * "getpos(string)" function
5569 */
5570 static void
5571f_getpos(typval_T *argvars, typval_T *rettv)
5572{
5573 getpos_both(argvars, rettv, FALSE);
5574}
5575
5576/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005577 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005578 */
5579 static void
5580f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5581{
5582#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005583 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005584#endif
5585}
5586
5587/*
5588 * "getreg()" function
5589 */
5590 static void
5591f_getreg(typval_T *argvars, typval_T *rettv)
5592{
5593 char_u *strregname;
5594 int regname;
5595 int arg2 = FALSE;
5596 int return_list = FALSE;
5597 int error = FALSE;
5598
5599 if (argvars[0].v_type != VAR_UNKNOWN)
5600 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005601 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005602 error = strregname == NULL;
5603 if (argvars[1].v_type != VAR_UNKNOWN)
5604 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005605 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005606 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005607 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005608 }
5609 }
5610 else
5611 strregname = get_vim_var_str(VV_REG);
5612
5613 if (error)
5614 return;
5615
5616 regname = (strregname == NULL ? '"' : *strregname);
5617 if (regname == 0)
5618 regname = '"';
5619
5620 if (return_list)
5621 {
5622 rettv->v_type = VAR_LIST;
5623 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5624 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5625 if (rettv->vval.v_list == NULL)
5626 (void)rettv_list_alloc(rettv);
5627 else
5628 ++rettv->vval.v_list->lv_refcount;
5629 }
5630 else
5631 {
5632 rettv->v_type = VAR_STRING;
5633 rettv->vval.v_string = get_reg_contents(regname,
5634 arg2 ? GREG_EXPR_SRC : 0);
5635 }
5636}
5637
5638/*
5639 * "getregtype()" function
5640 */
5641 static void
5642f_getregtype(typval_T *argvars, typval_T *rettv)
5643{
5644 char_u *strregname;
5645 int regname;
5646 char_u buf[NUMBUFLEN + 2];
5647 long reglen = 0;
5648
5649 if (argvars[0].v_type != VAR_UNKNOWN)
5650 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005651 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005652 if (strregname == NULL) /* type error; errmsg already given */
5653 {
5654 rettv->v_type = VAR_STRING;
5655 rettv->vval.v_string = NULL;
5656 return;
5657 }
5658 }
5659 else
5660 /* Default to v:register */
5661 strregname = get_vim_var_str(VV_REG);
5662
5663 regname = (strregname == NULL ? '"' : *strregname);
5664 if (regname == 0)
5665 regname = '"';
5666
5667 buf[0] = NUL;
5668 buf[1] = NUL;
5669 switch (get_reg_type(regname, &reglen))
5670 {
5671 case MLINE: buf[0] = 'V'; break;
5672 case MCHAR: buf[0] = 'v'; break;
5673 case MBLOCK:
5674 buf[0] = Ctrl_V;
5675 sprintf((char *)buf + 1, "%ld", reglen + 1);
5676 break;
5677 }
5678 rettv->v_type = VAR_STRING;
5679 rettv->vval.v_string = vim_strsave(buf);
5680}
5681
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005682/*
5683 * Returns information (variables, options, etc.) about a tab page
5684 * as a dictionary.
5685 */
5686 static dict_T *
5687get_tabpage_info(tabpage_T *tp, int tp_idx)
5688{
5689 win_T *wp;
5690 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005691 list_T *l;
5692
5693 dict = dict_alloc();
5694 if (dict == NULL)
5695 return NULL;
5696
Bram Moolenaare0be1672018-07-08 16:50:37 +02005697 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005698
5699 l = list_alloc();
5700 if (l != NULL)
5701 {
5702 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5703 wp; wp = wp->w_next)
5704 list_append_number(l, (varnumber_T)wp->w_id);
5705 dict_add_list(dict, "windows", l);
5706 }
5707
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005708 /* Make a reference to tabpage variables */
5709 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005710
5711 return dict;
5712}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005713
5714/*
5715 * "gettabinfo()" function
5716 */
5717 static void
5718f_gettabinfo(typval_T *argvars, typval_T *rettv)
5719{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005720 tabpage_T *tp, *tparg = NULL;
5721 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005722 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005723
5724 if (rettv_list_alloc(rettv) != OK)
5725 return;
5726
5727 if (argvars[0].v_type != VAR_UNKNOWN)
5728 {
5729 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005730 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005731 if (tparg == NULL)
5732 return;
5733 }
5734
5735 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005736 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005737 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005738 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005739 if (tparg != NULL && tp != tparg)
5740 continue;
5741 d = get_tabpage_info(tp, tpnr);
5742 if (d != NULL)
5743 list_append_dict(rettv->vval.v_list, d);
5744 if (tparg != NULL)
5745 return;
5746 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005747}
5748
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005749/*
5750 * "gettabvar()" function
5751 */
5752 static void
5753f_gettabvar(typval_T *argvars, typval_T *rettv)
5754{
5755 win_T *oldcurwin;
5756 tabpage_T *tp, *oldtabpage;
5757 dictitem_T *v;
5758 char_u *varname;
5759 int done = FALSE;
5760
5761 rettv->v_type = VAR_STRING;
5762 rettv->vval.v_string = NULL;
5763
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005764 varname = tv_get_string_chk(&argvars[1]);
5765 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005766 if (tp != NULL && varname != NULL)
5767 {
5768 /* Set tp to be our tabpage, temporarily. Also set the window to the
5769 * first window in the tabpage, otherwise the window is not valid. */
5770 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005771 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5772 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005773 {
5774 /* look up the variable */
5775 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5776 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5777 if (v != NULL)
5778 {
5779 copy_tv(&v->di_tv, rettv);
5780 done = TRUE;
5781 }
5782 }
5783
5784 /* restore previous notion of curwin */
5785 restore_win(oldcurwin, oldtabpage, TRUE);
5786 }
5787
5788 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5789 copy_tv(&argvars[2], rettv);
5790}
5791
5792/*
5793 * "gettabwinvar()" function
5794 */
5795 static void
5796f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5797{
5798 getwinvar(argvars, rettv, 1);
5799}
5800
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005801/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005802 * "gettagstack()" function
5803 */
5804 static void
5805f_gettagstack(typval_T *argvars, typval_T *rettv)
5806{
5807 win_T *wp = curwin; // default is current window
5808
5809 if (rettv_dict_alloc(rettv) != OK)
5810 return;
5811
5812 if (argvars[0].v_type != VAR_UNKNOWN)
5813 {
5814 wp = find_win_by_nr_or_id(&argvars[0]);
5815 if (wp == NULL)
5816 return;
5817 }
5818
5819 get_tagstack(wp, rettv->vval.v_dict);
5820}
5821
5822/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005823 * Returns information about a window as a dictionary.
5824 */
5825 static dict_T *
5826get_win_info(win_T *wp, short tpnr, short winnr)
5827{
5828 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005829
5830 dict = dict_alloc();
5831 if (dict == NULL)
5832 return NULL;
5833
Bram Moolenaare0be1672018-07-08 16:50:37 +02005834 dict_add_number(dict, "tabnr", tpnr);
5835 dict_add_number(dict, "winnr", winnr);
5836 dict_add_number(dict, "winid", wp->w_id);
5837 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005838 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005839 dict_add_number(dict, "topline", wp->w_topline);
5840 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005841#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005842 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005843#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005844 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005845 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005846 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005847
Bram Moolenaar69905d12017-08-13 18:14:47 +02005848#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005849 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005850#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005851#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005852 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5853 dict_add_number(dict, "loclist",
5854 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005855#endif
5856
Bram Moolenaar30567352016-08-27 21:25:44 +02005857 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005858 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005859
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005860 return dict;
5861}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005862
5863/*
5864 * "getwininfo()" function
5865 */
5866 static void
5867f_getwininfo(typval_T *argvars, typval_T *rettv)
5868{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005869 tabpage_T *tp;
5870 win_T *wp = NULL, *wparg = NULL;
5871 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005872 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005873
5874 if (rettv_list_alloc(rettv) != OK)
5875 return;
5876
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005877 if (argvars[0].v_type != VAR_UNKNOWN)
5878 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005879 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005880 if (wparg == NULL)
5881 return;
5882 }
5883
5884 /* Collect information about either all the windows across all the tab
5885 * pages or one particular window.
5886 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005887 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005888 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005889 tabnr++;
5890 winnr = 0;
5891 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005892 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005893 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005894 if (wparg != NULL && wp != wparg)
5895 continue;
5896 d = get_win_info(wp, tabnr, winnr);
5897 if (d != NULL)
5898 list_append_dict(rettv->vval.v_list, d);
5899 if (wparg != NULL)
5900 /* found information about a specific window */
5901 return;
5902 }
5903 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005904}
5905
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005906/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005907 * "win_findbuf()" function
5908 */
5909 static void
5910f_win_findbuf(typval_T *argvars, typval_T *rettv)
5911{
5912 if (rettv_list_alloc(rettv) != FAIL)
5913 win_findbuf(argvars, rettv->vval.v_list);
5914}
5915
5916/*
5917 * "win_getid()" function
5918 */
5919 static void
5920f_win_getid(typval_T *argvars, typval_T *rettv)
5921{
5922 rettv->vval.v_number = win_getid(argvars);
5923}
5924
5925/*
5926 * "win_gotoid()" function
5927 */
5928 static void
5929f_win_gotoid(typval_T *argvars, typval_T *rettv)
5930{
5931 rettv->vval.v_number = win_gotoid(argvars);
5932}
5933
5934/*
5935 * "win_id2tabwin()" function
5936 */
5937 static void
5938f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5939{
5940 if (rettv_list_alloc(rettv) != FAIL)
5941 win_id2tabwin(argvars, rettv->vval.v_list);
5942}
5943
5944/*
5945 * "win_id2win()" function
5946 */
5947 static void
5948f_win_id2win(typval_T *argvars, typval_T *rettv)
5949{
5950 rettv->vval.v_number = win_id2win(argvars);
5951}
5952
5953/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005954 * "win_screenpos()" function
5955 */
5956 static void
5957f_win_screenpos(typval_T *argvars, typval_T *rettv)
5958{
5959 win_T *wp;
5960
5961 if (rettv_list_alloc(rettv) == FAIL)
5962 return;
5963
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005964 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005965 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5966 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5967}
5968
5969/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005970 * "getwinpos({timeout})" function
5971 */
5972 static void
5973f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5974{
5975 int x = -1;
5976 int y = -1;
5977
5978 if (rettv_list_alloc(rettv) == FAIL)
5979 return;
5980#ifdef FEAT_GUI
5981 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005982 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005983# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5984 else
5985# endif
5986#endif
5987#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5988 {
5989 varnumber_T timeout = 100;
5990
5991 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005992 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005993 term_get_winpos(&x, &y, timeout);
5994 }
5995#endif
5996 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5997 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5998}
5999
6000
6001/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006002 * "getwinposx()" function
6003 */
6004 static void
6005f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
6006{
6007 rettv->vval.v_number = -1;
6008#ifdef FEAT_GUI
6009 if (gui.in_use)
6010 {
6011 int x, y;
6012
6013 if (gui_mch_get_winpos(&x, &y) == OK)
6014 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02006015 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006016 }
6017#endif
6018#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6019 {
6020 int x, y;
6021
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006022 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006023 rettv->vval.v_number = x;
6024 }
6025#endif
6026}
6027
6028/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006029 * "getwinposy()" function
6030 */
6031 static void
6032f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
6033{
6034 rettv->vval.v_number = -1;
6035#ifdef FEAT_GUI
6036 if (gui.in_use)
6037 {
6038 int x, y;
6039
6040 if (gui_mch_get_winpos(&x, &y) == OK)
6041 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02006042 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006043 }
6044#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006045#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6046 {
6047 int x, y;
6048
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006049 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006050 rettv->vval.v_number = y;
6051 }
6052#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006053}
6054
6055/*
6056 * "getwinvar()" function
6057 */
6058 static void
6059f_getwinvar(typval_T *argvars, typval_T *rettv)
6060{
6061 getwinvar(argvars, rettv, 0);
6062}
6063
6064/*
6065 * "glob()" function
6066 */
6067 static void
6068f_glob(typval_T *argvars, typval_T *rettv)
6069{
6070 int options = WILD_SILENT|WILD_USE_NL;
6071 expand_T xpc;
6072 int error = FALSE;
6073
6074 /* When the optional second argument is non-zero, don't remove matches
6075 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6076 rettv->v_type = VAR_STRING;
6077 if (argvars[1].v_type != VAR_UNKNOWN)
6078 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006079 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006080 options |= WILD_KEEP_ALL;
6081 if (argvars[2].v_type != VAR_UNKNOWN)
6082 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006083 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006084 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006085 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006086 }
6087 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006088 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006089 options |= WILD_ALLLINKS;
6090 }
6091 }
6092 if (!error)
6093 {
6094 ExpandInit(&xpc);
6095 xpc.xp_context = EXPAND_FILES;
6096 if (p_wic)
6097 options += WILD_ICASE;
6098 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006099 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006100 NULL, options, WILD_ALL);
6101 else if (rettv_list_alloc(rettv) != FAIL)
6102 {
6103 int i;
6104
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006105 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006106 NULL, options, WILD_ALL_KEEP);
6107 for (i = 0; i < xpc.xp_numfiles; i++)
6108 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6109
6110 ExpandCleanup(&xpc);
6111 }
6112 }
6113 else
6114 rettv->vval.v_string = NULL;
6115}
6116
6117/*
6118 * "globpath()" function
6119 */
6120 static void
6121f_globpath(typval_T *argvars, typval_T *rettv)
6122{
6123 int flags = 0;
6124 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006125 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006126 int error = FALSE;
6127 garray_T ga;
6128 int i;
6129
6130 /* When the optional second argument is non-zero, don't remove matches
6131 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6132 rettv->v_type = VAR_STRING;
6133 if (argvars[2].v_type != VAR_UNKNOWN)
6134 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006135 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006136 flags |= WILD_KEEP_ALL;
6137 if (argvars[3].v_type != VAR_UNKNOWN)
6138 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006139 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006140 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006141 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006142 }
6143 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006144 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006145 flags |= WILD_ALLLINKS;
6146 }
6147 }
6148 if (file != NULL && !error)
6149 {
6150 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006151 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006152 if (rettv->v_type == VAR_STRING)
6153 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6154 else if (rettv_list_alloc(rettv) != FAIL)
6155 for (i = 0; i < ga.ga_len; ++i)
6156 list_append_string(rettv->vval.v_list,
6157 ((char_u **)(ga.ga_data))[i], -1);
6158 ga_clear_strings(&ga);
6159 }
6160 else
6161 rettv->vval.v_string = NULL;
6162}
6163
6164/*
6165 * "glob2regpat()" function
6166 */
6167 static void
6168f_glob2regpat(typval_T *argvars, typval_T *rettv)
6169{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006170 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006171
6172 rettv->v_type = VAR_STRING;
6173 rettv->vval.v_string = (pat == NULL)
6174 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6175}
6176
6177/* for VIM_VERSION_ defines */
6178#include "version.h"
6179
6180/*
6181 * "has()" function
6182 */
6183 static void
6184f_has(typval_T *argvars, typval_T *rettv)
6185{
6186 int i;
6187 char_u *name;
6188 int n = FALSE;
6189 static char *(has_list[]) =
6190 {
6191#ifdef AMIGA
6192 "amiga",
6193# ifdef FEAT_ARP
6194 "arp",
6195# endif
6196#endif
6197#ifdef __BEOS__
6198 "beos",
6199#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006200#if defined(BSD) && !defined(MACOS_X)
6201 "bsd",
6202#endif
6203#ifdef hpux
6204 "hpux",
6205#endif
6206#ifdef __linux__
6207 "linux",
6208#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006209#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006210 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6211 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006212# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006213 "macunix", /* Mac OS X, with the darwin feature */
6214 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006215# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006216#endif
6217#ifdef __QNX__
6218 "qnx",
6219#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006220#ifdef SUN_SYSTEM
6221 "sun",
6222#else
6223 "moon",
6224#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006225#ifdef UNIX
6226 "unix",
6227#endif
6228#ifdef VMS
6229 "vms",
6230#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006231#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006232 "win32",
6233#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006234#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006235 "win32unix",
6236#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006237#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006238 "win64",
6239#endif
6240#ifdef EBCDIC
6241 "ebcdic",
6242#endif
6243#ifndef CASE_INSENSITIVE_FILENAME
6244 "fname_case",
6245#endif
6246#ifdef HAVE_ACL
6247 "acl",
6248#endif
6249#ifdef FEAT_ARABIC
6250 "arabic",
6251#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006252 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006253#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006254 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006255#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006256#ifdef FEAT_AUTOSERVERNAME
6257 "autoservername",
6258#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006259#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006260 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006261# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006262 "balloon_multiline",
6263# endif
6264#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006265#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006266 "balloon_eval_term",
6267#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006268#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6269 "builtin_terms",
6270# ifdef ALL_BUILTIN_TCAPS
6271 "all_builtin_terms",
6272# endif
6273#endif
6274#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006275 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006276 || defined(FEAT_GUI_MOTIF))
6277 "browsefilter",
6278#endif
6279#ifdef FEAT_BYTEOFF
6280 "byte_offset",
6281#endif
6282#ifdef FEAT_JOB_CHANNEL
6283 "channel",
6284#endif
6285#ifdef FEAT_CINDENT
6286 "cindent",
6287#endif
6288#ifdef FEAT_CLIENTSERVER
6289 "clientserver",
6290#endif
6291#ifdef FEAT_CLIPBOARD
6292 "clipboard",
6293#endif
6294#ifdef FEAT_CMDL_COMPL
6295 "cmdline_compl",
6296#endif
6297#ifdef FEAT_CMDHIST
6298 "cmdline_hist",
6299#endif
6300#ifdef FEAT_COMMENTS
6301 "comments",
6302#endif
6303#ifdef FEAT_CONCEAL
6304 "conceal",
6305#endif
6306#ifdef FEAT_CRYPT
6307 "cryptv",
6308 "crypt-blowfish",
6309 "crypt-blowfish2",
6310#endif
6311#ifdef FEAT_CSCOPE
6312 "cscope",
6313#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006314 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006315#ifdef CURSOR_SHAPE
6316 "cursorshape",
6317#endif
6318#ifdef DEBUG
6319 "debug",
6320#endif
6321#ifdef FEAT_CON_DIALOG
6322 "dialog_con",
6323#endif
6324#ifdef FEAT_GUI_DIALOG
6325 "dialog_gui",
6326#endif
6327#ifdef FEAT_DIFF
6328 "diff",
6329#endif
6330#ifdef FEAT_DIGRAPHS
6331 "digraphs",
6332#endif
6333#ifdef FEAT_DIRECTX
6334 "directx",
6335#endif
6336#ifdef FEAT_DND
6337 "dnd",
6338#endif
6339#ifdef FEAT_EMACS_TAGS
6340 "emacs_tags",
6341#endif
6342 "eval", /* always present, of course! */
6343 "ex_extra", /* graduated feature */
6344#ifdef FEAT_SEARCH_EXTRA
6345 "extra_search",
6346#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006347#ifdef FEAT_SEARCHPATH
6348 "file_in_path",
6349#endif
6350#ifdef FEAT_FILTERPIPE
6351 "filterpipe",
6352#endif
6353#ifdef FEAT_FIND_ID
6354 "find_in_path",
6355#endif
6356#ifdef FEAT_FLOAT
6357 "float",
6358#endif
6359#ifdef FEAT_FOLDING
6360 "folding",
6361#endif
6362#ifdef FEAT_FOOTER
6363 "footer",
6364#endif
6365#if !defined(USE_SYSTEM) && defined(UNIX)
6366 "fork",
6367#endif
6368#ifdef FEAT_GETTEXT
6369 "gettext",
6370#endif
6371#ifdef FEAT_GUI
6372 "gui",
6373#endif
6374#ifdef FEAT_GUI_ATHENA
6375# ifdef FEAT_GUI_NEXTAW
6376 "gui_neXtaw",
6377# else
6378 "gui_athena",
6379# endif
6380#endif
6381#ifdef FEAT_GUI_GTK
6382 "gui_gtk",
6383# ifdef USE_GTK3
6384 "gui_gtk3",
6385# else
6386 "gui_gtk2",
6387# endif
6388#endif
6389#ifdef FEAT_GUI_GNOME
6390 "gui_gnome",
6391#endif
6392#ifdef FEAT_GUI_MAC
6393 "gui_mac",
6394#endif
6395#ifdef FEAT_GUI_MOTIF
6396 "gui_motif",
6397#endif
6398#ifdef FEAT_GUI_PHOTON
6399 "gui_photon",
6400#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006401#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006402 "gui_win32",
6403#endif
6404#ifdef FEAT_HANGULIN
6405 "hangul_input",
6406#endif
6407#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6408 "iconv",
6409#endif
6410#ifdef FEAT_INS_EXPAND
6411 "insert_expand",
6412#endif
6413#ifdef FEAT_JOB_CHANNEL
6414 "job",
6415#endif
6416#ifdef FEAT_JUMPLIST
6417 "jumplist",
6418#endif
6419#ifdef FEAT_KEYMAP
6420 "keymap",
6421#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006422 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006423#ifdef FEAT_LANGMAP
6424 "langmap",
6425#endif
6426#ifdef FEAT_LIBCALL
6427 "libcall",
6428#endif
6429#ifdef FEAT_LINEBREAK
6430 "linebreak",
6431#endif
6432#ifdef FEAT_LISP
6433 "lispindent",
6434#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006435 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006436#ifdef FEAT_LOCALMAP
6437 "localmap",
6438#endif
6439#ifdef FEAT_LUA
6440# ifndef DYNAMIC_LUA
6441 "lua",
6442# endif
6443#endif
6444#ifdef FEAT_MENU
6445 "menu",
6446#endif
6447#ifdef FEAT_SESSION
6448 "mksession",
6449#endif
6450#ifdef FEAT_MODIFY_FNAME
6451 "modify_fname",
6452#endif
6453#ifdef FEAT_MOUSE
6454 "mouse",
6455#endif
6456#ifdef FEAT_MOUSESHAPE
6457 "mouseshape",
6458#endif
6459#if defined(UNIX) || defined(VMS)
6460# ifdef FEAT_MOUSE_DEC
6461 "mouse_dec",
6462# endif
6463# ifdef FEAT_MOUSE_GPM
6464 "mouse_gpm",
6465# endif
6466# ifdef FEAT_MOUSE_JSB
6467 "mouse_jsbterm",
6468# endif
6469# ifdef FEAT_MOUSE_NET
6470 "mouse_netterm",
6471# endif
6472# ifdef FEAT_MOUSE_PTERM
6473 "mouse_pterm",
6474# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006475# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006476 "mouse_sgr",
6477# endif
6478# ifdef FEAT_SYSMOUSE
6479 "mouse_sysmouse",
6480# endif
6481# ifdef FEAT_MOUSE_URXVT
6482 "mouse_urxvt",
6483# endif
6484# ifdef FEAT_MOUSE_XTERM
6485 "mouse_xterm",
6486# endif
6487#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006488 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006489#ifdef FEAT_MBYTE_IME
6490 "multi_byte_ime",
6491#endif
6492#ifdef FEAT_MULTI_LANG
6493 "multi_lang",
6494#endif
6495#ifdef FEAT_MZSCHEME
6496#ifndef DYNAMIC_MZSCHEME
6497 "mzscheme",
6498#endif
6499#endif
6500#ifdef FEAT_NUM64
6501 "num64",
6502#endif
6503#ifdef FEAT_OLE
6504 "ole",
6505#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006506#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006508#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006509#ifdef FEAT_PATH_EXTRA
6510 "path_extra",
6511#endif
6512#ifdef FEAT_PERL
6513#ifndef DYNAMIC_PERL
6514 "perl",
6515#endif
6516#endif
6517#ifdef FEAT_PERSISTENT_UNDO
6518 "persistent_undo",
6519#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006520#if defined(FEAT_PYTHON)
6521 "python_compiled",
6522# if defined(DYNAMIC_PYTHON)
6523 "python_dynamic",
6524# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006525 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006526 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006527# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006528#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006529#if defined(FEAT_PYTHON3)
6530 "python3_compiled",
6531# if defined(DYNAMIC_PYTHON3)
6532 "python3_dynamic",
6533# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006534 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006535 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006536# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006537#endif
6538#ifdef FEAT_POSTSCRIPT
6539 "postscript",
6540#endif
6541#ifdef FEAT_PRINTER
6542 "printer",
6543#endif
6544#ifdef FEAT_PROFILE
6545 "profile",
6546#endif
6547#ifdef FEAT_RELTIME
6548 "reltime",
6549#endif
6550#ifdef FEAT_QUICKFIX
6551 "quickfix",
6552#endif
6553#ifdef FEAT_RIGHTLEFT
6554 "rightleft",
6555#endif
6556#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6557 "ruby",
6558#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006559 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006560#ifdef FEAT_CMDL_INFO
6561 "showcmd",
6562 "cmdline_info",
6563#endif
6564#ifdef FEAT_SIGNS
6565 "signs",
6566#endif
6567#ifdef FEAT_SMARTINDENT
6568 "smartindent",
6569#endif
6570#ifdef STARTUPTIME
6571 "startuptime",
6572#endif
6573#ifdef FEAT_STL_OPT
6574 "statusline",
6575#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006576#ifdef FEAT_NETBEANS_INTG
6577 "netbeans_intg",
6578#endif
6579#ifdef FEAT_SPELL
6580 "spell",
6581#endif
6582#ifdef FEAT_SYN_HL
6583 "syntax",
6584#endif
6585#if defined(USE_SYSTEM) || !defined(UNIX)
6586 "system",
6587#endif
6588#ifdef FEAT_TAG_BINS
6589 "tag_binary",
6590#endif
6591#ifdef FEAT_TAG_OLDSTATIC
6592 "tag_old_static",
6593#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006594#ifdef FEAT_TCL
6595# ifndef DYNAMIC_TCL
6596 "tcl",
6597# endif
6598#endif
6599#ifdef FEAT_TERMGUICOLORS
6600 "termguicolors",
6601#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006602#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006603 "terminal",
6604#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006605#ifdef TERMINFO
6606 "terminfo",
6607#endif
6608#ifdef FEAT_TERMRESPONSE
6609 "termresponse",
6610#endif
6611#ifdef FEAT_TEXTOBJ
6612 "textobjects",
6613#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006614#ifdef FEAT_TEXT_PROP
6615 "textprop",
6616#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006617#ifdef HAVE_TGETENT
6618 "tgetent",
6619#endif
6620#ifdef FEAT_TIMERS
6621 "timers",
6622#endif
6623#ifdef FEAT_TITLE
6624 "title",
6625#endif
6626#ifdef FEAT_TOOLBAR
6627 "toolbar",
6628#endif
6629#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6630 "unnamedplus",
6631#endif
6632#ifdef FEAT_USR_CMDS
6633 "user-commands", /* was accidentally included in 5.4 */
6634 "user_commands",
6635#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006636#ifdef FEAT_VARTABS
6637 "vartabs",
6638#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006639#ifdef FEAT_VIMINFO
6640 "viminfo",
6641#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006642 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006643 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006644 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006645 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006646 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006647#ifdef FEAT_VTP
6648 "vtp",
6649#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006650#ifdef FEAT_WILDIGN
6651 "wildignore",
6652#endif
6653#ifdef FEAT_WILDMENU
6654 "wildmenu",
6655#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006656 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006657#ifdef FEAT_WAK
6658 "winaltkeys",
6659#endif
6660#ifdef FEAT_WRITEBACKUP
6661 "writebackup",
6662#endif
6663#ifdef FEAT_XIM
6664 "xim",
6665#endif
6666#ifdef FEAT_XFONTSET
6667 "xfontset",
6668#endif
6669#ifdef FEAT_XPM_W32
6670 "xpm",
6671 "xpm_w32", /* for backward compatibility */
6672#else
6673# if defined(HAVE_XPM)
6674 "xpm",
6675# endif
6676#endif
6677#ifdef USE_XSMP
6678 "xsmp",
6679#endif
6680#ifdef USE_XSMP_INTERACT
6681 "xsmp_interact",
6682#endif
6683#ifdef FEAT_XCLIPBOARD
6684 "xterm_clipboard",
6685#endif
6686#ifdef FEAT_XTERM_SAVE
6687 "xterm_save",
6688#endif
6689#if defined(UNIX) && defined(FEAT_X11)
6690 "X11",
6691#endif
6692 NULL
6693 };
6694
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006695 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006696 for (i = 0; has_list[i] != NULL; ++i)
6697 if (STRICMP(name, has_list[i]) == 0)
6698 {
6699 n = TRUE;
6700 break;
6701 }
6702
6703 if (n == FALSE)
6704 {
6705 if (STRNICMP(name, "patch", 5) == 0)
6706 {
6707 if (name[5] == '-'
6708 && STRLEN(name) >= 11
6709 && vim_isdigit(name[6])
6710 && vim_isdigit(name[8])
6711 && vim_isdigit(name[10]))
6712 {
6713 int major = atoi((char *)name + 6);
6714 int minor = atoi((char *)name + 8);
6715
6716 /* Expect "patch-9.9.01234". */
6717 n = (major < VIM_VERSION_MAJOR
6718 || (major == VIM_VERSION_MAJOR
6719 && (minor < VIM_VERSION_MINOR
6720 || (minor == VIM_VERSION_MINOR
6721 && has_patch(atoi((char *)name + 10))))));
6722 }
6723 else
6724 n = has_patch(atoi((char *)name + 5));
6725 }
6726 else if (STRICMP(name, "vim_starting") == 0)
6727 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006728 else if (STRICMP(name, "ttyin") == 0)
6729 n = mch_input_isatty();
6730 else if (STRICMP(name, "ttyout") == 0)
6731 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006732 else if (STRICMP(name, "multi_byte_encoding") == 0)
6733 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006734#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006735 else if (STRICMP(name, "balloon_multiline") == 0)
6736 n = multiline_balloon_available();
6737#endif
6738#ifdef DYNAMIC_TCL
6739 else if (STRICMP(name, "tcl") == 0)
6740 n = tcl_enabled(FALSE);
6741#endif
6742#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6743 else if (STRICMP(name, "iconv") == 0)
6744 n = iconv_enabled(FALSE);
6745#endif
6746#ifdef DYNAMIC_LUA
6747 else if (STRICMP(name, "lua") == 0)
6748 n = lua_enabled(FALSE);
6749#endif
6750#ifdef DYNAMIC_MZSCHEME
6751 else if (STRICMP(name, "mzscheme") == 0)
6752 n = mzscheme_enabled(FALSE);
6753#endif
6754#ifdef DYNAMIC_RUBY
6755 else if (STRICMP(name, "ruby") == 0)
6756 n = ruby_enabled(FALSE);
6757#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006758#ifdef DYNAMIC_PYTHON
6759 else if (STRICMP(name, "python") == 0)
6760 n = python_enabled(FALSE);
6761#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006762#ifdef DYNAMIC_PYTHON3
6763 else if (STRICMP(name, "python3") == 0)
6764 n = python3_enabled(FALSE);
6765#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006766#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6767 else if (STRICMP(name, "pythonx") == 0)
6768 {
6769# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6770 if (p_pyx == 0)
6771 n = python3_enabled(FALSE) || python_enabled(FALSE);
6772 else if (p_pyx == 3)
6773 n = python3_enabled(FALSE);
6774 else if (p_pyx == 2)
6775 n = python_enabled(FALSE);
6776# elif defined(DYNAMIC_PYTHON)
6777 n = python_enabled(FALSE);
6778# elif defined(DYNAMIC_PYTHON3)
6779 n = python3_enabled(FALSE);
6780# endif
6781 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006782#endif
6783#ifdef DYNAMIC_PERL
6784 else if (STRICMP(name, "perl") == 0)
6785 n = perl_enabled(FALSE);
6786#endif
6787#ifdef FEAT_GUI
6788 else if (STRICMP(name, "gui_running") == 0)
6789 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006790# ifdef FEAT_BROWSE
6791 else if (STRICMP(name, "browse") == 0)
6792 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6793# endif
6794#endif
6795#ifdef FEAT_SYN_HL
6796 else if (STRICMP(name, "syntax_items") == 0)
6797 n = syntax_present(curwin);
6798#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006799#ifdef FEAT_VTP
6800 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006801 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006802#endif
6803#ifdef FEAT_NETBEANS_INTG
6804 else if (STRICMP(name, "netbeans_enabled") == 0)
6805 n = netbeans_active();
6806#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006807#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006808 else if (STRICMP(name, "terminal") == 0)
6809 n = terminal_enabled();
6810#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006811#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006812 else if (STRICMP(name, "conpty") == 0)
6813 n = use_conpty();
6814#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006815 }
6816
6817 rettv->vval.v_number = n;
6818}
6819
6820/*
6821 * "has_key()" function
6822 */
6823 static void
6824f_has_key(typval_T *argvars, typval_T *rettv)
6825{
6826 if (argvars[0].v_type != VAR_DICT)
6827 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006828 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006829 return;
6830 }
6831 if (argvars[0].vval.v_dict == NULL)
6832 return;
6833
6834 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006835 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006836}
6837
6838/*
6839 * "haslocaldir()" function
6840 */
6841 static void
6842f_haslocaldir(typval_T *argvars, typval_T *rettv)
6843{
6844 win_T *wp = NULL;
6845
6846 wp = find_tabwin(&argvars[0], &argvars[1]);
6847 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6848}
6849
6850/*
6851 * "hasmapto()" function
6852 */
6853 static void
6854f_hasmapto(typval_T *argvars, typval_T *rettv)
6855{
6856 char_u *name;
6857 char_u *mode;
6858 char_u buf[NUMBUFLEN];
6859 int abbr = FALSE;
6860
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006861 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862 if (argvars[1].v_type == VAR_UNKNOWN)
6863 mode = (char_u *)"nvo";
6864 else
6865 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006866 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006867 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006868 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006869 }
6870
6871 if (map_to_exists(name, mode, abbr))
6872 rettv->vval.v_number = TRUE;
6873 else
6874 rettv->vval.v_number = FALSE;
6875}
6876
6877/*
6878 * "histadd()" function
6879 */
6880 static void
6881f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6882{
6883#ifdef FEAT_CMDHIST
6884 int histype;
6885 char_u *str;
6886 char_u buf[NUMBUFLEN];
6887#endif
6888
6889 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006890 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006891 return;
6892#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006893 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006894 histype = str != NULL ? get_histtype(str) : -1;
6895 if (histype >= 0)
6896 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006897 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006898 if (*str != NUL)
6899 {
6900 init_history();
6901 add_to_history(histype, str, FALSE, NUL);
6902 rettv->vval.v_number = TRUE;
6903 return;
6904 }
6905 }
6906#endif
6907}
6908
6909/*
6910 * "histdel()" function
6911 */
6912 static void
6913f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6914{
6915#ifdef FEAT_CMDHIST
6916 int n;
6917 char_u buf[NUMBUFLEN];
6918 char_u *str;
6919
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006920 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006921 if (str == NULL)
6922 n = 0;
6923 else if (argvars[1].v_type == VAR_UNKNOWN)
6924 /* only one argument: clear entire history */
6925 n = clr_history(get_histtype(str));
6926 else if (argvars[1].v_type == VAR_NUMBER)
6927 /* index given: remove that entry */
6928 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006929 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006930 else
6931 /* string given: remove all matching entries */
6932 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006933 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006934 rettv->vval.v_number = n;
6935#endif
6936}
6937
6938/*
6939 * "histget()" function
6940 */
6941 static void
6942f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6943{
6944#ifdef FEAT_CMDHIST
6945 int type;
6946 int idx;
6947 char_u *str;
6948
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006949 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006950 if (str == NULL)
6951 rettv->vval.v_string = NULL;
6952 else
6953 {
6954 type = get_histtype(str);
6955 if (argvars[1].v_type == VAR_UNKNOWN)
6956 idx = get_history_idx(type);
6957 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006958 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006959 /* -1 on type error */
6960 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6961 }
6962#else
6963 rettv->vval.v_string = NULL;
6964#endif
6965 rettv->v_type = VAR_STRING;
6966}
6967
6968/*
6969 * "histnr()" function
6970 */
6971 static void
6972f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6973{
6974 int i;
6975
6976#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006977 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006978
6979 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6980 if (i >= HIST_CMD && i < HIST_COUNT)
6981 i = get_history_idx(i);
6982 else
6983#endif
6984 i = -1;
6985 rettv->vval.v_number = i;
6986}
6987
6988/*
6989 * "highlightID(name)" function
6990 */
6991 static void
6992f_hlID(typval_T *argvars, typval_T *rettv)
6993{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006994 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006995}
6996
6997/*
6998 * "highlight_exists()" function
6999 */
7000 static void
7001f_hlexists(typval_T *argvars, typval_T *rettv)
7002{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007003 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007004}
7005
7006/*
7007 * "hostname()" function
7008 */
7009 static void
7010f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
7011{
7012 char_u hostname[256];
7013
7014 mch_get_host_name(hostname, 256);
7015 rettv->v_type = VAR_STRING;
7016 rettv->vval.v_string = vim_strsave(hostname);
7017}
7018
7019/*
7020 * iconv() function
7021 */
7022 static void
7023f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
7024{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007025 char_u buf1[NUMBUFLEN];
7026 char_u buf2[NUMBUFLEN];
7027 char_u *from, *to, *str;
7028 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007029
7030 rettv->v_type = VAR_STRING;
7031 rettv->vval.v_string = NULL;
7032
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007033 str = tv_get_string(&argvars[0]);
7034 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
7035 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007036 vimconv.vc_type = CONV_NONE;
7037 convert_setup(&vimconv, from, to);
7038
7039 /* If the encodings are equal, no conversion needed. */
7040 if (vimconv.vc_type == CONV_NONE)
7041 rettv->vval.v_string = vim_strsave(str);
7042 else
7043 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
7044
7045 convert_setup(&vimconv, NULL, NULL);
7046 vim_free(from);
7047 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007048}
7049
7050/*
7051 * "indent()" function
7052 */
7053 static void
7054f_indent(typval_T *argvars, typval_T *rettv)
7055{
7056 linenr_T lnum;
7057
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007058 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007059 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7060 rettv->vval.v_number = get_indent_lnum(lnum);
7061 else
7062 rettv->vval.v_number = -1;
7063}
7064
7065/*
7066 * "index()" function
7067 */
7068 static void
7069f_index(typval_T *argvars, typval_T *rettv)
7070{
7071 list_T *l;
7072 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007073 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007074 long idx = 0;
7075 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007076 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007077
7078 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007079 if (argvars[0].v_type == VAR_BLOB)
7080 {
7081 typval_T tv;
7082 int start = 0;
7083
7084 if (argvars[2].v_type != VAR_UNKNOWN)
7085 {
7086 start = tv_get_number_chk(&argvars[2], &error);
7087 if (error)
7088 return;
7089 }
7090 b = argvars[0].vval.v_blob;
7091 if (b == NULL)
7092 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007093 if (start < 0)
7094 {
7095 start = blob_len(b) + start;
7096 if (start < 0)
7097 start = 0;
7098 }
7099
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007100 for (idx = start; idx < blob_len(b); ++idx)
7101 {
7102 tv.v_type = VAR_NUMBER;
7103 tv.vval.v_number = blob_get(b, idx);
7104 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7105 {
7106 rettv->vval.v_number = idx;
7107 return;
7108 }
7109 }
7110 return;
7111 }
7112 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007113 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007114 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007115 return;
7116 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007117
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 l = argvars[0].vval.v_list;
7119 if (l != NULL)
7120 {
7121 item = l->lv_first;
7122 if (argvars[2].v_type != VAR_UNKNOWN)
7123 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007124 /* Start at specified item. Use the cached index that list_find()
7125 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007126 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007127 idx = l->lv_idx;
7128 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007129 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007130 if (error)
7131 item = NULL;
7132 }
7133
7134 for ( ; item != NULL; item = item->li_next, ++idx)
7135 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7136 {
7137 rettv->vval.v_number = idx;
7138 break;
7139 }
7140 }
7141}
7142
7143static int inputsecret_flag = 0;
7144
7145/*
7146 * "input()" function
7147 * Also handles inputsecret() when inputsecret is set.
7148 */
7149 static void
7150f_input(typval_T *argvars, typval_T *rettv)
7151{
7152 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7153}
7154
7155/*
7156 * "inputdialog()" function
7157 */
7158 static void
7159f_inputdialog(typval_T *argvars, typval_T *rettv)
7160{
7161#if defined(FEAT_GUI_TEXTDIALOG)
7162 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7163 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7164 {
7165 char_u *message;
7166 char_u buf[NUMBUFLEN];
7167 char_u *defstr = (char_u *)"";
7168
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007169 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007170 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007171 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007172 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7173 else
7174 IObuff[0] = NUL;
7175 if (message != NULL && defstr != NULL
7176 && do_dialog(VIM_QUESTION, NULL, message,
7177 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7178 rettv->vval.v_string = vim_strsave(IObuff);
7179 else
7180 {
7181 if (message != NULL && defstr != NULL
7182 && argvars[1].v_type != VAR_UNKNOWN
7183 && argvars[2].v_type != VAR_UNKNOWN)
7184 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007185 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007186 else
7187 rettv->vval.v_string = NULL;
7188 }
7189 rettv->v_type = VAR_STRING;
7190 }
7191 else
7192#endif
7193 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7194}
7195
7196/*
7197 * "inputlist()" function
7198 */
7199 static void
7200f_inputlist(typval_T *argvars, typval_T *rettv)
7201{
7202 listitem_T *li;
7203 int selected;
7204 int mouse_used;
7205
7206#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007207 /* While starting up, there is no place to enter text. When running tests
7208 * with --not-a-term we assume feedkeys() will be used. */
7209 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007210 return;
7211#endif
7212 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7213 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007214 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007215 return;
7216 }
7217
7218 msg_start();
7219 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7220 lines_left = Rows; /* avoid more prompt */
7221 msg_scroll = TRUE;
7222 msg_clr_eos();
7223
7224 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7225 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007226 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007227 msg_putchar('\n');
7228 }
7229
7230 /* Ask for choice. */
7231 selected = prompt_for_number(&mouse_used);
7232 if (mouse_used)
7233 selected -= lines_left;
7234
7235 rettv->vval.v_number = selected;
7236}
7237
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007238static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7239
7240/*
7241 * "inputrestore()" function
7242 */
7243 static void
7244f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7245{
7246 if (ga_userinput.ga_len > 0)
7247 {
7248 --ga_userinput.ga_len;
7249 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7250 + ga_userinput.ga_len);
7251 /* default return is zero == OK */
7252 }
7253 else if (p_verbose > 1)
7254 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007255 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007256 rettv->vval.v_number = 1; /* Failed */
7257 }
7258}
7259
7260/*
7261 * "inputsave()" function
7262 */
7263 static void
7264f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7265{
7266 /* Add an entry to the stack of typeahead storage. */
7267 if (ga_grow(&ga_userinput, 1) == OK)
7268 {
7269 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7270 + ga_userinput.ga_len);
7271 ++ga_userinput.ga_len;
7272 /* default return is zero == OK */
7273 }
7274 else
7275 rettv->vval.v_number = 1; /* Failed */
7276}
7277
7278/*
7279 * "inputsecret()" function
7280 */
7281 static void
7282f_inputsecret(typval_T *argvars, typval_T *rettv)
7283{
7284 ++cmdline_star;
7285 ++inputsecret_flag;
7286 f_input(argvars, rettv);
7287 --cmdline_star;
7288 --inputsecret_flag;
7289}
7290
7291/*
7292 * "insert()" function
7293 */
7294 static void
7295f_insert(typval_T *argvars, typval_T *rettv)
7296{
7297 long before = 0;
7298 listitem_T *item;
7299 list_T *l;
7300 int error = FALSE;
7301
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007302 if (argvars[0].v_type == VAR_BLOB)
7303 {
7304 int val, len;
7305 char_u *p;
7306
7307 len = blob_len(argvars[0].vval.v_blob);
7308 if (argvars[2].v_type != VAR_UNKNOWN)
7309 {
7310 before = (long)tv_get_number_chk(&argvars[2], &error);
7311 if (error)
7312 return; // type error; errmsg already given
7313 if (before < 0 || before > len)
7314 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007315 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007316 return;
7317 }
7318 }
7319 val = tv_get_number_chk(&argvars[1], &error);
7320 if (error)
7321 return;
7322 if (val < 0 || val > 255)
7323 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007324 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007325 return;
7326 }
7327
7328 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7329 return;
7330 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7331 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7332 *(p + before) = val;
7333 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7334
7335 copy_tv(&argvars[0], rettv);
7336 }
7337 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007338 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007339 else if ((l = argvars[0].vval.v_list) != NULL
7340 && !var_check_lock(l->lv_lock,
7341 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007342 {
7343 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007344 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007345 if (error)
7346 return; /* type error; errmsg already given */
7347
7348 if (before == l->lv_len)
7349 item = NULL;
7350 else
7351 {
7352 item = list_find(l, before);
7353 if (item == NULL)
7354 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007355 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007356 l = NULL;
7357 }
7358 }
7359 if (l != NULL)
7360 {
7361 list_insert_tv(l, &argvars[1], item);
7362 copy_tv(&argvars[0], rettv);
7363 }
7364 }
7365}
7366
7367/*
7368 * "invert(expr)" function
7369 */
7370 static void
7371f_invert(typval_T *argvars, typval_T *rettv)
7372{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007373 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007374}
7375
7376/*
7377 * "isdirectory()" function
7378 */
7379 static void
7380f_isdirectory(typval_T *argvars, typval_T *rettv)
7381{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007382 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007383}
7384
7385/*
7386 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7387 * or it refers to a List or Dictionary that is locked.
7388 */
7389 static int
7390tv_islocked(typval_T *tv)
7391{
7392 return (tv->v_lock & VAR_LOCKED)
7393 || (tv->v_type == VAR_LIST
7394 && tv->vval.v_list != NULL
7395 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7396 || (tv->v_type == VAR_DICT
7397 && tv->vval.v_dict != NULL
7398 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7399}
7400
7401/*
7402 * "islocked()" function
7403 */
7404 static void
7405f_islocked(typval_T *argvars, typval_T *rettv)
7406{
7407 lval_T lv;
7408 char_u *end;
7409 dictitem_T *di;
7410
7411 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007412 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007413 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007414 if (end != NULL && lv.ll_name != NULL)
7415 {
7416 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007417 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007418 else
7419 {
7420 if (lv.ll_tv == NULL)
7421 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007422 di = find_var(lv.ll_name, NULL, TRUE);
7423 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007424 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007425 /* Consider a variable locked when:
7426 * 1. the variable itself is locked
7427 * 2. the value of the variable is locked.
7428 * 3. the List or Dict value is locked.
7429 */
7430 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7431 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432 }
7433 }
7434 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007435 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007436 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007437 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007438 else if (lv.ll_list != NULL)
7439 /* List item. */
7440 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7441 else
7442 /* Dictionary item. */
7443 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7444 }
7445 }
7446
7447 clear_lval(&lv);
7448}
7449
7450#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7451/*
7452 * "isnan()" function
7453 */
7454 static void
7455f_isnan(typval_T *argvars, typval_T *rettv)
7456{
7457 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7458 && isnan(argvars[0].vval.v_float);
7459}
7460#endif
7461
7462/*
7463 * "items(dict)" function
7464 */
7465 static void
7466f_items(typval_T *argvars, typval_T *rettv)
7467{
7468 dict_list(argvars, rettv, 2);
7469}
7470
7471#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7472/*
7473 * Get the job from the argument.
7474 * Returns NULL if the job is invalid.
7475 */
7476 static job_T *
7477get_job_arg(typval_T *tv)
7478{
7479 job_T *job;
7480
7481 if (tv->v_type != VAR_JOB)
7482 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007483 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007484 return NULL;
7485 }
7486 job = tv->vval.v_job;
7487
7488 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007489 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007490 return job;
7491}
7492
7493/*
7494 * "job_getchannel()" function
7495 */
7496 static void
7497f_job_getchannel(typval_T *argvars, typval_T *rettv)
7498{
7499 job_T *job = get_job_arg(&argvars[0]);
7500
7501 if (job != NULL)
7502 {
7503 rettv->v_type = VAR_CHANNEL;
7504 rettv->vval.v_channel = job->jv_channel;
7505 if (job->jv_channel != NULL)
7506 ++job->jv_channel->ch_refcount;
7507 }
7508}
7509
7510/*
7511 * "job_info()" function
7512 */
7513 static void
7514f_job_info(typval_T *argvars, typval_T *rettv)
7515{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007516 if (argvars[0].v_type != VAR_UNKNOWN)
7517 {
7518 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007520 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7521 job_info(job, rettv->vval.v_dict);
7522 }
7523 else if (rettv_list_alloc(rettv) == OK)
7524 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007525}
7526
7527/*
7528 * "job_setoptions()" function
7529 */
7530 static void
7531f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7532{
7533 job_T *job = get_job_arg(&argvars[0]);
7534 jobopt_T opt;
7535
7536 if (job == NULL)
7537 return;
7538 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007539 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007540 job_set_options(job, &opt);
7541 free_job_options(&opt);
7542}
7543
7544/*
7545 * "job_start()" function
7546 */
7547 static void
7548f_job_start(typval_T *argvars, typval_T *rettv)
7549{
7550 rettv->v_type = VAR_JOB;
7551 if (check_restricted() || check_secure())
7552 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007553 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007554}
7555
7556/*
7557 * "job_status()" function
7558 */
7559 static void
7560f_job_status(typval_T *argvars, typval_T *rettv)
7561{
7562 job_T *job = get_job_arg(&argvars[0]);
7563
7564 if (job != NULL)
7565 {
7566 rettv->v_type = VAR_STRING;
7567 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7568 }
7569}
7570
7571/*
7572 * "job_stop()" function
7573 */
7574 static void
7575f_job_stop(typval_T *argvars, typval_T *rettv)
7576{
7577 job_T *job = get_job_arg(&argvars[0]);
7578
7579 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007580 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007581}
7582#endif
7583
7584/*
7585 * "join()" function
7586 */
7587 static void
7588f_join(typval_T *argvars, typval_T *rettv)
7589{
7590 garray_T ga;
7591 char_u *sep;
7592
7593 if (argvars[0].v_type != VAR_LIST)
7594 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007595 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007596 return;
7597 }
7598 if (argvars[0].vval.v_list == NULL)
7599 return;
7600 if (argvars[1].v_type == VAR_UNKNOWN)
7601 sep = (char_u *)" ";
7602 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007603 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007604
7605 rettv->v_type = VAR_STRING;
7606
7607 if (sep != NULL)
7608 {
7609 ga_init2(&ga, (int)sizeof(char), 80);
7610 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7611 ga_append(&ga, NUL);
7612 rettv->vval.v_string = (char_u *)ga.ga_data;
7613 }
7614 else
7615 rettv->vval.v_string = NULL;
7616}
7617
7618/*
7619 * "js_decode()" function
7620 */
7621 static void
7622f_js_decode(typval_T *argvars, typval_T *rettv)
7623{
7624 js_read_T reader;
7625
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007626 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007627 reader.js_fill = NULL;
7628 reader.js_used = 0;
7629 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007630 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007631}
7632
7633/*
7634 * "js_encode()" function
7635 */
7636 static void
7637f_js_encode(typval_T *argvars, typval_T *rettv)
7638{
7639 rettv->v_type = VAR_STRING;
7640 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7641}
7642
7643/*
7644 * "json_decode()" function
7645 */
7646 static void
7647f_json_decode(typval_T *argvars, typval_T *rettv)
7648{
7649 js_read_T reader;
7650
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007651 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007652 reader.js_fill = NULL;
7653 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007654 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007655}
7656
7657/*
7658 * "json_encode()" function
7659 */
7660 static void
7661f_json_encode(typval_T *argvars, typval_T *rettv)
7662{
7663 rettv->v_type = VAR_STRING;
7664 rettv->vval.v_string = json_encode(&argvars[0], 0);
7665}
7666
7667/*
7668 * "keys()" function
7669 */
7670 static void
7671f_keys(typval_T *argvars, typval_T *rettv)
7672{
7673 dict_list(argvars, rettv, 0);
7674}
7675
7676/*
7677 * "last_buffer_nr()" function.
7678 */
7679 static void
7680f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7681{
7682 int n = 0;
7683 buf_T *buf;
7684
Bram Moolenaar29323592016-07-24 22:04:11 +02007685 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007686 if (n < buf->b_fnum)
7687 n = buf->b_fnum;
7688
7689 rettv->vval.v_number = n;
7690}
7691
7692/*
7693 * "len()" function
7694 */
7695 static void
7696f_len(typval_T *argvars, typval_T *rettv)
7697{
7698 switch (argvars[0].v_type)
7699 {
7700 case VAR_STRING:
7701 case VAR_NUMBER:
7702 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007703 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007704 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007705 case VAR_BLOB:
7706 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7707 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007708 case VAR_LIST:
7709 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7710 break;
7711 case VAR_DICT:
7712 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7713 break;
7714 case VAR_UNKNOWN:
7715 case VAR_SPECIAL:
7716 case VAR_FLOAT:
7717 case VAR_FUNC:
7718 case VAR_PARTIAL:
7719 case VAR_JOB:
7720 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007721 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722 break;
7723 }
7724}
7725
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007726 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007727libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007728{
7729#ifdef FEAT_LIBCALL
7730 char_u *string_in;
7731 char_u **string_result;
7732 int nr_result;
7733#endif
7734
7735 rettv->v_type = type;
7736 if (type != VAR_NUMBER)
7737 rettv->vval.v_string = NULL;
7738
7739 if (check_restricted() || check_secure())
7740 return;
7741
7742#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007743 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007744 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7745 {
7746 string_in = NULL;
7747 if (argvars[2].v_type == VAR_STRING)
7748 string_in = argvars[2].vval.v_string;
7749 if (type == VAR_NUMBER)
7750 string_result = NULL;
7751 else
7752 string_result = &rettv->vval.v_string;
7753 if (mch_libcall(argvars[0].vval.v_string,
7754 argvars[1].vval.v_string,
7755 string_in,
7756 argvars[2].vval.v_number,
7757 string_result,
7758 &nr_result) == OK
7759 && type == VAR_NUMBER)
7760 rettv->vval.v_number = nr_result;
7761 }
7762#endif
7763}
7764
7765/*
7766 * "libcall()" function
7767 */
7768 static void
7769f_libcall(typval_T *argvars, typval_T *rettv)
7770{
7771 libcall_common(argvars, rettv, VAR_STRING);
7772}
7773
7774/*
7775 * "libcallnr()" function
7776 */
7777 static void
7778f_libcallnr(typval_T *argvars, typval_T *rettv)
7779{
7780 libcall_common(argvars, rettv, VAR_NUMBER);
7781}
7782
7783/*
7784 * "line(string)" function
7785 */
7786 static void
7787f_line(typval_T *argvars, typval_T *rettv)
7788{
7789 linenr_T lnum = 0;
7790 pos_T *fp;
7791 int fnum;
7792
7793 fp = var2fpos(&argvars[0], TRUE, &fnum);
7794 if (fp != NULL)
7795 lnum = fp->lnum;
7796 rettv->vval.v_number = lnum;
7797}
7798
7799/*
7800 * "line2byte(lnum)" function
7801 */
7802 static void
7803f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7804{
7805#ifndef FEAT_BYTEOFF
7806 rettv->vval.v_number = -1;
7807#else
7808 linenr_T lnum;
7809
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007810 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007811 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7812 rettv->vval.v_number = -1;
7813 else
7814 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7815 if (rettv->vval.v_number >= 0)
7816 ++rettv->vval.v_number;
7817#endif
7818}
7819
7820/*
7821 * "lispindent(lnum)" function
7822 */
7823 static void
7824f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7825{
7826#ifdef FEAT_LISP
7827 pos_T pos;
7828 linenr_T lnum;
7829
7830 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007831 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007832 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7833 {
7834 curwin->w_cursor.lnum = lnum;
7835 rettv->vval.v_number = get_lisp_indent();
7836 curwin->w_cursor = pos;
7837 }
7838 else
7839#endif
7840 rettv->vval.v_number = -1;
7841}
7842
7843/*
7844 * "localtime()" function
7845 */
7846 static void
7847f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7848{
7849 rettv->vval.v_number = (varnumber_T)time(NULL);
7850}
7851
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007852 static void
7853get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7854{
7855 char_u *keys;
7856 char_u *which;
7857 char_u buf[NUMBUFLEN];
7858 char_u *keys_buf = NULL;
7859 char_u *rhs;
7860 int mode;
7861 int abbr = FALSE;
7862 int get_dict = FALSE;
7863 mapblock_T *mp;
7864 int buffer_local;
7865
7866 /* return empty string for failure */
7867 rettv->v_type = VAR_STRING;
7868 rettv->vval.v_string = NULL;
7869
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007870 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007871 if (*keys == NUL)
7872 return;
7873
7874 if (argvars[1].v_type != VAR_UNKNOWN)
7875 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007876 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007877 if (argvars[2].v_type != VAR_UNKNOWN)
7878 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007879 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007880 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007881 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882 }
7883 }
7884 else
7885 which = (char_u *)"";
7886 if (which == NULL)
7887 return;
7888
7889 mode = get_map_mode(&which, 0);
7890
7891 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7892 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7893 vim_free(keys_buf);
7894
7895 if (!get_dict)
7896 {
7897 /* Return a string. */
7898 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007899 {
7900 if (*rhs == NUL)
7901 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7902 else
7903 rettv->vval.v_string = str2special_save(rhs, FALSE);
7904 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007905
7906 }
7907 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7908 {
7909 /* Return a dictionary. */
7910 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7911 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7912 dict_T *dict = rettv->vval.v_dict;
7913
Bram Moolenaare0be1672018-07-08 16:50:37 +02007914 dict_add_string(dict, "lhs", lhs);
7915 dict_add_string(dict, "rhs", mp->m_orig_str);
7916 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7917 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7918 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007919 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7920 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007921 dict_add_number(dict, "buffer", (long)buffer_local);
7922 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7923 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007924
7925 vim_free(lhs);
7926 vim_free(mapmode);
7927 }
7928}
7929
7930#ifdef FEAT_FLOAT
7931/*
7932 * "log()" function
7933 */
7934 static void
7935f_log(typval_T *argvars, typval_T *rettv)
7936{
7937 float_T f = 0.0;
7938
7939 rettv->v_type = VAR_FLOAT;
7940 if (get_float_arg(argvars, &f) == OK)
7941 rettv->vval.v_float = log(f);
7942 else
7943 rettv->vval.v_float = 0.0;
7944}
7945
7946/*
7947 * "log10()" function
7948 */
7949 static void
7950f_log10(typval_T *argvars, typval_T *rettv)
7951{
7952 float_T f = 0.0;
7953
7954 rettv->v_type = VAR_FLOAT;
7955 if (get_float_arg(argvars, &f) == OK)
7956 rettv->vval.v_float = log10(f);
7957 else
7958 rettv->vval.v_float = 0.0;
7959}
7960#endif
7961
7962#ifdef FEAT_LUA
7963/*
7964 * "luaeval()" function
7965 */
7966 static void
7967f_luaeval(typval_T *argvars, typval_T *rettv)
7968{
7969 char_u *str;
7970 char_u buf[NUMBUFLEN];
7971
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007972 if (check_restricted() || check_secure())
7973 return;
7974
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007975 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007976 do_luaeval(str, argvars + 1, rettv);
7977}
7978#endif
7979
7980/*
7981 * "map()" function
7982 */
7983 static void
7984f_map(typval_T *argvars, typval_T *rettv)
7985{
7986 filter_map(argvars, rettv, TRUE);
7987}
7988
7989/*
7990 * "maparg()" function
7991 */
7992 static void
7993f_maparg(typval_T *argvars, typval_T *rettv)
7994{
7995 get_maparg(argvars, rettv, TRUE);
7996}
7997
7998/*
7999 * "mapcheck()" function
8000 */
8001 static void
8002f_mapcheck(typval_T *argvars, typval_T *rettv)
8003{
8004 get_maparg(argvars, rettv, FALSE);
8005}
8006
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008007typedef enum
8008{
8009 MATCH_END, /* matchend() */
8010 MATCH_MATCH, /* match() */
8011 MATCH_STR, /* matchstr() */
8012 MATCH_LIST, /* matchlist() */
8013 MATCH_POS /* matchstrpos() */
8014} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008015
8016 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008017find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008018{
8019 char_u *str = NULL;
8020 long len = 0;
8021 char_u *expr = NULL;
8022 char_u *pat;
8023 regmatch_T regmatch;
8024 char_u patbuf[NUMBUFLEN];
8025 char_u strbuf[NUMBUFLEN];
8026 char_u *save_cpo;
8027 long start = 0;
8028 long nth = 1;
8029 colnr_T startcol = 0;
8030 int match = 0;
8031 list_T *l = NULL;
8032 listitem_T *li = NULL;
8033 long idx = 0;
8034 char_u *tofree = NULL;
8035
8036 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8037 save_cpo = p_cpo;
8038 p_cpo = (char_u *)"";
8039
8040 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008041 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008043 /* type MATCH_LIST: return empty list when there are no matches.
8044 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008045 if (rettv_list_alloc(rettv) == FAIL)
8046 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008047 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008048 && (list_append_string(rettv->vval.v_list,
8049 (char_u *)"", 0) == FAIL
8050 || list_append_number(rettv->vval.v_list,
8051 (varnumber_T)-1) == FAIL
8052 || list_append_number(rettv->vval.v_list,
8053 (varnumber_T)-1) == FAIL
8054 || list_append_number(rettv->vval.v_list,
8055 (varnumber_T)-1) == FAIL))
8056 {
8057 list_free(rettv->vval.v_list);
8058 rettv->vval.v_list = NULL;
8059 goto theend;
8060 }
8061 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008062 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008063 {
8064 rettv->v_type = VAR_STRING;
8065 rettv->vval.v_string = NULL;
8066 }
8067
8068 if (argvars[0].v_type == VAR_LIST)
8069 {
8070 if ((l = argvars[0].vval.v_list) == NULL)
8071 goto theend;
8072 li = l->lv_first;
8073 }
8074 else
8075 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008076 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008077 len = (long)STRLEN(str);
8078 }
8079
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008080 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008081 if (pat == NULL)
8082 goto theend;
8083
8084 if (argvars[2].v_type != VAR_UNKNOWN)
8085 {
8086 int error = FALSE;
8087
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008088 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008089 if (error)
8090 goto theend;
8091 if (l != NULL)
8092 {
8093 li = list_find(l, start);
8094 if (li == NULL)
8095 goto theend;
8096 idx = l->lv_idx; /* use the cached index */
8097 }
8098 else
8099 {
8100 if (start < 0)
8101 start = 0;
8102 if (start > len)
8103 goto theend;
8104 /* When "count" argument is there ignore matches before "start",
8105 * otherwise skip part of the string. Differs when pattern is "^"
8106 * or "\<". */
8107 if (argvars[3].v_type != VAR_UNKNOWN)
8108 startcol = start;
8109 else
8110 {
8111 str += start;
8112 len -= start;
8113 }
8114 }
8115
8116 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008117 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008118 if (error)
8119 goto theend;
8120 }
8121
8122 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8123 if (regmatch.regprog != NULL)
8124 {
8125 regmatch.rm_ic = p_ic;
8126
8127 for (;;)
8128 {
8129 if (l != NULL)
8130 {
8131 if (li == NULL)
8132 {
8133 match = FALSE;
8134 break;
8135 }
8136 vim_free(tofree);
8137 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8138 if (str == NULL)
8139 break;
8140 }
8141
8142 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8143
8144 if (match && --nth <= 0)
8145 break;
8146 if (l == NULL && !match)
8147 break;
8148
8149 /* Advance to just after the match. */
8150 if (l != NULL)
8151 {
8152 li = li->li_next;
8153 ++idx;
8154 }
8155 else
8156 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008157 startcol = (colnr_T)(regmatch.startp[0]
8158 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008159 if (startcol > (colnr_T)len
8160 || str + startcol <= regmatch.startp[0])
8161 {
8162 match = FALSE;
8163 break;
8164 }
8165 }
8166 }
8167
8168 if (match)
8169 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008170 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008171 {
8172 listitem_T *li1 = rettv->vval.v_list->lv_first;
8173 listitem_T *li2 = li1->li_next;
8174 listitem_T *li3 = li2->li_next;
8175 listitem_T *li4 = li3->li_next;
8176
8177 vim_free(li1->li_tv.vval.v_string);
8178 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8179 (int)(regmatch.endp[0] - regmatch.startp[0]));
8180 li3->li_tv.vval.v_number =
8181 (varnumber_T)(regmatch.startp[0] - expr);
8182 li4->li_tv.vval.v_number =
8183 (varnumber_T)(regmatch.endp[0] - expr);
8184 if (l != NULL)
8185 li2->li_tv.vval.v_number = (varnumber_T)idx;
8186 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008187 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008188 {
8189 int i;
8190
8191 /* return list with matched string and submatches */
8192 for (i = 0; i < NSUBEXP; ++i)
8193 {
8194 if (regmatch.endp[i] == NULL)
8195 {
8196 if (list_append_string(rettv->vval.v_list,
8197 (char_u *)"", 0) == FAIL)
8198 break;
8199 }
8200 else if (list_append_string(rettv->vval.v_list,
8201 regmatch.startp[i],
8202 (int)(regmatch.endp[i] - regmatch.startp[i]))
8203 == FAIL)
8204 break;
8205 }
8206 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008207 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008208 {
8209 /* return matched string */
8210 if (l != NULL)
8211 copy_tv(&li->li_tv, rettv);
8212 else
8213 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8214 (int)(regmatch.endp[0] - regmatch.startp[0]));
8215 }
8216 else if (l != NULL)
8217 rettv->vval.v_number = idx;
8218 else
8219 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008220 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008221 rettv->vval.v_number =
8222 (varnumber_T)(regmatch.startp[0] - str);
8223 else
8224 rettv->vval.v_number =
8225 (varnumber_T)(regmatch.endp[0] - str);
8226 rettv->vval.v_number += (varnumber_T)(str - expr);
8227 }
8228 }
8229 vim_regfree(regmatch.regprog);
8230 }
8231
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008232theend:
8233 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008234 /* matchstrpos() without a list: drop the second item. */
8235 listitem_remove(rettv->vval.v_list,
8236 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008237 vim_free(tofree);
8238 p_cpo = save_cpo;
8239}
8240
8241/*
8242 * "match()" function
8243 */
8244 static void
8245f_match(typval_T *argvars, typval_T *rettv)
8246{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008247 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008248}
8249
Bram Moolenaar95e51472018-07-28 16:55:56 +02008250#ifdef FEAT_SEARCH_EXTRA
8251 static int
8252matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8253{
8254 dictitem_T *di;
8255
8256 if (tv->v_type != VAR_DICT)
8257 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008258 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008259 return FAIL;
8260 }
8261
8262 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008263 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008264 (char_u *)"conceal", FALSE);
8265
8266 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8267 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008268 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008269 if (*win == NULL)
8270 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01008271 emsg(_(e_invalwindow));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008272 return FAIL;
8273 }
8274 }
8275
8276 return OK;
8277}
8278#endif
8279
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008280/*
8281 * "matchadd()" function
8282 */
8283 static void
8284f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8285{
8286#ifdef FEAT_SEARCH_EXTRA
8287 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008288 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8289 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008290 int prio = 10; /* default priority */
8291 int id = -1;
8292 int error = FALSE;
8293 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008294 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008295
8296 rettv->vval.v_number = -1;
8297
8298 if (grp == NULL || pat == NULL)
8299 return;
8300 if (argvars[2].v_type != VAR_UNKNOWN)
8301 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008302 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008303 if (argvars[3].v_type != VAR_UNKNOWN)
8304 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008305 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008306 if (argvars[4].v_type != VAR_UNKNOWN
8307 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8308 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008309 }
8310 }
8311 if (error == TRUE)
8312 return;
8313 if (id >= 1 && id <= 3)
8314 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008315 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008316 return;
8317 }
8318
Bram Moolenaar95e51472018-07-28 16:55:56 +02008319 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008320 conceal_char);
8321#endif
8322}
8323
8324/*
8325 * "matchaddpos()" function
8326 */
8327 static void
8328f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8329{
8330#ifdef FEAT_SEARCH_EXTRA
8331 char_u buf[NUMBUFLEN];
8332 char_u *group;
8333 int prio = 10;
8334 int id = -1;
8335 int error = FALSE;
8336 list_T *l;
8337 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008338 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008339
8340 rettv->vval.v_number = -1;
8341
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008342 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008343 if (group == NULL)
8344 return;
8345
8346 if (argvars[1].v_type != VAR_LIST)
8347 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008348 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008349 return;
8350 }
8351 l = argvars[1].vval.v_list;
8352 if (l == NULL)
8353 return;
8354
8355 if (argvars[2].v_type != VAR_UNKNOWN)
8356 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008357 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008358 if (argvars[3].v_type != VAR_UNKNOWN)
8359 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008360 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008361
8362 if (argvars[4].v_type != VAR_UNKNOWN
8363 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8364 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008365 }
8366 }
8367 if (error == TRUE)
8368 return;
8369
8370 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8371 if (id == 1 || id == 2)
8372 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008373 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008374 return;
8375 }
8376
Bram Moolenaar95e51472018-07-28 16:55:56 +02008377 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008378 conceal_char);
8379#endif
8380}
8381
8382/*
8383 * "matcharg()" function
8384 */
8385 static void
8386f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8387{
8388 if (rettv_list_alloc(rettv) == OK)
8389 {
8390#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008391 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008392 matchitem_T *m;
8393
8394 if (id >= 1 && id <= 3)
8395 {
8396 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8397 {
8398 list_append_string(rettv->vval.v_list,
8399 syn_id2name(m->hlg_id), -1);
8400 list_append_string(rettv->vval.v_list, m->pattern, -1);
8401 }
8402 else
8403 {
8404 list_append_string(rettv->vval.v_list, NULL, -1);
8405 list_append_string(rettv->vval.v_list, NULL, -1);
8406 }
8407 }
8408#endif
8409 }
8410}
8411
8412/*
8413 * "matchdelete()" function
8414 */
8415 static void
8416f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8417{
8418#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01008419 win_T *win = get_optional_window(argvars, 1);
8420
8421 if (win == NULL)
8422 rettv->vval.v_number = -1;
8423 else
8424 rettv->vval.v_number = match_delete(win,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008425 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008426#endif
8427}
8428
8429/*
8430 * "matchend()" function
8431 */
8432 static void
8433f_matchend(typval_T *argvars, typval_T *rettv)
8434{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008435 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008436}
8437
8438/*
8439 * "matchlist()" function
8440 */
8441 static void
8442f_matchlist(typval_T *argvars, typval_T *rettv)
8443{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008444 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008445}
8446
8447/*
8448 * "matchstr()" function
8449 */
8450 static void
8451f_matchstr(typval_T *argvars, typval_T *rettv)
8452{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008453 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008454}
8455
8456/*
8457 * "matchstrpos()" function
8458 */
8459 static void
8460f_matchstrpos(typval_T *argvars, typval_T *rettv)
8461{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008462 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008463}
8464
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008465 static void
8466max_min(typval_T *argvars, typval_T *rettv, int domax)
8467{
8468 varnumber_T n = 0;
8469 varnumber_T i;
8470 int error = FALSE;
8471
8472 if (argvars[0].v_type == VAR_LIST)
8473 {
8474 list_T *l;
8475 listitem_T *li;
8476
8477 l = argvars[0].vval.v_list;
8478 if (l != NULL)
8479 {
8480 li = l->lv_first;
8481 if (li != NULL)
8482 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008483 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008484 for (;;)
8485 {
8486 li = li->li_next;
8487 if (li == NULL)
8488 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008489 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008490 if (domax ? i > n : i < n)
8491 n = i;
8492 }
8493 }
8494 }
8495 }
8496 else if (argvars[0].v_type == VAR_DICT)
8497 {
8498 dict_T *d;
8499 int first = TRUE;
8500 hashitem_T *hi;
8501 int todo;
8502
8503 d = argvars[0].vval.v_dict;
8504 if (d != NULL)
8505 {
8506 todo = (int)d->dv_hashtab.ht_used;
8507 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8508 {
8509 if (!HASHITEM_EMPTY(hi))
8510 {
8511 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008512 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008513 if (first)
8514 {
8515 n = i;
8516 first = FALSE;
8517 }
8518 else if (domax ? i > n : i < n)
8519 n = i;
8520 }
8521 }
8522 }
8523 }
8524 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008525 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008526 rettv->vval.v_number = error ? 0 : n;
8527}
8528
8529/*
8530 * "max()" function
8531 */
8532 static void
8533f_max(typval_T *argvars, typval_T *rettv)
8534{
8535 max_min(argvars, rettv, TRUE);
8536}
8537
8538/*
8539 * "min()" function
8540 */
8541 static void
8542f_min(typval_T *argvars, typval_T *rettv)
8543{
8544 max_min(argvars, rettv, FALSE);
8545}
8546
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008547/*
8548 * Create the directory in which "dir" is located, and higher levels when
8549 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008550 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008551 */
8552 static int
8553mkdir_recurse(char_u *dir, int prot)
8554{
8555 char_u *p;
8556 char_u *updir;
8557 int r = FAIL;
8558
8559 /* Get end of directory name in "dir".
8560 * We're done when it's "/" or "c:/". */
8561 p = gettail_sep(dir);
8562 if (p <= get_past_head(dir))
8563 return OK;
8564
8565 /* If the directory exists we're done. Otherwise: create it.*/
8566 updir = vim_strnsave(dir, (int)(p - dir));
8567 if (updir == NULL)
8568 return FAIL;
8569 if (mch_isdir(updir))
8570 r = OK;
8571 else if (mkdir_recurse(updir, prot) == OK)
8572 r = vim_mkdir_emsg(updir, prot);
8573 vim_free(updir);
8574 return r;
8575}
8576
8577#ifdef vim_mkdir
8578/*
8579 * "mkdir()" function
8580 */
8581 static void
8582f_mkdir(typval_T *argvars, typval_T *rettv)
8583{
8584 char_u *dir;
8585 char_u buf[NUMBUFLEN];
8586 int prot = 0755;
8587
8588 rettv->vval.v_number = FAIL;
8589 if (check_restricted() || check_secure())
8590 return;
8591
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008592 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008593 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008594 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008595
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008596 if (*gettail(dir) == NUL)
8597 /* remove trailing slashes */
8598 *gettail_sep(dir) = NUL;
8599
8600 if (argvars[1].v_type != VAR_UNKNOWN)
8601 {
8602 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008603 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008604 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008605 if (prot == -1)
8606 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008607 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008608 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008609 {
8610 if (mch_isdir(dir))
8611 {
8612 /* With the "p" flag it's OK if the dir already exists. */
8613 rettv->vval.v_number = OK;
8614 return;
8615 }
8616 mkdir_recurse(dir, prot);
8617 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008618 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008619 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008620}
8621#endif
8622
8623/*
8624 * "mode()" function
8625 */
8626 static void
8627f_mode(typval_T *argvars, typval_T *rettv)
8628{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008629 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008630
Bram Moolenaar612cc382018-07-29 15:34:26 +02008631 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008632
8633 if (time_for_testing == 93784)
8634 {
8635 /* Testing the two-character code. */
8636 buf[0] = 'x';
8637 buf[1] = '!';
8638 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008639#ifdef FEAT_TERMINAL
8640 else if (term_use_loop())
8641 buf[0] = 't';
8642#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008643 else if (VIsual_active)
8644 {
8645 if (VIsual_select)
8646 buf[0] = VIsual_mode + 's' - 'v';
8647 else
8648 buf[0] = VIsual_mode;
8649 }
8650 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8651 || State == CONFIRM)
8652 {
8653 buf[0] = 'r';
8654 if (State == ASKMORE)
8655 buf[1] = 'm';
8656 else if (State == CONFIRM)
8657 buf[1] = '?';
8658 }
8659 else if (State == EXTERNCMD)
8660 buf[0] = '!';
8661 else if (State & INSERT)
8662 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008663 if (State & VREPLACE_FLAG)
8664 {
8665 buf[0] = 'R';
8666 buf[1] = 'v';
8667 }
8668 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008669 {
8670 if (State & REPLACE_FLAG)
8671 buf[0] = 'R';
8672 else
8673 buf[0] = 'i';
8674#ifdef FEAT_INS_EXPAND
8675 if (ins_compl_active())
8676 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008677 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008678 buf[1] = 'x';
8679#endif
8680 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008681 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008682 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008683 {
8684 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008685 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008686 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008687 else if (exmode_active == EXMODE_NORMAL)
8688 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008689 }
8690 else
8691 {
8692 buf[0] = 'n';
8693 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008694 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008695 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008696 // to be able to detect force-linewise/blockwise/characterwise operations
8697 buf[2] = motion_force;
8698 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008699 else if (restart_edit == 'I' || restart_edit == 'R'
8700 || restart_edit == 'V')
8701 {
8702 buf[1] = 'i';
8703 buf[2] = restart_edit;
8704 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008705 }
8706
8707 /* Clear out the minor mode when the argument is not a non-zero number or
8708 * non-empty string. */
8709 if (!non_zero_arg(&argvars[0]))
8710 buf[1] = NUL;
8711
8712 rettv->vval.v_string = vim_strsave(buf);
8713 rettv->v_type = VAR_STRING;
8714}
8715
8716#if defined(FEAT_MZSCHEME) || defined(PROTO)
8717/*
8718 * "mzeval()" function
8719 */
8720 static void
8721f_mzeval(typval_T *argvars, typval_T *rettv)
8722{
8723 char_u *str;
8724 char_u buf[NUMBUFLEN];
8725
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008726 if (check_restricted() || check_secure())
8727 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008728 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008729 do_mzeval(str, rettv);
8730}
8731
8732 void
8733mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8734{
8735 typval_T argvars[3];
8736
8737 argvars[0].v_type = VAR_STRING;
8738 argvars[0].vval.v_string = name;
8739 copy_tv(args, &argvars[1]);
8740 argvars[2].v_type = VAR_UNKNOWN;
8741 f_call(argvars, rettv);
8742 clear_tv(&argvars[1]);
8743}
8744#endif
8745
8746/*
8747 * "nextnonblank()" function
8748 */
8749 static void
8750f_nextnonblank(typval_T *argvars, typval_T *rettv)
8751{
8752 linenr_T lnum;
8753
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008754 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008755 {
8756 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8757 {
8758 lnum = 0;
8759 break;
8760 }
8761 if (*skipwhite(ml_get(lnum)) != NUL)
8762 break;
8763 }
8764 rettv->vval.v_number = lnum;
8765}
8766
8767/*
8768 * "nr2char()" function
8769 */
8770 static void
8771f_nr2char(typval_T *argvars, typval_T *rettv)
8772{
8773 char_u buf[NUMBUFLEN];
8774
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008775 if (has_mbyte)
8776 {
8777 int utf8 = 0;
8778
8779 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008780 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008781 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008782 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008783 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008784 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008785 }
8786 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008787 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008788 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008789 buf[1] = NUL;
8790 }
8791 rettv->v_type = VAR_STRING;
8792 rettv->vval.v_string = vim_strsave(buf);
8793}
8794
8795/*
8796 * "or(expr, expr)" function
8797 */
8798 static void
8799f_or(typval_T *argvars, typval_T *rettv)
8800{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008801 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8802 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008803}
8804
8805/*
8806 * "pathshorten()" function
8807 */
8808 static void
8809f_pathshorten(typval_T *argvars, typval_T *rettv)
8810{
8811 char_u *p;
8812
8813 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008814 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008815 if (p == NULL)
8816 rettv->vval.v_string = NULL;
8817 else
8818 {
8819 p = vim_strsave(p);
8820 rettv->vval.v_string = p;
8821 if (p != NULL)
8822 shorten_dir(p);
8823 }
8824}
8825
8826#ifdef FEAT_PERL
8827/*
8828 * "perleval()" function
8829 */
8830 static void
8831f_perleval(typval_T *argvars, typval_T *rettv)
8832{
8833 char_u *str;
8834 char_u buf[NUMBUFLEN];
8835
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008836 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008837 do_perleval(str, rettv);
8838}
8839#endif
8840
8841#ifdef FEAT_FLOAT
8842/*
8843 * "pow()" function
8844 */
8845 static void
8846f_pow(typval_T *argvars, typval_T *rettv)
8847{
8848 float_T fx = 0.0, fy = 0.0;
8849
8850 rettv->v_type = VAR_FLOAT;
8851 if (get_float_arg(argvars, &fx) == OK
8852 && get_float_arg(&argvars[1], &fy) == OK)
8853 rettv->vval.v_float = pow(fx, fy);
8854 else
8855 rettv->vval.v_float = 0.0;
8856}
8857#endif
8858
8859/*
8860 * "prevnonblank()" function
8861 */
8862 static void
8863f_prevnonblank(typval_T *argvars, typval_T *rettv)
8864{
8865 linenr_T lnum;
8866
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008867 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008868 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8869 lnum = 0;
8870 else
8871 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8872 --lnum;
8873 rettv->vval.v_number = lnum;
8874}
8875
8876/* This dummy va_list is here because:
8877 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8878 * - locally in the function results in a "used before set" warning
8879 * - using va_start() to initialize it gives "function with fixed args" error */
8880static va_list ap;
8881
8882/*
8883 * "printf()" function
8884 */
8885 static void
8886f_printf(typval_T *argvars, typval_T *rettv)
8887{
8888 char_u buf[NUMBUFLEN];
8889 int len;
8890 char_u *s;
8891 int saved_did_emsg = did_emsg;
8892 char *fmt;
8893
8894 rettv->v_type = VAR_STRING;
8895 rettv->vval.v_string = NULL;
8896
8897 /* Get the required length, allocate the buffer and do it for real. */
8898 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008899 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008900 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008901 if (!did_emsg)
8902 {
8903 s = alloc(len + 1);
8904 if (s != NULL)
8905 {
8906 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008907 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8908 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008909 }
8910 }
8911 did_emsg |= saved_did_emsg;
8912}
8913
Bram Moolenaarf2732452018-06-03 14:47:35 +02008914#ifdef FEAT_JOB_CHANNEL
8915/*
8916 * "prompt_setcallback({buffer}, {callback})" function
8917 */
8918 static void
8919f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8920{
8921 buf_T *buf;
8922 char_u *callback;
8923 partial_T *partial;
8924
8925 if (check_secure())
8926 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008927 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008928 if (buf == NULL)
8929 return;
8930
8931 callback = get_callback(&argvars[1], &partial);
8932 if (callback == NULL)
8933 return;
8934
8935 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8936 if (partial == NULL)
8937 buf->b_prompt_callback = vim_strsave(callback);
8938 else
8939 /* pointer into the partial */
8940 buf->b_prompt_callback = callback;
8941 buf->b_prompt_partial = partial;
8942}
8943
8944/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008945 * "prompt_setinterrupt({buffer}, {callback})" function
8946 */
8947 static void
8948f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8949{
8950 buf_T *buf;
8951 char_u *callback;
8952 partial_T *partial;
8953
8954 if (check_secure())
8955 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008956 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008957 if (buf == NULL)
8958 return;
8959
8960 callback = get_callback(&argvars[1], &partial);
8961 if (callback == NULL)
8962 return;
8963
8964 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8965 if (partial == NULL)
8966 buf->b_prompt_interrupt = vim_strsave(callback);
8967 else
8968 /* pointer into the partial */
8969 buf->b_prompt_interrupt = callback;
8970 buf->b_prompt_int_partial = partial;
8971}
8972
8973/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008974 * "prompt_setprompt({buffer}, {text})" function
8975 */
8976 static void
8977f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8978{
8979 buf_T *buf;
8980 char_u *text;
8981
8982 if (check_secure())
8983 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008984 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008985 if (buf == NULL)
8986 return;
8987
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008988 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008989 vim_free(buf->b_prompt_text);
8990 buf->b_prompt_text = vim_strsave(text);
8991}
8992#endif
8993
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008994/*
8995 * "pumvisible()" function
8996 */
8997 static void
8998f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8999{
9000#ifdef FEAT_INS_EXPAND
9001 if (pum_visible())
9002 rettv->vval.v_number = 1;
9003#endif
9004}
9005
9006#ifdef FEAT_PYTHON3
9007/*
9008 * "py3eval()" function
9009 */
9010 static void
9011f_py3eval(typval_T *argvars, typval_T *rettv)
9012{
9013 char_u *str;
9014 char_u buf[NUMBUFLEN];
9015
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009016 if (check_restricted() || check_secure())
9017 return;
9018
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009019 if (p_pyx == 0)
9020 p_pyx = 3;
9021
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009022 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009023 do_py3eval(str, rettv);
9024}
9025#endif
9026
9027#ifdef FEAT_PYTHON
9028/*
9029 * "pyeval()" function
9030 */
9031 static void
9032f_pyeval(typval_T *argvars, typval_T *rettv)
9033{
9034 char_u *str;
9035 char_u buf[NUMBUFLEN];
9036
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009037 if (check_restricted() || check_secure())
9038 return;
9039
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009040 if (p_pyx == 0)
9041 p_pyx = 2;
9042
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009043 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009044 do_pyeval(str, rettv);
9045}
9046#endif
9047
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009048#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
9049/*
9050 * "pyxeval()" function
9051 */
9052 static void
9053f_pyxeval(typval_T *argvars, typval_T *rettv)
9054{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009055 if (check_restricted() || check_secure())
9056 return;
9057
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009058# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
9059 init_pyxversion();
9060 if (p_pyx == 2)
9061 f_pyeval(argvars, rettv);
9062 else
9063 f_py3eval(argvars, rettv);
9064# elif defined(FEAT_PYTHON)
9065 f_pyeval(argvars, rettv);
9066# elif defined(FEAT_PYTHON3)
9067 f_py3eval(argvars, rettv);
9068# endif
9069}
9070#endif
9071
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009072/*
9073 * "range()" function
9074 */
9075 static void
9076f_range(typval_T *argvars, typval_T *rettv)
9077{
9078 varnumber_T start;
9079 varnumber_T end;
9080 varnumber_T stride = 1;
9081 varnumber_T i;
9082 int error = FALSE;
9083
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009084 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009085 if (argvars[1].v_type == VAR_UNKNOWN)
9086 {
9087 end = start - 1;
9088 start = 0;
9089 }
9090 else
9091 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009092 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009093 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009094 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009095 }
9096
9097 if (error)
9098 return; /* type error; errmsg already given */
9099 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009100 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009101 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009102 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009103 else
9104 {
9105 if (rettv_list_alloc(rettv) == OK)
9106 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9107 if (list_append_number(rettv->vval.v_list,
9108 (varnumber_T)i) == FAIL)
9109 break;
9110 }
9111}
9112
9113/*
9114 * "readfile()" function
9115 */
9116 static void
9117f_readfile(typval_T *argvars, typval_T *rettv)
9118{
9119 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009120 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009121 int failed = FALSE;
9122 char_u *fname;
9123 FILE *fd;
9124 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9125 int io_size = sizeof(buf);
9126 int readlen; /* size of last fread() */
9127 char_u *prev = NULL; /* previously read bytes, if any */
9128 long prevlen = 0; /* length of data in prev */
9129 long prevsize = 0; /* size of prev buffer */
9130 long maxline = MAXLNUM;
9131 long cnt = 0;
9132 char_u *p; /* position in buf */
9133 char_u *start; /* start of current line */
9134
9135 if (argvars[1].v_type != VAR_UNKNOWN)
9136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009137 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009138 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009139 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9140 blob = TRUE;
9141
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009142 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009143 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009144 }
9145
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009146 if (blob)
9147 {
9148 if (rettv_blob_alloc(rettv) == FAIL)
9149 return;
9150 }
9151 else
9152 {
9153 if (rettv_list_alloc(rettv) == FAIL)
9154 return;
9155 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009156
9157 /* Always open the file in binary mode, library functions have a mind of
9158 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009159 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009160 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9161 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009162 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009163 return;
9164 }
9165
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009166 if (blob)
9167 {
9168 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9169 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009170 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009171 blob_free(rettv->vval.v_blob);
9172 }
9173 fclose(fd);
9174 return;
9175 }
9176
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009177 while (cnt < maxline || maxline < 0)
9178 {
9179 readlen = (int)fread(buf, 1, io_size, fd);
9180
9181 /* This for loop processes what was read, but is also entered at end
9182 * of file so that either:
9183 * - an incomplete line gets written
9184 * - a "binary" file gets an empty line at the end if it ends in a
9185 * newline. */
9186 for (p = buf, start = buf;
9187 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9188 ++p)
9189 {
9190 if (*p == '\n' || readlen <= 0)
9191 {
9192 listitem_T *li;
9193 char_u *s = NULL;
9194 long_u len = p - start;
9195
9196 /* Finished a line. Remove CRs before NL. */
9197 if (readlen > 0 && !binary)
9198 {
9199 while (len > 0 && start[len - 1] == '\r')
9200 --len;
9201 /* removal may cross back to the "prev" string */
9202 if (len == 0)
9203 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9204 --prevlen;
9205 }
9206 if (prevlen == 0)
9207 s = vim_strnsave(start, (int)len);
9208 else
9209 {
9210 /* Change "prev" buffer to be the right size. This way
9211 * the bytes are only copied once, and very long lines are
9212 * allocated only once. */
9213 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9214 {
9215 mch_memmove(s + prevlen, start, len);
9216 s[prevlen + len] = NUL;
9217 prev = NULL; /* the list will own the string */
9218 prevlen = prevsize = 0;
9219 }
9220 }
9221 if (s == NULL)
9222 {
9223 do_outofmem_msg((long_u) prevlen + len + 1);
9224 failed = TRUE;
9225 break;
9226 }
9227
9228 if ((li = listitem_alloc()) == NULL)
9229 {
9230 vim_free(s);
9231 failed = TRUE;
9232 break;
9233 }
9234 li->li_tv.v_type = VAR_STRING;
9235 li->li_tv.v_lock = 0;
9236 li->li_tv.vval.v_string = s;
9237 list_append(rettv->vval.v_list, li);
9238
9239 start = p + 1; /* step over newline */
9240 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9241 break;
9242 }
9243 else if (*p == NUL)
9244 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009245 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9246 * when finding the BF and check the previous two bytes. */
9247 else if (*p == 0xbf && enc_utf8 && !binary)
9248 {
9249 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9250 * + 1, these may be in the "prev" string. */
9251 char_u back1 = p >= buf + 1 ? p[-1]
9252 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9253 char_u back2 = p >= buf + 2 ? p[-2]
9254 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9255 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9256
9257 if (back2 == 0xef && back1 == 0xbb)
9258 {
9259 char_u *dest = p - 2;
9260
9261 /* Usually a BOM is at the beginning of a file, and so at
9262 * the beginning of a line; then we can just step over it.
9263 */
9264 if (start == dest)
9265 start = p + 1;
9266 else
9267 {
9268 /* have to shuffle buf to close gap */
9269 int adjust_prevlen = 0;
9270
9271 if (dest < buf)
9272 {
9273 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9274 dest = buf;
9275 }
9276 if (readlen > p - buf + 1)
9277 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9278 readlen -= 3 - adjust_prevlen;
9279 prevlen -= adjust_prevlen;
9280 p = dest - 1;
9281 }
9282 }
9283 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009284 } /* for */
9285
9286 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9287 break;
9288 if (start < p)
9289 {
9290 /* There's part of a line in buf, store it in "prev". */
9291 if (p - start + prevlen >= prevsize)
9292 {
9293 /* need bigger "prev" buffer */
9294 char_u *newprev;
9295
9296 /* A common use case is ordinary text files and "prev" gets a
9297 * fragment of a line, so the first allocation is made
9298 * small, to avoid repeatedly 'allocing' large and
9299 * 'reallocing' small. */
9300 if (prevsize == 0)
9301 prevsize = (long)(p - start);
9302 else
9303 {
9304 long grow50pc = (prevsize * 3) / 2;
9305 long growmin = (long)((p - start) * 2 + prevlen);
9306 prevsize = grow50pc > growmin ? grow50pc : growmin;
9307 }
9308 newprev = prev == NULL ? alloc(prevsize)
9309 : vim_realloc(prev, prevsize);
9310 if (newprev == NULL)
9311 {
9312 do_outofmem_msg((long_u)prevsize);
9313 failed = TRUE;
9314 break;
9315 }
9316 prev = newprev;
9317 }
9318 /* Add the line part to end of "prev". */
9319 mch_memmove(prev + prevlen, start, p - start);
9320 prevlen += (long)(p - start);
9321 }
9322 } /* while */
9323
9324 /*
9325 * For a negative line count use only the lines at the end of the file,
9326 * free the rest.
9327 */
9328 if (!failed && maxline < 0)
9329 while (cnt > -maxline)
9330 {
9331 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9332 --cnt;
9333 }
9334
9335 if (failed)
9336 {
9337 list_free(rettv->vval.v_list);
9338 /* readfile doc says an empty list is returned on error */
9339 rettv->vval.v_list = list_alloc();
9340 }
9341
9342 vim_free(prev);
9343 fclose(fd);
9344}
9345
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009346 static void
9347return_register(int regname, typval_T *rettv)
9348{
9349 char_u buf[2] = {0, 0};
9350
9351 buf[0] = (char_u)regname;
9352 rettv->v_type = VAR_STRING;
9353 rettv->vval.v_string = vim_strsave(buf);
9354}
9355
9356/*
9357 * "reg_executing()" function
9358 */
9359 static void
9360f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9361{
9362 return_register(reg_executing, rettv);
9363}
9364
9365/*
9366 * "reg_recording()" function
9367 */
9368 static void
9369f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9370{
9371 return_register(reg_recording, rettv);
9372}
9373
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009374#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009375/*
9376 * Convert a List to proftime_T.
9377 * Return FAIL when there is something wrong.
9378 */
9379 static int
9380list2proftime(typval_T *arg, proftime_T *tm)
9381{
9382 long n1, n2;
9383 int error = FALSE;
9384
9385 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9386 || arg->vval.v_list->lv_len != 2)
9387 return FAIL;
9388 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9389 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009390# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009391 tm->HighPart = n1;
9392 tm->LowPart = n2;
9393# else
9394 tm->tv_sec = n1;
9395 tm->tv_usec = n2;
9396# endif
9397 return error ? FAIL : OK;
9398}
9399#endif /* FEAT_RELTIME */
9400
9401/*
9402 * "reltime()" function
9403 */
9404 static void
9405f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9406{
9407#ifdef FEAT_RELTIME
9408 proftime_T res;
9409 proftime_T start;
9410
9411 if (argvars[0].v_type == VAR_UNKNOWN)
9412 {
9413 /* No arguments: get current time. */
9414 profile_start(&res);
9415 }
9416 else if (argvars[1].v_type == VAR_UNKNOWN)
9417 {
9418 if (list2proftime(&argvars[0], &res) == FAIL)
9419 return;
9420 profile_end(&res);
9421 }
9422 else
9423 {
9424 /* Two arguments: compute the difference. */
9425 if (list2proftime(&argvars[0], &start) == FAIL
9426 || list2proftime(&argvars[1], &res) == FAIL)
9427 return;
9428 profile_sub(&res, &start);
9429 }
9430
9431 if (rettv_list_alloc(rettv) == OK)
9432 {
9433 long n1, n2;
9434
Bram Moolenaar4f974752019-02-17 17:44:42 +01009435# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009436 n1 = res.HighPart;
9437 n2 = res.LowPart;
9438# else
9439 n1 = res.tv_sec;
9440 n2 = res.tv_usec;
9441# endif
9442 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9443 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9444 }
9445#endif
9446}
9447
9448#ifdef FEAT_FLOAT
9449/*
9450 * "reltimefloat()" function
9451 */
9452 static void
9453f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9454{
9455# ifdef FEAT_RELTIME
9456 proftime_T tm;
9457# endif
9458
9459 rettv->v_type = VAR_FLOAT;
9460 rettv->vval.v_float = 0;
9461# ifdef FEAT_RELTIME
9462 if (list2proftime(&argvars[0], &tm) == OK)
9463 rettv->vval.v_float = profile_float(&tm);
9464# endif
9465}
9466#endif
9467
9468/*
9469 * "reltimestr()" function
9470 */
9471 static void
9472f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9473{
9474#ifdef FEAT_RELTIME
9475 proftime_T tm;
9476#endif
9477
9478 rettv->v_type = VAR_STRING;
9479 rettv->vval.v_string = NULL;
9480#ifdef FEAT_RELTIME
9481 if (list2proftime(&argvars[0], &tm) == OK)
9482 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9483#endif
9484}
9485
9486#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009487 static void
9488make_connection(void)
9489{
9490 if (X_DISPLAY == NULL
9491# ifdef FEAT_GUI
9492 && !gui.in_use
9493# endif
9494 )
9495 {
9496 x_force_connect = TRUE;
9497 setup_term_clip();
9498 x_force_connect = FALSE;
9499 }
9500}
9501
9502 static int
9503check_connection(void)
9504{
9505 make_connection();
9506 if (X_DISPLAY == NULL)
9507 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009508 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009509 return FAIL;
9510 }
9511 return OK;
9512}
9513#endif
9514
9515#ifdef FEAT_CLIENTSERVER
9516 static void
9517remote_common(typval_T *argvars, typval_T *rettv, int expr)
9518{
9519 char_u *server_name;
9520 char_u *keys;
9521 char_u *r = NULL;
9522 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009523 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009524# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009525 HWND w;
9526# else
9527 Window w;
9528# endif
9529
9530 if (check_restricted() || check_secure())
9531 return;
9532
9533# ifdef FEAT_X11
9534 if (check_connection() == FAIL)
9535 return;
9536# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009537 if (argvars[2].v_type != VAR_UNKNOWN
9538 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009539 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009540
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009541 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009542 if (server_name == NULL)
9543 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009544 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009545# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009546 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009547# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009548 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9549 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009550# endif
9551 {
9552 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009553 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009554 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009555 vim_free(r);
9556 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009557 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009558 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009559 return;
9560 }
9561
9562 rettv->vval.v_string = r;
9563
9564 if (argvars[2].v_type != VAR_UNKNOWN)
9565 {
9566 dictitem_T v;
9567 char_u str[30];
9568 char_u *idvar;
9569
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009570 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009571 if (idvar != NULL && *idvar != NUL)
9572 {
9573 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9574 v.di_tv.v_type = VAR_STRING;
9575 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009576 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009577 vim_free(v.di_tv.vval.v_string);
9578 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009579 }
9580}
9581#endif
9582
9583/*
9584 * "remote_expr()" function
9585 */
9586 static void
9587f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9588{
9589 rettv->v_type = VAR_STRING;
9590 rettv->vval.v_string = NULL;
9591#ifdef FEAT_CLIENTSERVER
9592 remote_common(argvars, rettv, TRUE);
9593#endif
9594}
9595
9596/*
9597 * "remote_foreground()" function
9598 */
9599 static void
9600f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9601{
9602#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009603# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009604 /* On Win32 it's done in this application. */
9605 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009606 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009607
9608 if (server_name != NULL)
9609 serverForeground(server_name);
9610 }
9611# else
9612 /* Send a foreground() expression to the server. */
9613 argvars[1].v_type = VAR_STRING;
9614 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9615 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009616 rettv->v_type = VAR_STRING;
9617 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009618 remote_common(argvars, rettv, TRUE);
9619 vim_free(argvars[1].vval.v_string);
9620# endif
9621#endif
9622}
9623
9624 static void
9625f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9626{
9627#ifdef FEAT_CLIENTSERVER
9628 dictitem_T v;
9629 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009630# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009631 long_u n = 0;
9632# endif
9633 char_u *serverid;
9634
9635 if (check_restricted() || check_secure())
9636 {
9637 rettv->vval.v_number = -1;
9638 return;
9639 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009640 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009641 if (serverid == NULL)
9642 {
9643 rettv->vval.v_number = -1;
9644 return; /* type error; errmsg already given */
9645 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009646# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009647 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9648 if (n == 0)
9649 rettv->vval.v_number = -1;
9650 else
9651 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009652 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009653 rettv->vval.v_number = (s != NULL);
9654 }
9655# else
9656 if (check_connection() == FAIL)
9657 return;
9658
9659 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9660 serverStrToWin(serverid), &s);
9661# endif
9662
9663 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9664 {
9665 char_u *retvar;
9666
9667 v.di_tv.v_type = VAR_STRING;
9668 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009669 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009670 if (retvar != NULL)
9671 set_var(retvar, &v.di_tv, FALSE);
9672 vim_free(v.di_tv.vval.v_string);
9673 }
9674#else
9675 rettv->vval.v_number = -1;
9676#endif
9677}
9678
9679 static void
9680f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9681{
9682 char_u *r = NULL;
9683
9684#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009685 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009686
9687 if (serverid != NULL && !check_restricted() && !check_secure())
9688 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009689 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009690# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009691 /* The server's HWND is encoded in the 'id' parameter */
9692 long_u n = 0;
9693# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009694
9695 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009696 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009697
Bram Moolenaar4f974752019-02-17 17:44:42 +01009698# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009699 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9700 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009701 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009702 if (r == NULL)
9703# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009704 if (check_connection() == FAIL
9705 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9706 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009707# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009708 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009709 }
9710#endif
9711 rettv->v_type = VAR_STRING;
9712 rettv->vval.v_string = r;
9713}
9714
9715/*
9716 * "remote_send()" function
9717 */
9718 static void
9719f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9720{
9721 rettv->v_type = VAR_STRING;
9722 rettv->vval.v_string = NULL;
9723#ifdef FEAT_CLIENTSERVER
9724 remote_common(argvars, rettv, FALSE);
9725#endif
9726}
9727
9728/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009729 * "remote_startserver()" function
9730 */
9731 static void
9732f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9733{
9734#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009735 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009736
9737 if (server == NULL)
9738 return; /* type error; errmsg already given */
9739 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009740 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009741 else
9742 {
9743# ifdef FEAT_X11
9744 if (check_connection() == OK)
9745 serverRegisterName(X_DISPLAY, server);
9746# else
9747 serverSetName(server);
9748# endif
9749 }
9750#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009751 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009752#endif
9753}
9754
9755/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009756 * "remove()" function
9757 */
9758 static void
9759f_remove(typval_T *argvars, typval_T *rettv)
9760{
9761 list_T *l;
9762 listitem_T *item, *item2;
9763 listitem_T *li;
9764 long idx;
9765 long end;
9766 char_u *key;
9767 dict_T *d;
9768 dictitem_T *di;
9769 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009770 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009771
9772 if (argvars[0].v_type == VAR_DICT)
9773 {
9774 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009775 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009776 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009777 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009778 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009779 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009780 if (key != NULL)
9781 {
9782 di = dict_find(d, key, -1);
9783 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009784 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009785 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9786 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9787 {
9788 *rettv = di->di_tv;
9789 init_tv(&di->di_tv);
9790 dictitem_remove(d, di);
9791 }
9792 }
9793 }
9794 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009795 else if (argvars[0].v_type == VAR_BLOB)
9796 {
9797 idx = (long)tv_get_number_chk(&argvars[1], &error);
9798 if (!error)
9799 {
9800 blob_T *b = argvars[0].vval.v_blob;
9801 int len = blob_len(b);
9802 char_u *p;
9803
9804 if (idx < 0)
9805 // count from the end
9806 idx = len + idx;
9807 if (idx < 0 || idx >= len)
9808 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009809 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009810 return;
9811 }
9812 if (argvars[2].v_type == VAR_UNKNOWN)
9813 {
9814 // Remove one item, return its value.
9815 p = (char_u *)b->bv_ga.ga_data;
9816 rettv->vval.v_number = (varnumber_T) *(p + idx);
9817 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9818 --b->bv_ga.ga_len;
9819 }
9820 else
9821 {
9822 blob_T *blob;
9823
9824 // Remove range of items, return list with values.
9825 end = (long)tv_get_number_chk(&argvars[2], &error);
9826 if (error)
9827 return;
9828 if (end < 0)
9829 // count from the end
9830 end = len + end;
9831 if (end >= len || idx > end)
9832 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009833 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009834 return;
9835 }
9836 blob = blob_alloc();
9837 if (blob == NULL)
9838 return;
9839 blob->bv_ga.ga_len = end - idx + 1;
9840 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9841 {
9842 vim_free(blob);
9843 return;
9844 }
9845 p = (char_u *)b->bv_ga.ga_data;
9846 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9847 (size_t)(end - idx + 1));
9848 ++blob->bv_refcount;
9849 rettv->v_type = VAR_BLOB;
9850 rettv->vval.v_blob = blob;
9851
9852 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9853 b->bv_ga.ga_len -= end - idx + 1;
9854 }
9855 }
9856 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009857 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009858 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009859 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009860 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009861 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009862 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009863 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009864 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009865 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009866 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009867 else
9868 {
9869 if (argvars[2].v_type == VAR_UNKNOWN)
9870 {
9871 /* Remove one item, return its value. */
9872 vimlist_remove(l, item, item);
9873 *rettv = item->li_tv;
9874 vim_free(item);
9875 }
9876 else
9877 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009878 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009879 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009880 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009881 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009882 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009883 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009884 else
9885 {
9886 int cnt = 0;
9887
9888 for (li = item; li != NULL; li = li->li_next)
9889 {
9890 ++cnt;
9891 if (li == item2)
9892 break;
9893 }
9894 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009895 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009896 else
9897 {
9898 vimlist_remove(l, item, item2);
9899 if (rettv_list_alloc(rettv) == OK)
9900 {
9901 l = rettv->vval.v_list;
9902 l->lv_first = item;
9903 l->lv_last = item2;
9904 item->li_prev = NULL;
9905 item2->li_next = NULL;
9906 l->lv_len = cnt;
9907 }
9908 }
9909 }
9910 }
9911 }
9912 }
9913}
9914
9915/*
9916 * "rename({from}, {to})" function
9917 */
9918 static void
9919f_rename(typval_T *argvars, typval_T *rettv)
9920{
9921 char_u buf[NUMBUFLEN];
9922
9923 if (check_restricted() || check_secure())
9924 rettv->vval.v_number = -1;
9925 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009926 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9927 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009928}
9929
9930/*
9931 * "repeat()" function
9932 */
9933 static void
9934f_repeat(typval_T *argvars, typval_T *rettv)
9935{
9936 char_u *p;
9937 int n;
9938 int slen;
9939 int len;
9940 char_u *r;
9941 int i;
9942
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009943 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009944 if (argvars[0].v_type == VAR_LIST)
9945 {
9946 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9947 while (n-- > 0)
9948 if (list_extend(rettv->vval.v_list,
9949 argvars[0].vval.v_list, NULL) == FAIL)
9950 break;
9951 }
9952 else
9953 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009954 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009955 rettv->v_type = VAR_STRING;
9956 rettv->vval.v_string = NULL;
9957
9958 slen = (int)STRLEN(p);
9959 len = slen * n;
9960 if (len <= 0)
9961 return;
9962
9963 r = alloc(len + 1);
9964 if (r != NULL)
9965 {
9966 for (i = 0; i < n; i++)
9967 mch_memmove(r + i * slen, p, (size_t)slen);
9968 r[len] = NUL;
9969 }
9970
9971 rettv->vval.v_string = r;
9972 }
9973}
9974
9975/*
9976 * "resolve()" function
9977 */
9978 static void
9979f_resolve(typval_T *argvars, typval_T *rettv)
9980{
9981 char_u *p;
9982#ifdef HAVE_READLINK
9983 char_u *buf = NULL;
9984#endif
9985
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009986 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009987#ifdef FEAT_SHORTCUT
9988 {
9989 char_u *v = NULL;
9990
Bram Moolenaardce1e892019-02-10 23:18:53 +01009991 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009992 if (v != NULL)
9993 rettv->vval.v_string = v;
9994 else
9995 rettv->vval.v_string = vim_strsave(p);
9996 }
9997#else
9998# ifdef HAVE_READLINK
9999 {
10000 char_u *cpy;
10001 int len;
10002 char_u *remain = NULL;
10003 char_u *q;
10004 int is_relative_to_current = FALSE;
10005 int has_trailing_pathsep = FALSE;
10006 int limit = 100;
10007
10008 p = vim_strsave(p);
10009
10010 if (p[0] == '.' && (vim_ispathsep(p[1])
10011 || (p[1] == '.' && (vim_ispathsep(p[2])))))
10012 is_relative_to_current = TRUE;
10013
10014 len = STRLEN(p);
10015 if (len > 0 && after_pathsep(p, p + len))
10016 {
10017 has_trailing_pathsep = TRUE;
10018 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
10019 }
10020
10021 q = getnextcomp(p);
10022 if (*q != NUL)
10023 {
10024 /* Separate the first path component in "p", and keep the
10025 * remainder (beginning with the path separator). */
10026 remain = vim_strsave(q - 1);
10027 q[-1] = NUL;
10028 }
10029
10030 buf = alloc(MAXPATHL + 1);
10031 if (buf == NULL)
10032 goto fail;
10033
10034 for (;;)
10035 {
10036 for (;;)
10037 {
10038 len = readlink((char *)p, (char *)buf, MAXPATHL);
10039 if (len <= 0)
10040 break;
10041 buf[len] = NUL;
10042
10043 if (limit-- == 0)
10044 {
10045 vim_free(p);
10046 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010047 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010048 rettv->vval.v_string = NULL;
10049 goto fail;
10050 }
10051
10052 /* Ensure that the result will have a trailing path separator
10053 * if the argument has one. */
10054 if (remain == NULL && has_trailing_pathsep)
10055 add_pathsep(buf);
10056
10057 /* Separate the first path component in the link value and
10058 * concatenate the remainders. */
10059 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10060 if (*q != NUL)
10061 {
10062 if (remain == NULL)
10063 remain = vim_strsave(q - 1);
10064 else
10065 {
10066 cpy = concat_str(q - 1, remain);
10067 if (cpy != NULL)
10068 {
10069 vim_free(remain);
10070 remain = cpy;
10071 }
10072 }
10073 q[-1] = NUL;
10074 }
10075
10076 q = gettail(p);
10077 if (q > p && *q == NUL)
10078 {
10079 /* Ignore trailing path separator. */
10080 q[-1] = NUL;
10081 q = gettail(p);
10082 }
10083 if (q > p && !mch_isFullName(buf))
10084 {
10085 /* symlink is relative to directory of argument */
10086 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10087 if (cpy != NULL)
10088 {
10089 STRCPY(cpy, p);
10090 STRCPY(gettail(cpy), buf);
10091 vim_free(p);
10092 p = cpy;
10093 }
10094 }
10095 else
10096 {
10097 vim_free(p);
10098 p = vim_strsave(buf);
10099 }
10100 }
10101
10102 if (remain == NULL)
10103 break;
10104
10105 /* Append the first path component of "remain" to "p". */
10106 q = getnextcomp(remain + 1);
10107 len = q - remain - (*q != NUL);
10108 cpy = vim_strnsave(p, STRLEN(p) + len);
10109 if (cpy != NULL)
10110 {
10111 STRNCAT(cpy, remain, len);
10112 vim_free(p);
10113 p = cpy;
10114 }
10115 /* Shorten "remain". */
10116 if (*q != NUL)
10117 STRMOVE(remain, q - 1);
10118 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010119 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010120 }
10121
10122 /* If the result is a relative path name, make it explicitly relative to
10123 * the current directory if and only if the argument had this form. */
10124 if (!vim_ispathsep(*p))
10125 {
10126 if (is_relative_to_current
10127 && *p != NUL
10128 && !(p[0] == '.'
10129 && (p[1] == NUL
10130 || vim_ispathsep(p[1])
10131 || (p[1] == '.'
10132 && (p[2] == NUL
10133 || vim_ispathsep(p[2]))))))
10134 {
10135 /* Prepend "./". */
10136 cpy = concat_str((char_u *)"./", p);
10137 if (cpy != NULL)
10138 {
10139 vim_free(p);
10140 p = cpy;
10141 }
10142 }
10143 else if (!is_relative_to_current)
10144 {
10145 /* Strip leading "./". */
10146 q = p;
10147 while (q[0] == '.' && vim_ispathsep(q[1]))
10148 q += 2;
10149 if (q > p)
10150 STRMOVE(p, p + 2);
10151 }
10152 }
10153
10154 /* Ensure that the result will have no trailing path separator
10155 * if the argument had none. But keep "/" or "//". */
10156 if (!has_trailing_pathsep)
10157 {
10158 q = p + STRLEN(p);
10159 if (after_pathsep(p, q))
10160 *gettail_sep(p) = NUL;
10161 }
10162
10163 rettv->vval.v_string = p;
10164 }
10165# else
10166 rettv->vval.v_string = vim_strsave(p);
10167# endif
10168#endif
10169
10170 simplify_filename(rettv->vval.v_string);
10171
10172#ifdef HAVE_READLINK
10173fail:
10174 vim_free(buf);
10175#endif
10176 rettv->v_type = VAR_STRING;
10177}
10178
10179/*
10180 * "reverse({list})" function
10181 */
10182 static void
10183f_reverse(typval_T *argvars, typval_T *rettv)
10184{
10185 list_T *l;
10186 listitem_T *li, *ni;
10187
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010188 if (argvars[0].v_type == VAR_BLOB)
10189 {
10190 blob_T *b = argvars[0].vval.v_blob;
10191 int i, len = blob_len(b);
10192
10193 for (i = 0; i < len / 2; i++)
10194 {
10195 int tmp = blob_get(b, i);
10196
10197 blob_set(b, i, blob_get(b, len - i - 1));
10198 blob_set(b, len - i - 1, tmp);
10199 }
10200 rettv_blob_set(rettv, b);
10201 return;
10202 }
10203
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010204 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010205 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010206 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010207 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010208 (char_u *)N_("reverse() argument"), TRUE))
10209 {
10210 li = l->lv_last;
10211 l->lv_first = l->lv_last = NULL;
10212 l->lv_len = 0;
10213 while (li != NULL)
10214 {
10215 ni = li->li_prev;
10216 list_append(l, li);
10217 li = ni;
10218 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010219 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010220 l->lv_idx = l->lv_len - l->lv_idx - 1;
10221 }
10222}
10223
10224#define SP_NOMOVE 0x01 /* don't move cursor */
10225#define SP_REPEAT 0x02 /* repeat to find outer pair */
10226#define SP_RETCOUNT 0x04 /* return matchcount */
10227#define SP_SETPCMARK 0x08 /* set previous context mark */
10228#define SP_START 0x10 /* accept match at start position */
10229#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10230#define SP_END 0x40 /* leave cursor at end of match */
10231#define SP_COLUMN 0x80 /* start at cursor column */
10232
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010233/*
10234 * Get flags for a search function.
10235 * Possibly sets "p_ws".
10236 * Returns BACKWARD, FORWARD or zero (for an error).
10237 */
10238 static int
10239get_search_arg(typval_T *varp, int *flagsp)
10240{
10241 int dir = FORWARD;
10242 char_u *flags;
10243 char_u nbuf[NUMBUFLEN];
10244 int mask;
10245
10246 if (varp->v_type != VAR_UNKNOWN)
10247 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010248 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010249 if (flags == NULL)
10250 return 0; /* type error; errmsg already given */
10251 while (*flags != NUL)
10252 {
10253 switch (*flags)
10254 {
10255 case 'b': dir = BACKWARD; break;
10256 case 'w': p_ws = TRUE; break;
10257 case 'W': p_ws = FALSE; break;
10258 default: mask = 0;
10259 if (flagsp != NULL)
10260 switch (*flags)
10261 {
10262 case 'c': mask = SP_START; break;
10263 case 'e': mask = SP_END; break;
10264 case 'm': mask = SP_RETCOUNT; break;
10265 case 'n': mask = SP_NOMOVE; break;
10266 case 'p': mask = SP_SUBPAT; break;
10267 case 'r': mask = SP_REPEAT; break;
10268 case 's': mask = SP_SETPCMARK; break;
10269 case 'z': mask = SP_COLUMN; break;
10270 }
10271 if (mask == 0)
10272 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010273 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010274 dir = 0;
10275 }
10276 else
10277 *flagsp |= mask;
10278 }
10279 if (dir == 0)
10280 break;
10281 ++flags;
10282 }
10283 }
10284 return dir;
10285}
10286
10287/*
10288 * Shared by search() and searchpos() functions.
10289 */
10290 static int
10291search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10292{
10293 int flags;
10294 char_u *pat;
10295 pos_T pos;
10296 pos_T save_cursor;
10297 int save_p_ws = p_ws;
10298 int dir;
10299 int retval = 0; /* default: FAIL */
10300 long lnum_stop = 0;
10301 proftime_T tm;
10302#ifdef FEAT_RELTIME
10303 long time_limit = 0;
10304#endif
10305 int options = SEARCH_KEEP;
10306 int subpatnum;
10307
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010308 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010309 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10310 if (dir == 0)
10311 goto theend;
10312 flags = *flagsp;
10313 if (flags & SP_START)
10314 options |= SEARCH_START;
10315 if (flags & SP_END)
10316 options |= SEARCH_END;
10317 if (flags & SP_COLUMN)
10318 options |= SEARCH_COL;
10319
10320 /* Optional arguments: line number to stop searching and timeout. */
10321 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10322 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010323 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010324 if (lnum_stop < 0)
10325 goto theend;
10326#ifdef FEAT_RELTIME
10327 if (argvars[3].v_type != VAR_UNKNOWN)
10328 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010329 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010330 if (time_limit < 0)
10331 goto theend;
10332 }
10333#endif
10334 }
10335
10336#ifdef FEAT_RELTIME
10337 /* Set the time limit, if there is one. */
10338 profile_setlimit(time_limit, &tm);
10339#endif
10340
10341 /*
10342 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10343 * Check to make sure only those flags are set.
10344 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10345 * flags cannot be set. Check for that condition also.
10346 */
10347 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10348 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10349 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010350 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010351 goto theend;
10352 }
10353
10354 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010355 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010356 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010357 if (subpatnum != FAIL)
10358 {
10359 if (flags & SP_SUBPAT)
10360 retval = subpatnum;
10361 else
10362 retval = pos.lnum;
10363 if (flags & SP_SETPCMARK)
10364 setpcmark();
10365 curwin->w_cursor = pos;
10366 if (match_pos != NULL)
10367 {
10368 /* Store the match cursor position */
10369 match_pos->lnum = pos.lnum;
10370 match_pos->col = pos.col + 1;
10371 }
10372 /* "/$" will put the cursor after the end of the line, may need to
10373 * correct that here */
10374 check_cursor();
10375 }
10376
10377 /* If 'n' flag is used: restore cursor position. */
10378 if (flags & SP_NOMOVE)
10379 curwin->w_cursor = save_cursor;
10380 else
10381 curwin->w_set_curswant = TRUE;
10382theend:
10383 p_ws = save_p_ws;
10384
10385 return retval;
10386}
10387
10388#ifdef FEAT_FLOAT
10389
10390/*
10391 * round() is not in C90, use ceil() or floor() instead.
10392 */
10393 float_T
10394vim_round(float_T f)
10395{
10396 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10397}
10398
10399/*
10400 * "round({float})" function
10401 */
10402 static void
10403f_round(typval_T *argvars, typval_T *rettv)
10404{
10405 float_T f = 0.0;
10406
10407 rettv->v_type = VAR_FLOAT;
10408 if (get_float_arg(argvars, &f) == OK)
10409 rettv->vval.v_float = vim_round(f);
10410 else
10411 rettv->vval.v_float = 0.0;
10412}
10413#endif
10414
Bram Moolenaare99be0e2019-03-26 22:51:09 +010010415#ifdef FEAT_RUBY
10416/*
10417 * "rubyeval()" function
10418 */
10419 static void
10420f_rubyeval(typval_T *argvars, typval_T *rettv)
10421{
10422 char_u *str;
10423 char_u buf[NUMBUFLEN];
10424
10425 str = tv_get_string_buf(&argvars[0], buf);
10426 do_rubyeval(str, rettv);
10427}
10428#endif
10429
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010430/*
10431 * "screenattr()" function
10432 */
10433 static void
10434f_screenattr(typval_T *argvars, typval_T *rettv)
10435{
10436 int row;
10437 int col;
10438 int c;
10439
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010440 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10441 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010442 if (row < 0 || row >= screen_Rows
10443 || col < 0 || col >= screen_Columns)
10444 c = -1;
10445 else
10446 c = ScreenAttrs[LineOffset[row] + col];
10447 rettv->vval.v_number = c;
10448}
10449
10450/*
10451 * "screenchar()" function
10452 */
10453 static void
10454f_screenchar(typval_T *argvars, typval_T *rettv)
10455{
10456 int row;
10457 int col;
10458 int off;
10459 int c;
10460
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010461 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10462 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010463 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010464 c = -1;
10465 else
10466 {
10467 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010468 if (enc_utf8 && ScreenLinesUC[off] != 0)
10469 c = ScreenLinesUC[off];
10470 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010471 c = ScreenLines[off];
10472 }
10473 rettv->vval.v_number = c;
10474}
10475
10476/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010477 * "screenchars()" function
10478 */
10479 static void
10480f_screenchars(typval_T *argvars, typval_T *rettv)
10481{
10482 int row;
10483 int col;
10484 int off;
10485 int c;
10486 int i;
10487
10488 if (rettv_list_alloc(rettv) == FAIL)
10489 return;
10490 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10491 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10492 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10493 return;
10494
10495 off = LineOffset[row] + col;
10496 if (enc_utf8 && ScreenLinesUC[off] != 0)
10497 c = ScreenLinesUC[off];
10498 else
10499 c = ScreenLines[off];
10500 list_append_number(rettv->vval.v_list, (varnumber_T)c);
10501
10502 if (enc_utf8)
10503
10504 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10505 list_append_number(rettv->vval.v_list,
10506 (varnumber_T)ScreenLinesC[i][off]);
10507}
10508
10509/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010510 * "screencol()" function
10511 *
10512 * First column is 1 to be consistent with virtcol().
10513 */
10514 static void
10515f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10516{
10517 rettv->vval.v_number = screen_screencol() + 1;
10518}
10519
10520/*
10521 * "screenrow()" function
10522 */
10523 static void
10524f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10525{
10526 rettv->vval.v_number = screen_screenrow() + 1;
10527}
10528
10529/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010530 * "screenstring()" function
10531 */
10532 static void
10533f_screenstring(typval_T *argvars, typval_T *rettv)
10534{
10535 int row;
10536 int col;
10537 int off;
10538 int c;
10539 int i;
10540 char_u buf[MB_MAXBYTES + 1];
10541 int buflen = 0;
10542
10543 rettv->vval.v_string = NULL;
10544 rettv->v_type = VAR_STRING;
10545
10546 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10547 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10548 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10549 return;
10550
10551 off = LineOffset[row] + col;
10552 if (enc_utf8 && ScreenLinesUC[off] != 0)
10553 c = ScreenLinesUC[off];
10554 else
10555 c = ScreenLines[off];
10556 buflen += mb_char2bytes(c, buf);
10557
10558 if (enc_utf8)
10559 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10560 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
10561
10562 buf[buflen] = NUL;
10563 rettv->vval.v_string = vim_strsave(buf);
10564}
10565
10566/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010567 * "search()" function
10568 */
10569 static void
10570f_search(typval_T *argvars, typval_T *rettv)
10571{
10572 int flags = 0;
10573
10574 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10575}
10576
10577/*
10578 * "searchdecl()" function
10579 */
10580 static void
10581f_searchdecl(typval_T *argvars, typval_T *rettv)
10582{
10583 int locally = 1;
10584 int thisblock = 0;
10585 int error = FALSE;
10586 char_u *name;
10587
10588 rettv->vval.v_number = 1; /* default: FAIL */
10589
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010590 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010591 if (argvars[1].v_type != VAR_UNKNOWN)
10592 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010593 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010594 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010595 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010596 }
10597 if (!error && name != NULL)
10598 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10599 locally, thisblock, SEARCH_KEEP) == FAIL;
10600}
10601
10602/*
10603 * Used by searchpair() and searchpairpos()
10604 */
10605 static int
10606searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10607{
10608 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010609 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010610 int save_p_ws = p_ws;
10611 int dir;
10612 int flags = 0;
10613 char_u nbuf1[NUMBUFLEN];
10614 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010615 int retval = 0; /* default: FAIL */
10616 long lnum_stop = 0;
10617 long time_limit = 0;
10618
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010619 /* Get the three pattern arguments: start, middle, end. Will result in an
10620 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010621 spat = tv_get_string_chk(&argvars[0]);
10622 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10623 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010624 if (spat == NULL || mpat == NULL || epat == NULL)
10625 goto theend; /* type error */
10626
10627 /* Handle the optional fourth argument: flags */
10628 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10629 if (dir == 0)
10630 goto theend;
10631
10632 /* Don't accept SP_END or SP_SUBPAT.
10633 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10634 */
10635 if ((flags & (SP_END | SP_SUBPAT)) != 0
10636 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10637 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010638 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010639 goto theend;
10640 }
10641
10642 /* Using 'r' implies 'W', otherwise it doesn't work. */
10643 if (flags & SP_REPEAT)
10644 p_ws = FALSE;
10645
10646 /* Optional fifth argument: skip expression */
10647 if (argvars[3].v_type == VAR_UNKNOWN
10648 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010649 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010650 else
10651 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010652 skip = &argvars[4];
10653 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10654 && skip->v_type != VAR_STRING)
10655 {
10656 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010657 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010658 goto theend;
10659 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010660 if (argvars[5].v_type != VAR_UNKNOWN)
10661 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010662 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010663 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010664 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010665 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010666 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010667 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010668#ifdef FEAT_RELTIME
10669 if (argvars[6].v_type != VAR_UNKNOWN)
10670 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010671 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010672 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010673 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010674 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010675 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010676 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010677 }
10678#endif
10679 }
10680 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010681
10682 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10683 match_pos, lnum_stop, time_limit);
10684
10685theend:
10686 p_ws = save_p_ws;
10687
10688 return retval;
10689}
10690
10691/*
10692 * "searchpair()" function
10693 */
10694 static void
10695f_searchpair(typval_T *argvars, typval_T *rettv)
10696{
10697 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10698}
10699
10700/*
10701 * "searchpairpos()" function
10702 */
10703 static void
10704f_searchpairpos(typval_T *argvars, typval_T *rettv)
10705{
10706 pos_T match_pos;
10707 int lnum = 0;
10708 int col = 0;
10709
10710 if (rettv_list_alloc(rettv) == FAIL)
10711 return;
10712
10713 if (searchpair_cmn(argvars, &match_pos) > 0)
10714 {
10715 lnum = match_pos.lnum;
10716 col = match_pos.col;
10717 }
10718
10719 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10720 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10721}
10722
10723/*
10724 * Search for a start/middle/end thing.
10725 * Used by searchpair(), see its documentation for the details.
10726 * Returns 0 or -1 for no match,
10727 */
10728 long
10729do_searchpair(
10730 char_u *spat, /* start pattern */
10731 char_u *mpat, /* middle pattern */
10732 char_u *epat, /* end pattern */
10733 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010734 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010735 int flags, /* SP_SETPCMARK and other SP_ values */
10736 pos_T *match_pos,
10737 linenr_T lnum_stop, /* stop at this line if not zero */
10738 long time_limit UNUSED) /* stop after this many msec */
10739{
10740 char_u *save_cpo;
10741 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10742 long retval = 0;
10743 pos_T pos;
10744 pos_T firstpos;
10745 pos_T foundpos;
10746 pos_T save_cursor;
10747 pos_T save_pos;
10748 int n;
10749 int r;
10750 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010751 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010752 int err;
10753 int options = SEARCH_KEEP;
10754 proftime_T tm;
10755
10756 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10757 save_cpo = p_cpo;
10758 p_cpo = empty_option;
10759
10760#ifdef FEAT_RELTIME
10761 /* Set the time limit, if there is one. */
10762 profile_setlimit(time_limit, &tm);
10763#endif
10764
10765 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10766 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010767 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10768 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010769 if (pat2 == NULL || pat3 == NULL)
10770 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010771 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010772 if (*mpat == NUL)
10773 STRCPY(pat3, pat2);
10774 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010775 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010776 spat, epat, mpat);
10777 if (flags & SP_START)
10778 options |= SEARCH_START;
10779
Bram Moolenaar48570482017-10-30 21:48:41 +010010780 if (skip != NULL)
10781 {
10782 /* Empty string means to not use the skip expression. */
10783 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10784 use_skip = skip->vval.v_string != NULL
10785 && *skip->vval.v_string != NUL;
10786 }
10787
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010788 save_cursor = curwin->w_cursor;
10789 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010790 CLEAR_POS(&firstpos);
10791 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010792 pat = pat3;
10793 for (;;)
10794 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010795 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010796 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010797 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010798 /* didn't find it or found the first match again: FAIL */
10799 break;
10800
10801 if (firstpos.lnum == 0)
10802 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010803 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010804 {
10805 /* Found the same position again. Can happen with a pattern that
10806 * has "\zs" at the end and searching backwards. Advance one
10807 * character and try again. */
10808 if (dir == BACKWARD)
10809 decl(&pos);
10810 else
10811 incl(&pos);
10812 }
10813 foundpos = pos;
10814
10815 /* clear the start flag to avoid getting stuck here */
10816 options &= ~SEARCH_START;
10817
10818 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010819 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010820 {
10821 save_pos = curwin->w_cursor;
10822 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010823 err = FALSE;
10824 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010825 curwin->w_cursor = save_pos;
10826 if (err)
10827 {
10828 /* Evaluating {skip} caused an error, break here. */
10829 curwin->w_cursor = save_cursor;
10830 retval = -1;
10831 break;
10832 }
10833 if (r)
10834 continue;
10835 }
10836
10837 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10838 {
10839 /* Found end when searching backwards or start when searching
10840 * forward: nested pair. */
10841 ++nest;
10842 pat = pat2; /* nested, don't search for middle */
10843 }
10844 else
10845 {
10846 /* Found end when searching forward or start when searching
10847 * backward: end of (nested) pair; or found middle in outer pair. */
10848 if (--nest == 1)
10849 pat = pat3; /* outer level, search for middle */
10850 }
10851
10852 if (nest == 0)
10853 {
10854 /* Found the match: return matchcount or line number. */
10855 if (flags & SP_RETCOUNT)
10856 ++retval;
10857 else
10858 retval = pos.lnum;
10859 if (flags & SP_SETPCMARK)
10860 setpcmark();
10861 curwin->w_cursor = pos;
10862 if (!(flags & SP_REPEAT))
10863 break;
10864 nest = 1; /* search for next unmatched */
10865 }
10866 }
10867
10868 if (match_pos != NULL)
10869 {
10870 /* Store the match cursor position */
10871 match_pos->lnum = curwin->w_cursor.lnum;
10872 match_pos->col = curwin->w_cursor.col + 1;
10873 }
10874
10875 /* If 'n' flag is used or search failed: restore cursor position. */
10876 if ((flags & SP_NOMOVE) || retval == 0)
10877 curwin->w_cursor = save_cursor;
10878
10879theend:
10880 vim_free(pat2);
10881 vim_free(pat3);
10882 if (p_cpo == empty_option)
10883 p_cpo = save_cpo;
10884 else
10885 /* Darn, evaluating the {skip} expression changed the value. */
10886 free_string_option(save_cpo);
10887
10888 return retval;
10889}
10890
10891/*
10892 * "searchpos()" function
10893 */
10894 static void
10895f_searchpos(typval_T *argvars, typval_T *rettv)
10896{
10897 pos_T match_pos;
10898 int lnum = 0;
10899 int col = 0;
10900 int n;
10901 int flags = 0;
10902
10903 if (rettv_list_alloc(rettv) == FAIL)
10904 return;
10905
10906 n = search_cmn(argvars, &match_pos, &flags);
10907 if (n > 0)
10908 {
10909 lnum = match_pos.lnum;
10910 col = match_pos.col;
10911 }
10912
10913 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10914 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10915 if (flags & SP_SUBPAT)
10916 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10917}
10918
10919 static void
10920f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10921{
10922#ifdef FEAT_CLIENTSERVER
10923 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010924 char_u *server = tv_get_string_chk(&argvars[0]);
10925 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010926
10927 rettv->vval.v_number = -1;
10928 if (server == NULL || reply == NULL)
10929 return;
10930 if (check_restricted() || check_secure())
10931 return;
10932# ifdef FEAT_X11
10933 if (check_connection() == FAIL)
10934 return;
10935# endif
10936
10937 if (serverSendReply(server, reply) < 0)
10938 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010939 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010940 return;
10941 }
10942 rettv->vval.v_number = 0;
10943#else
10944 rettv->vval.v_number = -1;
10945#endif
10946}
10947
10948 static void
10949f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10950{
10951 char_u *r = NULL;
10952
10953#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010954# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010955 r = serverGetVimNames();
10956# else
10957 make_connection();
10958 if (X_DISPLAY != NULL)
10959 r = serverGetVimNames(X_DISPLAY);
10960# endif
10961#endif
10962 rettv->v_type = VAR_STRING;
10963 rettv->vval.v_string = r;
10964}
10965
10966/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010967 * "setbufline()" function
10968 */
10969 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010970f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010971{
10972 linenr_T lnum;
10973 buf_T *buf;
10974
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010975 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010976 if (buf == NULL)
10977 rettv->vval.v_number = 1; /* FAIL */
10978 else
10979 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010980 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010981 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010982 }
10983}
10984
10985/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010986 * "setbufvar()" function
10987 */
10988 static void
10989f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10990{
10991 buf_T *buf;
10992 char_u *varname, *bufvarname;
10993 typval_T *varp;
10994 char_u nbuf[NUMBUFLEN];
10995
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010996 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010997 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010998 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10999 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011000 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011001 varp = &argvars[2];
11002
11003 if (buf != NULL && varname != NULL && varp != NULL)
11004 {
11005 if (*varname == '&')
11006 {
11007 long numval;
11008 char_u *strval;
11009 int error = FALSE;
11010 aco_save_T aco;
11011
11012 /* set curbuf to be our buf, temporarily */
11013 aucmd_prepbuf(&aco, buf);
11014
11015 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011016 numval = (long)tv_get_number_chk(varp, &error);
11017 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011018 if (!error && strval != NULL)
11019 set_option_value(varname, numval, strval, OPT_LOCAL);
11020
11021 /* reset notion of buffer */
11022 aucmd_restbuf(&aco);
11023 }
11024 else
11025 {
11026 buf_T *save_curbuf = curbuf;
11027
11028 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
11029 if (bufvarname != NULL)
11030 {
11031 curbuf = buf;
11032 STRCPY(bufvarname, "b:");
11033 STRCPY(bufvarname + 2, varname);
11034 set_var(bufvarname, varp, TRUE);
11035 vim_free(bufvarname);
11036 curbuf = save_curbuf;
11037 }
11038 }
11039 }
11040}
11041
11042 static void
11043f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
11044{
11045 dict_T *d;
11046 dictitem_T *di;
11047 char_u *csearch;
11048
11049 if (argvars[0].v_type != VAR_DICT)
11050 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011051 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011052 return;
11053 }
11054
11055 if ((d = argvars[0].vval.v_dict) != NULL)
11056 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010011057 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011058 if (csearch != NULL)
11059 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011060 if (enc_utf8)
11061 {
11062 int pcc[MAX_MCO];
11063 int c = utfc_ptr2char(csearch, pcc);
11064
11065 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
11066 }
11067 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011068 set_last_csearch(PTR2CHAR(csearch),
11069 csearch, MB_PTR2LEN(csearch));
11070 }
11071
11072 di = dict_find(d, (char_u *)"forward", -1);
11073 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011074 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011075 ? FORWARD : BACKWARD);
11076
11077 di = dict_find(d, (char_u *)"until", -1);
11078 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011079 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080 }
11081}
11082
11083/*
11084 * "setcmdpos()" function
11085 */
11086 static void
11087f_setcmdpos(typval_T *argvars, typval_T *rettv)
11088{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011089 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011090
11091 if (pos >= 0)
11092 rettv->vval.v_number = set_cmdline_pos(pos);
11093}
11094
11095/*
11096 * "setfperm({fname}, {mode})" function
11097 */
11098 static void
11099f_setfperm(typval_T *argvars, typval_T *rettv)
11100{
11101 char_u *fname;
11102 char_u modebuf[NUMBUFLEN];
11103 char_u *mode_str;
11104 int i;
11105 int mask;
11106 int mode = 0;
11107
11108 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011109 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011110 if (fname == NULL)
11111 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011112 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011113 if (mode_str == NULL)
11114 return;
11115 if (STRLEN(mode_str) != 9)
11116 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011117 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011118 return;
11119 }
11120
11121 mask = 1;
11122 for (i = 8; i >= 0; --i)
11123 {
11124 if (mode_str[i] != '-')
11125 mode |= mask;
11126 mask = mask << 1;
11127 }
11128 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11129}
11130
11131/*
11132 * "setline()" function
11133 */
11134 static void
11135f_setline(typval_T *argvars, typval_T *rettv)
11136{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011137 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011138
Bram Moolenaarca851592018-06-06 21:04:07 +020011139 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011140}
11141
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011142/*
11143 * Used by "setqflist()" and "setloclist()" functions
11144 */
11145 static void
11146set_qf_ll_list(
11147 win_T *wp UNUSED,
11148 typval_T *list_arg UNUSED,
11149 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011150 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011151 typval_T *rettv)
11152{
11153#ifdef FEAT_QUICKFIX
11154 static char *e_invact = N_("E927: Invalid action: '%s'");
11155 char_u *act;
11156 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011157 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011158#endif
11159
11160 rettv->vval.v_number = -1;
11161
11162#ifdef FEAT_QUICKFIX
11163 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011164 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011165 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011166 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011167 else
11168 {
11169 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011170 dict_T *d = NULL;
11171 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011172
11173 if (action_arg->v_type == VAR_STRING)
11174 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011175 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011176 if (act == NULL)
11177 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011178 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11179 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011180 action = *act;
11181 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011182 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011183 }
11184 else if (action_arg->v_type == VAR_UNKNOWN)
11185 action = ' ';
11186 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011187 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011188
Bram Moolenaard823fa92016-08-12 16:29:27 +020011189 if (action_arg->v_type != VAR_UNKNOWN
11190 && what_arg->v_type != VAR_UNKNOWN)
11191 {
11192 if (what_arg->v_type == VAR_DICT)
11193 d = what_arg->vval.v_dict;
11194 else
11195 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011196 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011197 valid_dict = FALSE;
11198 }
11199 }
11200
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011201 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011202 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011203 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11204 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011205 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011206 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011207 }
11208#endif
11209}
11210
11211/*
11212 * "setloclist()" function
11213 */
11214 static void
11215f_setloclist(typval_T *argvars, typval_T *rettv)
11216{
11217 win_T *win;
11218
11219 rettv->vval.v_number = -1;
11220
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011221 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011222 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011223 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011224}
11225
11226/*
11227 * "setmatches()" function
11228 */
11229 static void
11230f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11231{
11232#ifdef FEAT_SEARCH_EXTRA
11233 list_T *l;
11234 listitem_T *li;
11235 dict_T *d;
11236 list_T *s = NULL;
Bram Moolenaaraff74912019-03-30 18:11:49 +010011237 win_T *win = get_optional_window(argvars, 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011238
11239 rettv->vval.v_number = -1;
11240 if (argvars[0].v_type != VAR_LIST)
11241 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011242 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011243 return;
11244 }
Bram Moolenaaraff74912019-03-30 18:11:49 +010011245 if (win == NULL)
11246 return;
11247
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011248 if ((l = argvars[0].vval.v_list) != NULL)
11249 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011250 /* To some extent make sure that we are dealing with a list from
11251 * "getmatches()". */
11252 li = l->lv_first;
11253 while (li != NULL)
11254 {
11255 if (li->li_tv.v_type != VAR_DICT
11256 || (d = li->li_tv.vval.v_dict) == NULL)
11257 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011258 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011259 return;
11260 }
11261 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11262 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11263 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11264 && dict_find(d, (char_u *)"priority", -1) != NULL
11265 && dict_find(d, (char_u *)"id", -1) != NULL))
11266 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011267 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011268 return;
11269 }
11270 li = li->li_next;
11271 }
11272
Bram Moolenaaraff74912019-03-30 18:11:49 +010011273 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011274 li = l->lv_first;
11275 while (li != NULL)
11276 {
11277 int i = 0;
11278 char_u buf[5];
11279 dictitem_T *di;
11280 char_u *group;
11281 int priority;
11282 int id;
11283 char_u *conceal;
11284
11285 d = li->li_tv.vval.v_dict;
11286 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11287 {
11288 if (s == NULL)
11289 {
11290 s = list_alloc();
11291 if (s == NULL)
11292 return;
11293 }
11294
11295 /* match from matchaddpos() */
11296 for (i = 1; i < 9; i++)
11297 {
11298 sprintf((char *)buf, (char *)"pos%d", i);
11299 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11300 {
11301 if (di->di_tv.v_type != VAR_LIST)
11302 return;
11303
11304 list_append_tv(s, &di->di_tv);
11305 s->lv_refcount++;
11306 }
11307 else
11308 break;
11309 }
11310 }
11311
Bram Moolenaar8f667172018-12-14 15:38:31 +010011312 group = dict_get_string(d, (char_u *)"group", TRUE);
11313 priority = (int)dict_get_number(d, (char_u *)"priority");
11314 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011315 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011316 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011317 : NULL;
11318 if (i == 0)
11319 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011320 match_add(win, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011321 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011322 priority, id, NULL, conceal);
11323 }
11324 else
11325 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011326 match_add(win, group, NULL, priority, id, s, conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011327 list_unref(s);
11328 s = NULL;
11329 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011330 vim_free(group);
11331 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011332
11333 li = li->li_next;
11334 }
11335 rettv->vval.v_number = 0;
11336 }
11337#endif
11338}
11339
11340/*
11341 * "setpos()" function
11342 */
11343 static void
11344f_setpos(typval_T *argvars, typval_T *rettv)
11345{
11346 pos_T pos;
11347 int fnum;
11348 char_u *name;
11349 colnr_T curswant = -1;
11350
11351 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011352 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011353 if (name != NULL)
11354 {
11355 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11356 {
11357 if (--pos.col < 0)
11358 pos.col = 0;
11359 if (name[0] == '.' && name[1] == NUL)
11360 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011361 /* set cursor; "fnum" is ignored */
11362 curwin->w_cursor = pos;
11363 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011364 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011365 curwin->w_curswant = curswant - 1;
11366 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011367 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011368 check_cursor();
11369 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011370 }
11371 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11372 {
11373 /* set mark */
11374 if (setmark_pos(name[1], &pos, fnum) == OK)
11375 rettv->vval.v_number = 0;
11376 }
11377 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011378 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011379 }
11380 }
11381}
11382
11383/*
11384 * "setqflist()" function
11385 */
11386 static void
11387f_setqflist(typval_T *argvars, typval_T *rettv)
11388{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011389 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011390}
11391
11392/*
11393 * "setreg()" function
11394 */
11395 static void
11396f_setreg(typval_T *argvars, typval_T *rettv)
11397{
11398 int regname;
11399 char_u *strregname;
11400 char_u *stropt;
11401 char_u *strval;
11402 int append;
11403 char_u yank_type;
11404 long block_len;
11405
11406 block_len = -1;
11407 yank_type = MAUTO;
11408 append = FALSE;
11409
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011410 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011411 rettv->vval.v_number = 1; /* FAIL is default */
11412
11413 if (strregname == NULL)
11414 return; /* type error; errmsg already given */
11415 regname = *strregname;
11416 if (regname == 0 || regname == '@')
11417 regname = '"';
11418
11419 if (argvars[2].v_type != VAR_UNKNOWN)
11420 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011421 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011422 if (stropt == NULL)
11423 return; /* type error */
11424 for (; *stropt != NUL; ++stropt)
11425 switch (*stropt)
11426 {
11427 case 'a': case 'A': /* append */
11428 append = TRUE;
11429 break;
11430 case 'v': case 'c': /* character-wise selection */
11431 yank_type = MCHAR;
11432 break;
11433 case 'V': case 'l': /* line-wise selection */
11434 yank_type = MLINE;
11435 break;
11436 case 'b': case Ctrl_V: /* block-wise selection */
11437 yank_type = MBLOCK;
11438 if (VIM_ISDIGIT(stropt[1]))
11439 {
11440 ++stropt;
11441 block_len = getdigits(&stropt) - 1;
11442 --stropt;
11443 }
11444 break;
11445 }
11446 }
11447
11448 if (argvars[1].v_type == VAR_LIST)
11449 {
11450 char_u **lstval;
11451 char_u **allocval;
11452 char_u buf[NUMBUFLEN];
11453 char_u **curval;
11454 char_u **curallocval;
11455 list_T *ll = argvars[1].vval.v_list;
11456 listitem_T *li;
11457 int len;
11458
11459 /* If the list is NULL handle like an empty list. */
11460 len = ll == NULL ? 0 : ll->lv_len;
11461
11462 /* First half: use for pointers to result lines; second half: use for
11463 * pointers to allocated copies. */
11464 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11465 if (lstval == NULL)
11466 return;
11467 curval = lstval;
11468 allocval = lstval + len + 2;
11469 curallocval = allocval;
11470
11471 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11472 li = li->li_next)
11473 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011474 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011475 if (strval == NULL)
11476 goto free_lstval;
11477 if (strval == buf)
11478 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011479 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011480 * overwrite the string. */
11481 strval = vim_strsave(buf);
11482 if (strval == NULL)
11483 goto free_lstval;
11484 *curallocval++ = strval;
11485 }
11486 *curval++ = strval;
11487 }
11488 *curval++ = NULL;
11489
11490 write_reg_contents_lst(regname, lstval, -1,
11491 append, yank_type, block_len);
11492free_lstval:
11493 while (curallocval > allocval)
11494 vim_free(*--curallocval);
11495 vim_free(lstval);
11496 }
11497 else
11498 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011499 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011500 if (strval == NULL)
11501 return;
11502 write_reg_contents_ex(regname, strval, -1,
11503 append, yank_type, block_len);
11504 }
11505 rettv->vval.v_number = 0;
11506}
11507
11508/*
11509 * "settabvar()" function
11510 */
11511 static void
11512f_settabvar(typval_T *argvars, typval_T *rettv)
11513{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011514 tabpage_T *save_curtab;
11515 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011516 char_u *varname, *tabvarname;
11517 typval_T *varp;
11518
11519 rettv->vval.v_number = 0;
11520
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011521 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011522 return;
11523
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011524 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11525 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011526 varp = &argvars[2];
11527
Bram Moolenaar4033c552017-09-16 20:54:51 +020011528 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011529 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011530 save_curtab = curtab;
11531 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011532
11533 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11534 if (tabvarname != NULL)
11535 {
11536 STRCPY(tabvarname, "t:");
11537 STRCPY(tabvarname + 2, varname);
11538 set_var(tabvarname, varp, TRUE);
11539 vim_free(tabvarname);
11540 }
11541
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011542 /* Restore current tabpage */
11543 if (valid_tabpage(save_curtab))
11544 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011545 }
11546}
11547
11548/*
11549 * "settabwinvar()" function
11550 */
11551 static void
11552f_settabwinvar(typval_T *argvars, typval_T *rettv)
11553{
11554 setwinvar(argvars, rettv, 1);
11555}
11556
11557/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011558 * "settagstack()" function
11559 */
11560 static void
11561f_settagstack(typval_T *argvars, typval_T *rettv)
11562{
11563 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11564 win_T *wp;
11565 dict_T *d;
11566 int action = 'r';
11567
11568 rettv->vval.v_number = -1;
11569
11570 // first argument: window number or id
11571 wp = find_win_by_nr_or_id(&argvars[0]);
11572 if (wp == NULL)
11573 return;
11574
11575 // second argument: dict with items to set in the tag stack
11576 if (argvars[1].v_type != VAR_DICT)
11577 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011578 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011579 return;
11580 }
11581 d = argvars[1].vval.v_dict;
11582 if (d == NULL)
11583 return;
11584
11585 // third argument: action - 'a' for append and 'r' for replace.
11586 // default is to replace the stack.
11587 if (argvars[2].v_type == VAR_UNKNOWN)
11588 action = 'r';
11589 else if (argvars[2].v_type == VAR_STRING)
11590 {
11591 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011592 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011593 if (actstr == NULL)
11594 return;
11595 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11596 action = *actstr;
11597 else
11598 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011599 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011600 return;
11601 }
11602 }
11603 else
11604 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011605 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011606 return;
11607 }
11608
11609 if (set_tagstack(wp, d, action) == OK)
11610 rettv->vval.v_number = 0;
11611}
11612
11613/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011614 * "setwinvar()" function
11615 */
11616 static void
11617f_setwinvar(typval_T *argvars, typval_T *rettv)
11618{
11619 setwinvar(argvars, rettv, 0);
11620}
11621
11622#ifdef FEAT_CRYPT
11623/*
11624 * "sha256({string})" function
11625 */
11626 static void
11627f_sha256(typval_T *argvars, typval_T *rettv)
11628{
11629 char_u *p;
11630
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011631 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011632 rettv->vval.v_string = vim_strsave(
11633 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11634 rettv->v_type = VAR_STRING;
11635}
11636#endif /* FEAT_CRYPT */
11637
11638/*
11639 * "shellescape({string})" function
11640 */
11641 static void
11642f_shellescape(typval_T *argvars, typval_T *rettv)
11643{
Bram Moolenaar20615522017-06-05 18:46:26 +020011644 int do_special = non_zero_arg(&argvars[1]);
11645
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011646 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011647 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011648 rettv->v_type = VAR_STRING;
11649}
11650
11651/*
11652 * shiftwidth() function
11653 */
11654 static void
11655f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11656{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011657 rettv->vval.v_number = 0;
11658
11659 if (argvars[0].v_type != VAR_UNKNOWN)
11660 {
11661 long col;
11662
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011663 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011664 if (col < 0)
11665 return; // type error; errmsg already given
11666#ifdef FEAT_VARTABS
11667 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11668 return;
11669#endif
11670 }
11671
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011672 rettv->vval.v_number = get_sw_value(curbuf);
11673}
11674
Bram Moolenaar162b7142018-12-21 15:17:36 +010011675#ifdef FEAT_SIGNS
11676/*
11677 * "sign_define()" function
11678 */
11679 static void
11680f_sign_define(typval_T *argvars, typval_T *rettv)
11681{
11682 char_u *name;
11683 dict_T *dict;
11684 char_u *icon = NULL;
11685 char_u *linehl = NULL;
11686 char_u *text = NULL;
11687 char_u *texthl = NULL;
11688
11689 rettv->vval.v_number = -1;
11690
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011691 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011692 if (name == NULL)
11693 return;
11694
11695 if (argvars[1].v_type != VAR_UNKNOWN)
11696 {
11697 if (argvars[1].v_type != VAR_DICT)
11698 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011699 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011700 return;
11701 }
11702
11703 // sign attributes
11704 dict = argvars[1].vval.v_dict;
11705 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11706 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11707 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11708 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11709 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11710 text = dict_get_string(dict, (char_u *)"text", TRUE);
11711 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11712 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11713 }
11714
11715 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11716 rettv->vval.v_number = 0;
11717
11718 vim_free(icon);
11719 vim_free(linehl);
11720 vim_free(text);
11721 vim_free(texthl);
11722}
11723
11724/*
11725 * "sign_getdefined()" function
11726 */
11727 static void
11728f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11729{
11730 char_u *name = NULL;
11731
11732 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11733 return;
11734
11735 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011736 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011737
11738 sign_getlist(name, rettv->vval.v_list);
11739}
11740
11741/*
11742 * "sign_getplaced()" function
11743 */
11744 static void
11745f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11746{
11747 buf_T *buf = NULL;
11748 dict_T *dict;
11749 dictitem_T *di;
11750 linenr_T lnum = 0;
11751 int sign_id = 0;
11752 char_u *group = NULL;
11753 int notanum = FALSE;
11754
11755 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11756 return;
11757
11758 if (argvars[0].v_type != VAR_UNKNOWN)
11759 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011760 // get signs placed in the specified buffer
11761 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011762 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011763 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011764
11765 if (argvars[1].v_type != VAR_UNKNOWN)
11766 {
11767 if (argvars[1].v_type != VAR_DICT ||
11768 ((dict = argvars[1].vval.v_dict) == NULL))
11769 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011770 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011771 return;
11772 }
11773 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11774 {
11775 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011776 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011777 if (notanum)
11778 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011779 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011780 }
11781 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11782 {
11783 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011784 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011785 if (notanum)
11786 return;
11787 }
11788 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11789 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011790 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011791 if (group == NULL)
11792 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011793 if (*group == '\0') // empty string means global group
11794 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011795 }
11796 }
11797 }
11798
11799 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11800}
11801
11802/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011803 * "sign_jump()" function
11804 */
11805 static void
11806f_sign_jump(typval_T *argvars, typval_T *rettv)
11807{
11808 int sign_id;
11809 char_u *sign_group = NULL;
11810 buf_T *buf;
11811 int notanum = FALSE;
11812
11813 rettv->vval.v_number = -1;
11814
Bram Moolenaarbdace832019-03-02 10:13:42 +010011815 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011816 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11817 if (notanum)
11818 return;
11819 if (sign_id <= 0)
11820 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011821 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011822 return;
11823 }
11824
11825 // Sign group
11826 sign_group = tv_get_string_chk(&argvars[1]);
11827 if (sign_group == NULL)
11828 return;
11829 if (sign_group[0] == '\0')
11830 sign_group = NULL; // global sign group
11831 else
11832 {
11833 sign_group = vim_strsave(sign_group);
11834 if (sign_group == NULL)
11835 return;
11836 }
11837
11838 // Buffer to place the sign
11839 buf = get_buf_arg(&argvars[2]);
11840 if (buf == NULL)
11841 goto cleanup;
11842
11843 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11844
11845cleanup:
11846 vim_free(sign_group);
11847}
11848
11849/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011850 * "sign_place()" function
11851 */
11852 static void
11853f_sign_place(typval_T *argvars, typval_T *rettv)
11854{
11855 int sign_id;
11856 char_u *group = NULL;
11857 char_u *sign_name;
11858 buf_T *buf;
11859 dict_T *dict;
11860 dictitem_T *di;
11861 linenr_T lnum = 0;
11862 int prio = SIGN_DEF_PRIO;
11863 int notanum = FALSE;
11864
11865 rettv->vval.v_number = -1;
11866
Bram Moolenaarbdace832019-03-02 10:13:42 +010011867 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011868 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011869 if (notanum)
11870 return;
11871 if (sign_id < 0)
11872 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011873 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011874 return;
11875 }
11876
11877 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011878 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011879 if (group == NULL)
11880 return;
11881 if (group[0] == '\0')
11882 group = NULL; // global sign group
11883 else
11884 {
11885 group = vim_strsave(group);
11886 if (group == NULL)
11887 return;
11888 }
11889
11890 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011891 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011892 if (sign_name == NULL)
11893 goto cleanup;
11894
11895 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011896 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011897 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011898 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011899
11900 if (argvars[4].v_type != VAR_UNKNOWN)
11901 {
11902 if (argvars[4].v_type != VAR_DICT ||
11903 ((dict = argvars[4].vval.v_dict) == NULL))
11904 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011905 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011906 goto cleanup;
11907 }
11908
11909 // Line number where the sign is to be placed
11910 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11911 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011912 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011913 if (notanum)
11914 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011915 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011916 }
11917 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11918 {
11919 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011920 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011921 if (notanum)
11922 goto cleanup;
11923 }
11924 }
11925
11926 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11927 rettv->vval.v_number = sign_id;
11928
11929cleanup:
11930 vim_free(group);
11931}
11932
11933/*
11934 * "sign_undefine()" function
11935 */
11936 static void
11937f_sign_undefine(typval_T *argvars, typval_T *rettv)
11938{
11939 char_u *name;
11940
11941 rettv->vval.v_number = -1;
11942
11943 if (argvars[0].v_type == VAR_UNKNOWN)
11944 {
11945 // Free all the signs
11946 free_signs();
11947 rettv->vval.v_number = 0;
11948 }
11949 else
11950 {
11951 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011952 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011953 if (name == NULL)
11954 return;
11955
11956 if (sign_undefine_by_name(name) == OK)
11957 rettv->vval.v_number = 0;
11958 }
11959}
11960
11961/*
11962 * "sign_unplace()" function
11963 */
11964 static void
11965f_sign_unplace(typval_T *argvars, typval_T *rettv)
11966{
11967 dict_T *dict;
11968 dictitem_T *di;
11969 int sign_id = 0;
11970 buf_T *buf = NULL;
11971 char_u *group = NULL;
11972
11973 rettv->vval.v_number = -1;
11974
11975 if (argvars[0].v_type != VAR_STRING)
11976 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011977 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011978 return;
11979 }
11980
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011981 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011982 if (group[0] == '\0')
11983 group = NULL; // global sign group
11984 else
11985 {
11986 group = vim_strsave(group);
11987 if (group == NULL)
11988 return;
11989 }
11990
11991 if (argvars[1].v_type != VAR_UNKNOWN)
11992 {
11993 if (argvars[1].v_type != VAR_DICT)
11994 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011995 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011996 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011997 }
11998 dict = argvars[1].vval.v_dict;
11999
12000 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
12001 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012002 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012003 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012004 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012005 }
12006 if (dict_find(dict, (char_u *)"id", -1) != NULL)
12007 sign_id = dict_get_number(dict, (char_u *)"id");
12008 }
12009
12010 if (buf == NULL)
12011 {
12012 // Delete the sign in all the buffers
12013 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012014 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012015 rettv->vval.v_number = 0;
12016 }
12017 else
12018 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012019 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012020 rettv->vval.v_number = 0;
12021 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012022
12023cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010012024 vim_free(group);
12025}
12026#endif
12027
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012028/*
12029 * "simplify()" function
12030 */
12031 static void
12032f_simplify(typval_T *argvars, typval_T *rettv)
12033{
12034 char_u *p;
12035
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012036 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012037 rettv->vval.v_string = vim_strsave(p);
12038 simplify_filename(rettv->vval.v_string); /* simplify in place */
12039 rettv->v_type = VAR_STRING;
12040}
12041
12042#ifdef FEAT_FLOAT
12043/*
12044 * "sin()" function
12045 */
12046 static void
12047f_sin(typval_T *argvars, typval_T *rettv)
12048{
12049 float_T f = 0.0;
12050
12051 rettv->v_type = VAR_FLOAT;
12052 if (get_float_arg(argvars, &f) == OK)
12053 rettv->vval.v_float = sin(f);
12054 else
12055 rettv->vval.v_float = 0.0;
12056}
12057
12058/*
12059 * "sinh()" function
12060 */
12061 static void
12062f_sinh(typval_T *argvars, typval_T *rettv)
12063{
12064 float_T f = 0.0;
12065
12066 rettv->v_type = VAR_FLOAT;
12067 if (get_float_arg(argvars, &f) == OK)
12068 rettv->vval.v_float = sinh(f);
12069 else
12070 rettv->vval.v_float = 0.0;
12071}
12072#endif
12073
12074static int
12075#ifdef __BORLANDC__
12076 _RTLENTRYF
12077#endif
12078 item_compare(const void *s1, const void *s2);
12079static int
12080#ifdef __BORLANDC__
12081 _RTLENTRYF
12082#endif
12083 item_compare2(const void *s1, const void *s2);
12084
12085/* struct used in the array that's given to qsort() */
12086typedef struct
12087{
12088 listitem_T *item;
12089 int idx;
12090} sortItem_T;
12091
12092/* struct storing information about current sort */
12093typedef struct
12094{
12095 int item_compare_ic;
12096 int item_compare_numeric;
12097 int item_compare_numbers;
12098#ifdef FEAT_FLOAT
12099 int item_compare_float;
12100#endif
12101 char_u *item_compare_func;
12102 partial_T *item_compare_partial;
12103 dict_T *item_compare_selfdict;
12104 int item_compare_func_err;
12105 int item_compare_keep_zero;
12106} sortinfo_T;
12107static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012108#define ITEM_COMPARE_FAIL 999
12109
12110/*
12111 * Compare functions for f_sort() and f_uniq() below.
12112 */
12113 static int
12114#ifdef __BORLANDC__
12115_RTLENTRYF
12116#endif
12117item_compare(const void *s1, const void *s2)
12118{
12119 sortItem_T *si1, *si2;
12120 typval_T *tv1, *tv2;
12121 char_u *p1, *p2;
12122 char_u *tofree1 = NULL, *tofree2 = NULL;
12123 int res;
12124 char_u numbuf1[NUMBUFLEN];
12125 char_u numbuf2[NUMBUFLEN];
12126
12127 si1 = (sortItem_T *)s1;
12128 si2 = (sortItem_T *)s2;
12129 tv1 = &si1->item->li_tv;
12130 tv2 = &si2->item->li_tv;
12131
12132 if (sortinfo->item_compare_numbers)
12133 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012134 varnumber_T v1 = tv_get_number(tv1);
12135 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012136
12137 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12138 }
12139
12140#ifdef FEAT_FLOAT
12141 if (sortinfo->item_compare_float)
12142 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012143 float_T v1 = tv_get_float(tv1);
12144 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012145
12146 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12147 }
12148#endif
12149
12150 /* tv2string() puts quotes around a string and allocates memory. Don't do
12151 * that for string variables. Use a single quote when comparing with a
12152 * non-string to do what the docs promise. */
12153 if (tv1->v_type == VAR_STRING)
12154 {
12155 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12156 p1 = (char_u *)"'";
12157 else
12158 p1 = tv1->vval.v_string;
12159 }
12160 else
12161 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12162 if (tv2->v_type == VAR_STRING)
12163 {
12164 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12165 p2 = (char_u *)"'";
12166 else
12167 p2 = tv2->vval.v_string;
12168 }
12169 else
12170 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12171 if (p1 == NULL)
12172 p1 = (char_u *)"";
12173 if (p2 == NULL)
12174 p2 = (char_u *)"";
12175 if (!sortinfo->item_compare_numeric)
12176 {
12177 if (sortinfo->item_compare_ic)
12178 res = STRICMP(p1, p2);
12179 else
12180 res = STRCMP(p1, p2);
12181 }
12182 else
12183 {
12184 double n1, n2;
12185 n1 = strtod((char *)p1, (char **)&p1);
12186 n2 = strtod((char *)p2, (char **)&p2);
12187 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12188 }
12189
12190 /* When the result would be zero, compare the item indexes. Makes the
12191 * sort stable. */
12192 if (res == 0 && !sortinfo->item_compare_keep_zero)
12193 res = si1->idx > si2->idx ? 1 : -1;
12194
12195 vim_free(tofree1);
12196 vim_free(tofree2);
12197 return res;
12198}
12199
12200 static int
12201#ifdef __BORLANDC__
12202_RTLENTRYF
12203#endif
12204item_compare2(const void *s1, const void *s2)
12205{
12206 sortItem_T *si1, *si2;
12207 int res;
12208 typval_T rettv;
12209 typval_T argv[3];
12210 int dummy;
12211 char_u *func_name;
12212 partial_T *partial = sortinfo->item_compare_partial;
12213
12214 /* shortcut after failure in previous call; compare all items equal */
12215 if (sortinfo->item_compare_func_err)
12216 return 0;
12217
12218 si1 = (sortItem_T *)s1;
12219 si2 = (sortItem_T *)s2;
12220
12221 if (partial == NULL)
12222 func_name = sortinfo->item_compare_func;
12223 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012224 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012225
12226 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12227 * in the copy without changing the original list items. */
12228 copy_tv(&si1->item->li_tv, &argv[0]);
12229 copy_tv(&si2->item->li_tv, &argv[1]);
12230
12231 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
12232 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020012233 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012234 partial, sortinfo->item_compare_selfdict);
12235 clear_tv(&argv[0]);
12236 clear_tv(&argv[1]);
12237
12238 if (res == FAIL)
12239 res = ITEM_COMPARE_FAIL;
12240 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012241 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012242 if (sortinfo->item_compare_func_err)
12243 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12244 clear_tv(&rettv);
12245
12246 /* When the result would be zero, compare the pointers themselves. Makes
12247 * the sort stable. */
12248 if (res == 0 && !sortinfo->item_compare_keep_zero)
12249 res = si1->idx > si2->idx ? 1 : -1;
12250
12251 return res;
12252}
12253
12254/*
12255 * "sort({list})" function
12256 */
12257 static void
12258do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12259{
12260 list_T *l;
12261 listitem_T *li;
12262 sortItem_T *ptrs;
12263 sortinfo_T *old_sortinfo;
12264 sortinfo_T info;
12265 long len;
12266 long i;
12267
12268 /* Pointer to current info struct used in compare function. Save and
12269 * restore the current one for nested calls. */
12270 old_sortinfo = sortinfo;
12271 sortinfo = &info;
12272
12273 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012274 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012275 else
12276 {
12277 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012278 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012279 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12280 TRUE))
12281 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012282 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012283
12284 len = list_len(l);
12285 if (len <= 1)
12286 goto theend; /* short list sorts pretty quickly */
12287
12288 info.item_compare_ic = FALSE;
12289 info.item_compare_numeric = FALSE;
12290 info.item_compare_numbers = FALSE;
12291#ifdef FEAT_FLOAT
12292 info.item_compare_float = FALSE;
12293#endif
12294 info.item_compare_func = NULL;
12295 info.item_compare_partial = NULL;
12296 info.item_compare_selfdict = NULL;
12297 if (argvars[1].v_type != VAR_UNKNOWN)
12298 {
12299 /* optional second argument: {func} */
12300 if (argvars[1].v_type == VAR_FUNC)
12301 info.item_compare_func = argvars[1].vval.v_string;
12302 else if (argvars[1].v_type == VAR_PARTIAL)
12303 info.item_compare_partial = argvars[1].vval.v_partial;
12304 else
12305 {
12306 int error = FALSE;
12307
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012308 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012309 if (error)
12310 goto theend; /* type error; errmsg already given */
12311 if (i == 1)
12312 info.item_compare_ic = TRUE;
12313 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012314 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012315 else if (i != 0)
12316 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012317 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012318 goto theend;
12319 }
12320 if (info.item_compare_func != NULL)
12321 {
12322 if (*info.item_compare_func == NUL)
12323 {
12324 /* empty string means default sort */
12325 info.item_compare_func = NULL;
12326 }
12327 else if (STRCMP(info.item_compare_func, "n") == 0)
12328 {
12329 info.item_compare_func = NULL;
12330 info.item_compare_numeric = TRUE;
12331 }
12332 else if (STRCMP(info.item_compare_func, "N") == 0)
12333 {
12334 info.item_compare_func = NULL;
12335 info.item_compare_numbers = TRUE;
12336 }
12337#ifdef FEAT_FLOAT
12338 else if (STRCMP(info.item_compare_func, "f") == 0)
12339 {
12340 info.item_compare_func = NULL;
12341 info.item_compare_float = TRUE;
12342 }
12343#endif
12344 else if (STRCMP(info.item_compare_func, "i") == 0)
12345 {
12346 info.item_compare_func = NULL;
12347 info.item_compare_ic = TRUE;
12348 }
12349 }
12350 }
12351
12352 if (argvars[2].v_type != VAR_UNKNOWN)
12353 {
12354 /* optional third argument: {dict} */
12355 if (argvars[2].v_type != VAR_DICT)
12356 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012357 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012358 goto theend;
12359 }
12360 info.item_compare_selfdict = argvars[2].vval.v_dict;
12361 }
12362 }
12363
12364 /* Make an array with each entry pointing to an item in the List. */
12365 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12366 if (ptrs == NULL)
12367 goto theend;
12368
12369 i = 0;
12370 if (sort)
12371 {
12372 /* sort(): ptrs will be the list to sort */
12373 for (li = l->lv_first; li != NULL; li = li->li_next)
12374 {
12375 ptrs[i].item = li;
12376 ptrs[i].idx = i;
12377 ++i;
12378 }
12379
12380 info.item_compare_func_err = FALSE;
12381 info.item_compare_keep_zero = FALSE;
12382 /* test the compare function */
12383 if ((info.item_compare_func != NULL
12384 || info.item_compare_partial != NULL)
12385 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12386 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012387 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012388 else
12389 {
12390 /* Sort the array with item pointers. */
12391 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12392 info.item_compare_func == NULL
12393 && info.item_compare_partial == NULL
12394 ? item_compare : item_compare2);
12395
12396 if (!info.item_compare_func_err)
12397 {
12398 /* Clear the List and append the items in sorted order. */
12399 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12400 l->lv_len = 0;
12401 for (i = 0; i < len; ++i)
12402 list_append(l, ptrs[i].item);
12403 }
12404 }
12405 }
12406 else
12407 {
12408 int (*item_compare_func_ptr)(const void *, const void *);
12409
12410 /* f_uniq(): ptrs will be a stack of items to remove */
12411 info.item_compare_func_err = FALSE;
12412 info.item_compare_keep_zero = TRUE;
12413 item_compare_func_ptr = info.item_compare_func != NULL
12414 || info.item_compare_partial != NULL
12415 ? item_compare2 : item_compare;
12416
12417 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12418 li = li->li_next)
12419 {
12420 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12421 == 0)
12422 ptrs[i++].item = li;
12423 if (info.item_compare_func_err)
12424 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012425 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012426 break;
12427 }
12428 }
12429
12430 if (!info.item_compare_func_err)
12431 {
12432 while (--i >= 0)
12433 {
12434 li = ptrs[i].item->li_next;
12435 ptrs[i].item->li_next = li->li_next;
12436 if (li->li_next != NULL)
12437 li->li_next->li_prev = ptrs[i].item;
12438 else
12439 l->lv_last = ptrs[i].item;
12440 list_fix_watch(l, li);
12441 listitem_free(li);
12442 l->lv_len--;
12443 }
12444 }
12445 }
12446
12447 vim_free(ptrs);
12448 }
12449theend:
12450 sortinfo = old_sortinfo;
12451}
12452
12453/*
12454 * "sort({list})" function
12455 */
12456 static void
12457f_sort(typval_T *argvars, typval_T *rettv)
12458{
12459 do_sort_uniq(argvars, rettv, TRUE);
12460}
12461
12462/*
12463 * "uniq({list})" function
12464 */
12465 static void
12466f_uniq(typval_T *argvars, typval_T *rettv)
12467{
12468 do_sort_uniq(argvars, rettv, FALSE);
12469}
12470
12471/*
12472 * "soundfold({word})" function
12473 */
12474 static void
12475f_soundfold(typval_T *argvars, typval_T *rettv)
12476{
12477 char_u *s;
12478
12479 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012480 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012481#ifdef FEAT_SPELL
12482 rettv->vval.v_string = eval_soundfold(s);
12483#else
12484 rettv->vval.v_string = vim_strsave(s);
12485#endif
12486}
12487
12488/*
12489 * "spellbadword()" function
12490 */
12491 static void
12492f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12493{
12494 char_u *word = (char_u *)"";
12495 hlf_T attr = HLF_COUNT;
12496 int len = 0;
12497
12498 if (rettv_list_alloc(rettv) == FAIL)
12499 return;
12500
12501#ifdef FEAT_SPELL
12502 if (argvars[0].v_type == VAR_UNKNOWN)
12503 {
12504 /* Find the start and length of the badly spelled word. */
12505 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12506 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012507 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012508 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012509 curwin->w_set_curswant = TRUE;
12510 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012511 }
12512 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12513 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012514 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012515 int capcol = -1;
12516
12517 if (str != NULL)
12518 {
12519 /* Check the argument for spelling. */
12520 while (*str != NUL)
12521 {
12522 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12523 if (attr != HLF_COUNT)
12524 {
12525 word = str;
12526 break;
12527 }
12528 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012529 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012530 }
12531 }
12532 }
12533#endif
12534
12535 list_append_string(rettv->vval.v_list, word, len);
12536 list_append_string(rettv->vval.v_list, (char_u *)(
12537 attr == HLF_SPB ? "bad" :
12538 attr == HLF_SPR ? "rare" :
12539 attr == HLF_SPL ? "local" :
12540 attr == HLF_SPC ? "caps" :
12541 ""), -1);
12542}
12543
12544/*
12545 * "spellsuggest()" function
12546 */
12547 static void
12548f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12549{
12550#ifdef FEAT_SPELL
12551 char_u *str;
12552 int typeerr = FALSE;
12553 int maxcount;
12554 garray_T ga;
12555 int i;
12556 listitem_T *li;
12557 int need_capital = FALSE;
12558#endif
12559
12560 if (rettv_list_alloc(rettv) == FAIL)
12561 return;
12562
12563#ifdef FEAT_SPELL
12564 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12565 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012566 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012567 if (argvars[1].v_type != VAR_UNKNOWN)
12568 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012569 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012570 if (maxcount <= 0)
12571 return;
12572 if (argvars[2].v_type != VAR_UNKNOWN)
12573 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012574 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012575 if (typeerr)
12576 return;
12577 }
12578 }
12579 else
12580 maxcount = 25;
12581
12582 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12583
12584 for (i = 0; i < ga.ga_len; ++i)
12585 {
12586 str = ((char_u **)ga.ga_data)[i];
12587
12588 li = listitem_alloc();
12589 if (li == NULL)
12590 vim_free(str);
12591 else
12592 {
12593 li->li_tv.v_type = VAR_STRING;
12594 li->li_tv.v_lock = 0;
12595 li->li_tv.vval.v_string = str;
12596 list_append(rettv->vval.v_list, li);
12597 }
12598 }
12599 ga_clear(&ga);
12600 }
12601#endif
12602}
12603
12604 static void
12605f_split(typval_T *argvars, typval_T *rettv)
12606{
12607 char_u *str;
12608 char_u *end;
12609 char_u *pat = NULL;
12610 regmatch_T regmatch;
12611 char_u patbuf[NUMBUFLEN];
12612 char_u *save_cpo;
12613 int match;
12614 colnr_T col = 0;
12615 int keepempty = FALSE;
12616 int typeerr = FALSE;
12617
12618 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12619 save_cpo = p_cpo;
12620 p_cpo = (char_u *)"";
12621
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012622 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012623 if (argvars[1].v_type != VAR_UNKNOWN)
12624 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012625 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012626 if (pat == NULL)
12627 typeerr = TRUE;
12628 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012629 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012630 }
12631 if (pat == NULL || *pat == NUL)
12632 pat = (char_u *)"[\\x01- ]\\+";
12633
12634 if (rettv_list_alloc(rettv) == FAIL)
12635 return;
12636 if (typeerr)
12637 return;
12638
12639 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12640 if (regmatch.regprog != NULL)
12641 {
12642 regmatch.rm_ic = FALSE;
12643 while (*str != NUL || keepempty)
12644 {
12645 if (*str == NUL)
12646 match = FALSE; /* empty item at the end */
12647 else
12648 match = vim_regexec_nl(&regmatch, str, col);
12649 if (match)
12650 end = regmatch.startp[0];
12651 else
12652 end = str + STRLEN(str);
12653 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12654 && *str != NUL && match && end < regmatch.endp[0]))
12655 {
12656 if (list_append_string(rettv->vval.v_list, str,
12657 (int)(end - str)) == FAIL)
12658 break;
12659 }
12660 if (!match)
12661 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010012662 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012663 if (regmatch.endp[0] > str)
12664 col = 0;
12665 else
Bram Moolenaar13505972019-01-24 15:04:48 +010012666 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012667 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012668 str = regmatch.endp[0];
12669 }
12670
12671 vim_regfree(regmatch.regprog);
12672 }
12673
12674 p_cpo = save_cpo;
12675}
12676
12677#ifdef FEAT_FLOAT
12678/*
12679 * "sqrt()" function
12680 */
12681 static void
12682f_sqrt(typval_T *argvars, typval_T *rettv)
12683{
12684 float_T f = 0.0;
12685
12686 rettv->v_type = VAR_FLOAT;
12687 if (get_float_arg(argvars, &f) == OK)
12688 rettv->vval.v_float = sqrt(f);
12689 else
12690 rettv->vval.v_float = 0.0;
12691}
12692
12693/*
12694 * "str2float()" function
12695 */
12696 static void
12697f_str2float(typval_T *argvars, typval_T *rettv)
12698{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012699 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012700 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012701
Bram Moolenaar08243d22017-01-10 16:12:29 +010012702 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012703 p = skipwhite(p + 1);
12704 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012705 if (isneg)
12706 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012707 rettv->v_type = VAR_FLOAT;
12708}
12709#endif
12710
12711/*
12712 * "str2nr()" function
12713 */
12714 static void
12715f_str2nr(typval_T *argvars, typval_T *rettv)
12716{
12717 int base = 10;
12718 char_u *p;
12719 varnumber_T n;
12720 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012721 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012722
12723 if (argvars[1].v_type != VAR_UNKNOWN)
12724 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012725 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012726 if (base != 2 && base != 8 && base != 10 && base != 16)
12727 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012728 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012729 return;
12730 }
12731 }
12732
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012733 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012734 isneg = (*p == '-');
12735 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012736 p = skipwhite(p + 1);
12737 switch (base)
12738 {
12739 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12740 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12741 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12742 default: what = 0;
12743 }
12744 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012745 if (isneg)
12746 rettv->vval.v_number = -n;
12747 else
12748 rettv->vval.v_number = n;
12749
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012750}
12751
12752#ifdef HAVE_STRFTIME
12753/*
12754 * "strftime({format}[, {time}])" function
12755 */
12756 static void
12757f_strftime(typval_T *argvars, typval_T *rettv)
12758{
12759 char_u result_buf[256];
12760 struct tm *curtime;
12761 time_t seconds;
12762 char_u *p;
12763
12764 rettv->v_type = VAR_STRING;
12765
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012766 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012767 if (argvars[1].v_type == VAR_UNKNOWN)
12768 seconds = time(NULL);
12769 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012770 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012771 curtime = localtime(&seconds);
12772 /* MSVC returns NULL for an invalid value of seconds. */
12773 if (curtime == NULL)
12774 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12775 else
12776 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012777 vimconv_T conv;
12778 char_u *enc;
12779
12780 conv.vc_type = CONV_NONE;
12781 enc = enc_locale();
12782 convert_setup(&conv, p_enc, enc);
12783 if (conv.vc_type != CONV_NONE)
12784 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012785 if (p != NULL)
12786 (void)strftime((char *)result_buf, sizeof(result_buf),
12787 (char *)p, curtime);
12788 else
12789 result_buf[0] = NUL;
12790
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012791 if (conv.vc_type != CONV_NONE)
12792 vim_free(p);
12793 convert_setup(&conv, enc, p_enc);
12794 if (conv.vc_type != CONV_NONE)
12795 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12796 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012797 rettv->vval.v_string = vim_strsave(result_buf);
12798
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012799 /* Release conversion descriptors */
12800 convert_setup(&conv, NULL, NULL);
12801 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012802 }
12803}
12804#endif
12805
12806/*
12807 * "strgetchar()" function
12808 */
12809 static void
12810f_strgetchar(typval_T *argvars, typval_T *rettv)
12811{
12812 char_u *str;
12813 int len;
12814 int error = FALSE;
12815 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012816 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012817
12818 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012819 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012820 if (str == NULL)
12821 return;
12822 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012823 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012824 if (error)
12825 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012826
Bram Moolenaar13505972019-01-24 15:04:48 +010012827 while (charidx >= 0 && byteidx < len)
12828 {
12829 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012830 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012831 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12832 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012833 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012834 --charidx;
12835 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012836 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012837}
12838
12839/*
12840 * "stridx()" function
12841 */
12842 static void
12843f_stridx(typval_T *argvars, typval_T *rettv)
12844{
12845 char_u buf[NUMBUFLEN];
12846 char_u *needle;
12847 char_u *haystack;
12848 char_u *save_haystack;
12849 char_u *pos;
12850 int start_idx;
12851
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012852 needle = tv_get_string_chk(&argvars[1]);
12853 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012854 rettv->vval.v_number = -1;
12855 if (needle == NULL || haystack == NULL)
12856 return; /* type error; errmsg already given */
12857
12858 if (argvars[2].v_type != VAR_UNKNOWN)
12859 {
12860 int error = FALSE;
12861
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012862 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012863 if (error || start_idx >= (int)STRLEN(haystack))
12864 return;
12865 if (start_idx >= 0)
12866 haystack += start_idx;
12867 }
12868
12869 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12870 if (pos != NULL)
12871 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12872}
12873
12874/*
12875 * "string()" function
12876 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012877 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012878f_string(typval_T *argvars, typval_T *rettv)
12879{
12880 char_u *tofree;
12881 char_u numbuf[NUMBUFLEN];
12882
12883 rettv->v_type = VAR_STRING;
12884 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12885 get_copyID());
12886 /* Make a copy if we have a value but it's not in allocated memory. */
12887 if (rettv->vval.v_string != NULL && tofree == NULL)
12888 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12889}
12890
12891/*
12892 * "strlen()" function
12893 */
12894 static void
12895f_strlen(typval_T *argvars, typval_T *rettv)
12896{
12897 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012898 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012899}
12900
12901/*
12902 * "strchars()" function
12903 */
12904 static void
12905f_strchars(typval_T *argvars, typval_T *rettv)
12906{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012907 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012908 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012909 varnumber_T len = 0;
12910 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012911
12912 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012913 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012914 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012915 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012916 else
12917 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012918 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12919 while (*s != NUL)
12920 {
12921 func_mb_ptr2char_adv(&s);
12922 ++len;
12923 }
12924 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012925 }
12926}
12927
12928/*
12929 * "strdisplaywidth()" function
12930 */
12931 static void
12932f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12933{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012934 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012935 int col = 0;
12936
12937 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012938 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012939
12940 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12941}
12942
12943/*
12944 * "strwidth()" function
12945 */
12946 static void
12947f_strwidth(typval_T *argvars, typval_T *rettv)
12948{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012949 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012950
Bram Moolenaar13505972019-01-24 15:04:48 +010012951 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012952}
12953
12954/*
12955 * "strcharpart()" function
12956 */
12957 static void
12958f_strcharpart(typval_T *argvars, typval_T *rettv)
12959{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012960 char_u *p;
12961 int nchar;
12962 int nbyte = 0;
12963 int charlen;
12964 int len = 0;
12965 int slen;
12966 int error = FALSE;
12967
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012968 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012969 slen = (int)STRLEN(p);
12970
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012971 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012972 if (!error)
12973 {
12974 if (nchar > 0)
12975 while (nchar > 0 && nbyte < slen)
12976 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012977 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012978 --nchar;
12979 }
12980 else
12981 nbyte = nchar;
12982 if (argvars[2].v_type != VAR_UNKNOWN)
12983 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012984 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012985 while (charlen > 0 && nbyte + len < slen)
12986 {
12987 int off = nbyte + len;
12988
12989 if (off < 0)
12990 len += 1;
12991 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012992 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012993 --charlen;
12994 }
12995 }
12996 else
12997 len = slen - nbyte; /* default: all bytes that are available. */
12998 }
12999
13000 /*
13001 * Only return the overlap between the specified part and the actual
13002 * string.
13003 */
13004 if (nbyte < 0)
13005 {
13006 len += nbyte;
13007 nbyte = 0;
13008 }
13009 else if (nbyte > slen)
13010 nbyte = slen;
13011 if (len < 0)
13012 len = 0;
13013 else if (nbyte + len > slen)
13014 len = slen - nbyte;
13015
13016 rettv->v_type = VAR_STRING;
13017 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013018}
13019
13020/*
13021 * "strpart()" function
13022 */
13023 static void
13024f_strpart(typval_T *argvars, typval_T *rettv)
13025{
13026 char_u *p;
13027 int n;
13028 int len;
13029 int slen;
13030 int error = FALSE;
13031
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013032 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013033 slen = (int)STRLEN(p);
13034
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013035 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013036 if (error)
13037 len = 0;
13038 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013039 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013040 else
13041 len = slen - n; /* default len: all bytes that are available. */
13042
13043 /*
13044 * Only return the overlap between the specified part and the actual
13045 * string.
13046 */
13047 if (n < 0)
13048 {
13049 len += n;
13050 n = 0;
13051 }
13052 else if (n > slen)
13053 n = slen;
13054 if (len < 0)
13055 len = 0;
13056 else if (n + len > slen)
13057 len = slen - n;
13058
13059 rettv->v_type = VAR_STRING;
13060 rettv->vval.v_string = vim_strnsave(p + n, len);
13061}
13062
13063/*
13064 * "strridx()" function
13065 */
13066 static void
13067f_strridx(typval_T *argvars, typval_T *rettv)
13068{
13069 char_u buf[NUMBUFLEN];
13070 char_u *needle;
13071 char_u *haystack;
13072 char_u *rest;
13073 char_u *lastmatch = NULL;
13074 int haystack_len, end_idx;
13075
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013076 needle = tv_get_string_chk(&argvars[1]);
13077 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013078
13079 rettv->vval.v_number = -1;
13080 if (needle == NULL || haystack == NULL)
13081 return; /* type error; errmsg already given */
13082
13083 haystack_len = (int)STRLEN(haystack);
13084 if (argvars[2].v_type != VAR_UNKNOWN)
13085 {
13086 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013087 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013088 if (end_idx < 0)
13089 return; /* can never find a match */
13090 }
13091 else
13092 end_idx = haystack_len;
13093
13094 if (*needle == NUL)
13095 {
13096 /* Empty string matches past the end. */
13097 lastmatch = haystack + end_idx;
13098 }
13099 else
13100 {
13101 for (rest = haystack; *rest != '\0'; ++rest)
13102 {
13103 rest = (char_u *)strstr((char *)rest, (char *)needle);
13104 if (rest == NULL || rest > haystack + end_idx)
13105 break;
13106 lastmatch = rest;
13107 }
13108 }
13109
13110 if (lastmatch == NULL)
13111 rettv->vval.v_number = -1;
13112 else
13113 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
13114}
13115
13116/*
13117 * "strtrans()" function
13118 */
13119 static void
13120f_strtrans(typval_T *argvars, typval_T *rettv)
13121{
13122 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013123 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013124}
13125
13126/*
13127 * "submatch()" function
13128 */
13129 static void
13130f_submatch(typval_T *argvars, typval_T *rettv)
13131{
13132 int error = FALSE;
13133 int no;
13134 int retList = 0;
13135
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013136 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013137 if (error)
13138 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013139 if (no < 0 || no >= NSUBEXP)
13140 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013141 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010013142 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013143 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013144 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013145 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013146 if (error)
13147 return;
13148
13149 if (retList == 0)
13150 {
13151 rettv->v_type = VAR_STRING;
13152 rettv->vval.v_string = reg_submatch(no);
13153 }
13154 else
13155 {
13156 rettv->v_type = VAR_LIST;
13157 rettv->vval.v_list = reg_submatch_list(no);
13158 }
13159}
13160
13161/*
13162 * "substitute()" function
13163 */
13164 static void
13165f_substitute(typval_T *argvars, typval_T *rettv)
13166{
13167 char_u patbuf[NUMBUFLEN];
13168 char_u subbuf[NUMBUFLEN];
13169 char_u flagsbuf[NUMBUFLEN];
13170
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013171 char_u *str = tv_get_string_chk(&argvars[0]);
13172 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013173 char_u *sub = NULL;
13174 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013175 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013176
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013177 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13178 expr = &argvars[2];
13179 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013180 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013181
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013182 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013183 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13184 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013185 rettv->vval.v_string = NULL;
13186 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013187 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013188}
13189
13190/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013191 * "swapinfo(swap_filename)" function
13192 */
13193 static void
13194f_swapinfo(typval_T *argvars, typval_T *rettv)
13195{
13196 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013197 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013198}
13199
13200/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013201 * "swapname(expr)" function
13202 */
13203 static void
13204f_swapname(typval_T *argvars, typval_T *rettv)
13205{
13206 buf_T *buf;
13207
13208 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013209 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013210 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13211 || buf->b_ml.ml_mfp->mf_fname == NULL)
13212 rettv->vval.v_string = NULL;
13213 else
13214 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13215}
13216
13217/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013218 * "synID(lnum, col, trans)" function
13219 */
13220 static void
13221f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13222{
13223 int id = 0;
13224#ifdef FEAT_SYN_HL
13225 linenr_T lnum;
13226 colnr_T col;
13227 int trans;
13228 int transerr = FALSE;
13229
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013230 lnum = tv_get_lnum(argvars); /* -1 on type error */
13231 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13232 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013233
13234 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13235 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13236 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13237#endif
13238
13239 rettv->vval.v_number = id;
13240}
13241
13242/*
13243 * "synIDattr(id, what [, mode])" function
13244 */
13245 static void
13246f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13247{
13248 char_u *p = NULL;
13249#ifdef FEAT_SYN_HL
13250 int id;
13251 char_u *what;
13252 char_u *mode;
13253 char_u modebuf[NUMBUFLEN];
13254 int modec;
13255
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013256 id = (int)tv_get_number(&argvars[0]);
13257 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013258 if (argvars[2].v_type != VAR_UNKNOWN)
13259 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013260 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013261 modec = TOLOWER_ASC(mode[0]);
13262 if (modec != 't' && modec != 'c' && modec != 'g')
13263 modec = 0; /* replace invalid with current */
13264 }
13265 else
13266 {
13267#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13268 if (USE_24BIT)
13269 modec = 'g';
13270 else
13271#endif
13272 if (t_colors > 1)
13273 modec = 'c';
13274 else
13275 modec = 't';
13276 }
13277
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013278 switch (TOLOWER_ASC(what[0]))
13279 {
13280 case 'b':
13281 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13282 p = highlight_color(id, what, modec);
13283 else /* bold */
13284 p = highlight_has_attr(id, HL_BOLD, modec);
13285 break;
13286
13287 case 'f': /* fg[#] or font */
13288 p = highlight_color(id, what, modec);
13289 break;
13290
13291 case 'i':
13292 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13293 p = highlight_has_attr(id, HL_INVERSE, modec);
13294 else /* italic */
13295 p = highlight_has_attr(id, HL_ITALIC, modec);
13296 break;
13297
13298 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013299 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013300 break;
13301
13302 case 'r': /* reverse */
13303 p = highlight_has_attr(id, HL_INVERSE, modec);
13304 break;
13305
13306 case 's':
13307 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13308 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013309 /* strikeout */
13310 else if (TOLOWER_ASC(what[1]) == 't' &&
13311 TOLOWER_ASC(what[2]) == 'r')
13312 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013313 else /* standout */
13314 p = highlight_has_attr(id, HL_STANDOUT, modec);
13315 break;
13316
13317 case 'u':
13318 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13319 /* underline */
13320 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13321 else
13322 /* undercurl */
13323 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13324 break;
13325 }
13326
13327 if (p != NULL)
13328 p = vim_strsave(p);
13329#endif
13330 rettv->v_type = VAR_STRING;
13331 rettv->vval.v_string = p;
13332}
13333
13334/*
13335 * "synIDtrans(id)" function
13336 */
13337 static void
13338f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13339{
13340 int id;
13341
13342#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013343 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013344
13345 if (id > 0)
13346 id = syn_get_final_id(id);
13347 else
13348#endif
13349 id = 0;
13350
13351 rettv->vval.v_number = id;
13352}
13353
13354/*
13355 * "synconcealed(lnum, col)" function
13356 */
13357 static void
13358f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13359{
13360#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13361 linenr_T lnum;
13362 colnr_T col;
13363 int syntax_flags = 0;
13364 int cchar;
13365 int matchid = 0;
13366 char_u str[NUMBUFLEN];
13367#endif
13368
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013369 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013370
13371#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013372 lnum = tv_get_lnum(argvars); /* -1 on type error */
13373 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013374
13375 vim_memset(str, NUL, sizeof(str));
13376
13377 if (rettv_list_alloc(rettv) != FAIL)
13378 {
13379 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13380 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13381 && curwin->w_p_cole > 0)
13382 {
13383 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13384 syntax_flags = get_syntax_info(&matchid);
13385
13386 /* get the conceal character */
13387 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13388 {
13389 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013390 if (cchar == NUL && curwin->w_p_cole == 1)
13391 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013392 if (cchar != NUL)
13393 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013394 if (has_mbyte)
13395 (*mb_char2bytes)(cchar, str);
13396 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013397 str[0] = cchar;
13398 }
13399 }
13400 }
13401
13402 list_append_number(rettv->vval.v_list,
13403 (syntax_flags & HL_CONCEAL) != 0);
13404 /* -1 to auto-determine strlen */
13405 list_append_string(rettv->vval.v_list, str, -1);
13406 list_append_number(rettv->vval.v_list, matchid);
13407 }
13408#endif
13409}
13410
13411/*
13412 * "synstack(lnum, col)" function
13413 */
13414 static void
13415f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13416{
13417#ifdef FEAT_SYN_HL
13418 linenr_T lnum;
13419 colnr_T col;
13420 int i;
13421 int id;
13422#endif
13423
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013424 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013425
13426#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013427 lnum = tv_get_lnum(argvars); /* -1 on type error */
13428 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013429
13430 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13431 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13432 && rettv_list_alloc(rettv) != FAIL)
13433 {
13434 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13435 for (i = 0; ; ++i)
13436 {
13437 id = syn_get_stack_item(i);
13438 if (id < 0)
13439 break;
13440 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13441 break;
13442 }
13443 }
13444#endif
13445}
13446
13447 static void
13448get_cmd_output_as_rettv(
13449 typval_T *argvars,
13450 typval_T *rettv,
13451 int retlist)
13452{
13453 char_u *res = NULL;
13454 char_u *p;
13455 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013456 int err = FALSE;
13457 FILE *fd;
13458 list_T *list = NULL;
13459 int flags = SHELL_SILENT;
13460
13461 rettv->v_type = VAR_STRING;
13462 rettv->vval.v_string = NULL;
13463 if (check_restricted() || check_secure())
13464 goto errret;
13465
13466 if (argvars[1].v_type != VAR_UNKNOWN)
13467 {
13468 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013469 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013470 * command.
13471 */
13472 if ((infile = vim_tempname('i', TRUE)) == NULL)
13473 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013474 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013475 goto errret;
13476 }
13477
13478 fd = mch_fopen((char *)infile, WRITEBIN);
13479 if (fd == NULL)
13480 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013481 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013482 goto errret;
13483 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013484 if (argvars[1].v_type == VAR_NUMBER)
13485 {
13486 linenr_T lnum;
13487 buf_T *buf;
13488
13489 buf = buflist_findnr(argvars[1].vval.v_number);
13490 if (buf == NULL)
13491 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013492 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013493 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013494 goto errret;
13495 }
13496
13497 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13498 {
13499 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13500 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13501 {
13502 err = TRUE;
13503 break;
13504 }
13505 if (putc(NL, fd) == EOF)
13506 {
13507 err = TRUE;
13508 break;
13509 }
13510 }
13511 }
13512 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013513 {
13514 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13515 err = TRUE;
13516 }
13517 else
13518 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013519 size_t len;
13520 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013521
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013522 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013523 if (p == NULL)
13524 {
13525 fclose(fd);
13526 goto errret; /* type error; errmsg already given */
13527 }
13528 len = STRLEN(p);
13529 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13530 err = TRUE;
13531 }
13532 if (fclose(fd) != 0)
13533 err = TRUE;
13534 if (err)
13535 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013536 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013537 goto errret;
13538 }
13539 }
13540
13541 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13542 * echoes typeahead, that messes up the display. */
13543 if (!msg_silent)
13544 flags += SHELL_COOKED;
13545
13546 if (retlist)
13547 {
13548 int len;
13549 listitem_T *li;
13550 char_u *s = NULL;
13551 char_u *start;
13552 char_u *end;
13553 int i;
13554
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013555 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013556 if (res == NULL)
13557 goto errret;
13558
13559 list = list_alloc();
13560 if (list == NULL)
13561 goto errret;
13562
13563 for (i = 0; i < len; ++i)
13564 {
13565 start = res + i;
13566 while (i < len && res[i] != NL)
13567 ++i;
13568 end = res + i;
13569
13570 s = alloc((unsigned)(end - start + 1));
13571 if (s == NULL)
13572 goto errret;
13573
13574 for (p = s; start < end; ++p, ++start)
13575 *p = *start == NUL ? NL : *start;
13576 *p = NUL;
13577
13578 li = listitem_alloc();
13579 if (li == NULL)
13580 {
13581 vim_free(s);
13582 goto errret;
13583 }
13584 li->li_tv.v_type = VAR_STRING;
13585 li->li_tv.v_lock = 0;
13586 li->li_tv.vval.v_string = s;
13587 list_append(list, li);
13588 }
13589
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013590 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013591 list = NULL;
13592 }
13593 else
13594 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013595 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010013596#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013597 /* translate <CR><NL> into <NL> */
13598 if (res != NULL)
13599 {
13600 char_u *s, *d;
13601
13602 d = res;
13603 for (s = res; *s; ++s)
13604 {
13605 if (s[0] == CAR && s[1] == NL)
13606 ++s;
13607 *d++ = *s;
13608 }
13609 *d = NUL;
13610 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013611#endif
13612 rettv->vval.v_string = res;
13613 res = NULL;
13614 }
13615
13616errret:
13617 if (infile != NULL)
13618 {
13619 mch_remove(infile);
13620 vim_free(infile);
13621 }
13622 if (res != NULL)
13623 vim_free(res);
13624 if (list != NULL)
13625 list_free(list);
13626}
13627
13628/*
13629 * "system()" function
13630 */
13631 static void
13632f_system(typval_T *argvars, typval_T *rettv)
13633{
13634 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13635}
13636
13637/*
13638 * "systemlist()" function
13639 */
13640 static void
13641f_systemlist(typval_T *argvars, typval_T *rettv)
13642{
13643 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13644}
13645
13646/*
13647 * "tabpagebuflist()" function
13648 */
13649 static void
13650f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13651{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013652 tabpage_T *tp;
13653 win_T *wp = NULL;
13654
13655 if (argvars[0].v_type == VAR_UNKNOWN)
13656 wp = firstwin;
13657 else
13658 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013659 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013660 if (tp != NULL)
13661 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13662 }
13663 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13664 {
13665 for (; wp != NULL; wp = wp->w_next)
13666 if (list_append_number(rettv->vval.v_list,
13667 wp->w_buffer->b_fnum) == FAIL)
13668 break;
13669 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013670}
13671
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013672/*
13673 * "tabpagenr()" function
13674 */
13675 static void
13676f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13677{
13678 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013679 char_u *arg;
13680
13681 if (argvars[0].v_type != VAR_UNKNOWN)
13682 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013683 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013684 nr = 0;
13685 if (arg != NULL)
13686 {
13687 if (STRCMP(arg, "$") == 0)
13688 nr = tabpage_index(NULL) - 1;
13689 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013690 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013691 }
13692 }
13693 else
13694 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013695 rettv->vval.v_number = nr;
13696}
13697
13698
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013699/*
13700 * Common code for tabpagewinnr() and winnr().
13701 */
13702 static int
13703get_winnr(tabpage_T *tp, typval_T *argvar)
13704{
13705 win_T *twin;
13706 int nr = 1;
13707 win_T *wp;
13708 char_u *arg;
13709
13710 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13711 if (argvar->v_type != VAR_UNKNOWN)
13712 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013713 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013714 if (arg == NULL)
13715 nr = 0; /* type error; errmsg already given */
13716 else if (STRCMP(arg, "$") == 0)
13717 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13718 else if (STRCMP(arg, "#") == 0)
13719 {
13720 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13721 if (twin == NULL)
13722 nr = 0;
13723 }
13724 else
13725 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013726 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013727 nr = 0;
13728 }
13729 }
13730
13731 if (nr > 0)
13732 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13733 wp != twin; wp = wp->w_next)
13734 {
13735 if (wp == NULL)
13736 {
13737 /* didn't find it in this tabpage */
13738 nr = 0;
13739 break;
13740 }
13741 ++nr;
13742 }
13743 return nr;
13744}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013745
13746/*
13747 * "tabpagewinnr()" function
13748 */
13749 static void
13750f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13751{
13752 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013753 tabpage_T *tp;
13754
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013755 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013756 if (tp == NULL)
13757 nr = 0;
13758 else
13759 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013760 rettv->vval.v_number = nr;
13761}
13762
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013763/*
13764 * "tagfiles()" function
13765 */
13766 static void
13767f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13768{
13769 char_u *fname;
13770 tagname_T tn;
13771 int first;
13772
13773 if (rettv_list_alloc(rettv) == FAIL)
13774 return;
13775 fname = alloc(MAXPATHL);
13776 if (fname == NULL)
13777 return;
13778
13779 for (first = TRUE; ; first = FALSE)
13780 if (get_tagfname(&tn, first, fname) == FAIL
13781 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13782 break;
13783 tagname_free(&tn);
13784 vim_free(fname);
13785}
13786
13787/*
13788 * "taglist()" function
13789 */
13790 static void
13791f_taglist(typval_T *argvars, typval_T *rettv)
13792{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013793 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013794 char_u *tag_pattern;
13795
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013796 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013797
13798 rettv->vval.v_number = FALSE;
13799 if (*tag_pattern == NUL)
13800 return;
13801
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013802 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013803 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013804 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013805 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013806}
13807
13808/*
13809 * "tempname()" function
13810 */
13811 static void
13812f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13813{
13814 static int x = 'A';
13815
13816 rettv->v_type = VAR_STRING;
13817 rettv->vval.v_string = vim_tempname(x, FALSE);
13818
13819 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13820 * names. Skip 'I' and 'O', they are used for shell redirection. */
13821 do
13822 {
13823 if (x == 'Z')
13824 x = '0';
13825 else if (x == '9')
13826 x = 'A';
13827 else
13828 {
13829#ifdef EBCDIC
13830 if (x == 'I')
13831 x = 'J';
13832 else if (x == 'R')
13833 x = 'S';
13834 else
13835#endif
13836 ++x;
13837 }
13838 } while (x == 'I' || x == 'O');
13839}
13840
13841#ifdef FEAT_FLOAT
13842/*
13843 * "tan()" function
13844 */
13845 static void
13846f_tan(typval_T *argvars, typval_T *rettv)
13847{
13848 float_T f = 0.0;
13849
13850 rettv->v_type = VAR_FLOAT;
13851 if (get_float_arg(argvars, &f) == OK)
13852 rettv->vval.v_float = tan(f);
13853 else
13854 rettv->vval.v_float = 0.0;
13855}
13856
13857/*
13858 * "tanh()" function
13859 */
13860 static void
13861f_tanh(typval_T *argvars, typval_T *rettv)
13862{
13863 float_T f = 0.0;
13864
13865 rettv->v_type = VAR_FLOAT;
13866 if (get_float_arg(argvars, &f) == OK)
13867 rettv->vval.v_float = tanh(f);
13868 else
13869 rettv->vval.v_float = 0.0;
13870}
13871#endif
13872
13873/*
13874 * "test_alloc_fail(id, countdown, repeat)" function
13875 */
13876 static void
13877f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13878{
13879 if (argvars[0].v_type != VAR_NUMBER
13880 || argvars[0].vval.v_number <= 0
13881 || argvars[1].v_type != VAR_NUMBER
13882 || argvars[1].vval.v_number < 0
13883 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013884 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013885 else
13886 {
13887 alloc_fail_id = argvars[0].vval.v_number;
13888 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013889 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013890 alloc_fail_countdown = argvars[1].vval.v_number;
13891 alloc_fail_repeat = argvars[2].vval.v_number;
13892 did_outofmem_msg = FALSE;
13893 }
13894}
13895
13896/*
13897 * "test_autochdir()"
13898 */
13899 static void
13900f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13901{
13902#if defined(FEAT_AUTOCHDIR)
13903 test_autochdir = TRUE;
13904#endif
13905}
13906
13907/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013908 * "test_feedinput()"
13909 */
13910 static void
13911f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13912{
13913#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013914 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013915
13916 if (val != NULL)
13917 {
13918 trash_input_buf();
13919 add_to_input_buf_csi(val, (int)STRLEN(val));
13920 }
13921#endif
13922}
13923
13924/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013925 * "test_option_not_set({name})" function
13926 */
13927 static void
13928f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13929{
13930 char_u *name = (char_u *)"";
13931
13932 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013933 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013934 else
13935 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013936 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013937 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013938 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013939 }
13940}
13941
13942/*
13943 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013944 */
13945 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013946f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013947{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013948 char_u *name = (char_u *)"";
13949 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013950 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013951
13952 if (argvars[0].v_type != VAR_STRING
13953 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013954 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013955 else
13956 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013957 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013958 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013959
13960 if (STRCMP(name, (char_u *)"redraw") == 0)
13961 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013962 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13963 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013964 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13965 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013966 else if (STRCMP(name, (char_u *)"starting") == 0)
13967 {
13968 if (val)
13969 {
13970 if (save_starting < 0)
13971 save_starting = starting;
13972 starting = 0;
13973 }
13974 else
13975 {
13976 starting = save_starting;
13977 save_starting = -1;
13978 }
13979 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013980 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13981 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013982 else if (STRCMP(name, (char_u *)"ALL") == 0)
13983 {
13984 disable_char_avail_for_testing = FALSE;
13985 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013986 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013987 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013988 if (save_starting >= 0)
13989 {
13990 starting = save_starting;
13991 save_starting = -1;
13992 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013993 }
13994 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013995 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013996 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013997}
13998
13999/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010014000 * "test_refcount({expr})" function
14001 */
14002 static void
14003f_test_refcount(typval_T *argvars, typval_T *rettv)
14004{
14005 int retval = -1;
14006
14007 switch (argvars[0].v_type)
14008 {
14009 case VAR_UNKNOWN:
14010 case VAR_NUMBER:
14011 case VAR_FLOAT:
14012 case VAR_SPECIAL:
14013 case VAR_STRING:
14014 break;
14015 case VAR_JOB:
14016#ifdef FEAT_JOB_CHANNEL
14017 if (argvars[0].vval.v_job != NULL)
14018 retval = argvars[0].vval.v_job->jv_refcount - 1;
14019#endif
14020 break;
14021 case VAR_CHANNEL:
14022#ifdef FEAT_JOB_CHANNEL
14023 if (argvars[0].vval.v_channel != NULL)
14024 retval = argvars[0].vval.v_channel->ch_refcount - 1;
14025#endif
14026 break;
14027 case VAR_FUNC:
14028 if (argvars[0].vval.v_string != NULL)
14029 {
14030 ufunc_T *fp;
14031
14032 fp = find_func(argvars[0].vval.v_string);
14033 if (fp != NULL)
14034 retval = fp->uf_refcount;
14035 }
14036 break;
14037 case VAR_PARTIAL:
14038 if (argvars[0].vval.v_partial != NULL)
14039 retval = argvars[0].vval.v_partial->pt_refcount - 1;
14040 break;
14041 case VAR_BLOB:
14042 if (argvars[0].vval.v_blob != NULL)
14043 retval = argvars[0].vval.v_blob->bv_refcount - 1;
14044 break;
14045 case VAR_LIST:
14046 if (argvars[0].vval.v_list != NULL)
14047 retval = argvars[0].vval.v_list->lv_refcount - 1;
14048 break;
14049 case VAR_DICT:
14050 if (argvars[0].vval.v_dict != NULL)
14051 retval = argvars[0].vval.v_dict->dv_refcount - 1;
14052 break;
14053 }
14054
14055 rettv->v_type = VAR_NUMBER;
14056 rettv->vval.v_number = retval;
14057
14058}
14059
14060/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014061 * "test_garbagecollect_now()" function
14062 */
14063 static void
14064f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14065{
14066 /* This is dangerous, any Lists and Dicts used internally may be freed
14067 * while still in use. */
14068 garbage_collect(TRUE);
14069}
14070
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014071/*
14072 * "test_ignore_error()" function
14073 */
14074 static void
14075f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
14076{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014077 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014078}
14079
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010014080 static void
14081f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
14082{
14083 rettv->v_type = VAR_BLOB;
14084 rettv->vval.v_blob = NULL;
14085}
14086
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014087#ifdef FEAT_JOB_CHANNEL
14088 static void
14089f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
14090{
14091 rettv->v_type = VAR_CHANNEL;
14092 rettv->vval.v_channel = NULL;
14093}
14094#endif
14095
14096 static void
14097f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
14098{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014099 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014100}
14101
14102#ifdef FEAT_JOB_CHANNEL
14103 static void
14104f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
14105{
14106 rettv->v_type = VAR_JOB;
14107 rettv->vval.v_job = NULL;
14108}
14109#endif
14110
14111 static void
14112f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
14113{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014114 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014115}
14116
14117 static void
14118f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
14119{
14120 rettv->v_type = VAR_PARTIAL;
14121 rettv->vval.v_partial = NULL;
14122}
14123
14124 static void
14125f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
14126{
14127 rettv->v_type = VAR_STRING;
14128 rettv->vval.v_string = NULL;
14129}
14130
Bram Moolenaarab186732018-09-14 21:27:06 +020014131#ifdef FEAT_GUI
14132 static void
14133f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
14134{
14135 char_u *which;
14136 long value;
14137 int dragging;
14138 scrollbar_T *sb = NULL;
14139
14140 if (argvars[0].v_type != VAR_STRING
14141 || (argvars[1].v_type) != VAR_NUMBER
14142 || (argvars[2].v_type) != VAR_NUMBER)
14143 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014144 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020014145 return;
14146 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014147 which = tv_get_string(&argvars[0]);
14148 value = tv_get_number(&argvars[1]);
14149 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020014150
14151 if (STRCMP(which, "left") == 0)
14152 sb = &curwin->w_scrollbars[SBAR_LEFT];
14153 else if (STRCMP(which, "right") == 0)
14154 sb = &curwin->w_scrollbars[SBAR_RIGHT];
14155 else if (STRCMP(which, "hor") == 0)
14156 sb = &gui.bottom_sbar;
14157 if (sb == NULL)
14158 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014159 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020014160 return;
14161 }
14162 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020014163# ifndef USE_ON_FLY_SCROLL
14164 // need to loop through normal_cmd() to handle the scroll events
14165 exec_normal(FALSE, TRUE, FALSE);
14166# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020014167}
14168#endif
14169
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014170 static void
14171f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14172{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014173 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014174}
14175
14176#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14177/*
14178 * Get a callback from "arg". It can be a Funcref or a function name.
14179 * When "arg" is zero return an empty string.
14180 * Return NULL for an invalid argument.
14181 */
14182 char_u *
14183get_callback(typval_T *arg, partial_T **pp)
14184{
14185 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14186 {
14187 *pp = arg->vval.v_partial;
14188 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014189 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014190 }
14191 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014192 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014193 {
14194 func_ref(arg->vval.v_string);
14195 return arg->vval.v_string;
14196 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014197 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14198 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014199 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014200 return NULL;
14201}
14202
14203/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020014204 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014205 */
14206 void
14207free_callback(char_u *callback, partial_T *partial)
14208{
14209 if (partial != NULL)
14210 partial_unref(partial);
14211 else if (callback != NULL)
14212 {
14213 func_unref(callback);
14214 vim_free(callback);
14215 }
14216}
14217#endif
14218
14219#ifdef FEAT_TIMERS
14220/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014221 * "timer_info([timer])" function
14222 */
14223 static void
14224f_timer_info(typval_T *argvars, typval_T *rettv)
14225{
14226 timer_T *timer = NULL;
14227
14228 if (rettv_list_alloc(rettv) != OK)
14229 return;
14230 if (argvars[0].v_type != VAR_UNKNOWN)
14231 {
14232 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014233 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014234 else
14235 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014236 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014237 if (timer != NULL)
14238 add_timer_info(rettv, timer);
14239 }
14240 }
14241 else
14242 add_timer_info_all(rettv);
14243}
14244
14245/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014246 * "timer_pause(timer, paused)" function
14247 */
14248 static void
14249f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14250{
14251 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014252 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014253
14254 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014255 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014256 else
14257 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014258 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014259 if (timer != NULL)
14260 timer->tr_paused = paused;
14261 }
14262}
14263
14264/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014265 * "timer_start(time, callback [, options])" function
14266 */
14267 static void
14268f_timer_start(typval_T *argvars, typval_T *rettv)
14269{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014270 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014271 timer_T *timer;
14272 int repeat = 0;
14273 char_u *callback;
14274 dict_T *dict;
14275 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014276
Bram Moolenaar75537a92016-09-05 22:45:28 +020014277 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014278 if (check_secure())
14279 return;
14280 if (argvars[2].v_type != VAR_UNKNOWN)
14281 {
14282 if (argvars[2].v_type != VAR_DICT
14283 || (dict = argvars[2].vval.v_dict) == NULL)
14284 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014285 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014286 return;
14287 }
14288 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014289 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014290 }
14291
Bram Moolenaar75537a92016-09-05 22:45:28 +020014292 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014293 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014294 return;
14295
14296 timer = create_timer(msec, repeat);
14297 if (timer == NULL)
14298 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014299 else
14300 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014301 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014302 timer->tr_callback = vim_strsave(callback);
14303 else
14304 /* pointer into the partial */
14305 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014306 timer->tr_partial = partial;
14307 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014308 }
14309}
14310
14311/*
14312 * "timer_stop(timer)" function
14313 */
14314 static void
14315f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14316{
14317 timer_T *timer;
14318
14319 if (argvars[0].v_type != VAR_NUMBER)
14320 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014321 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014322 return;
14323 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014324 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014325 if (timer != NULL)
14326 stop_timer(timer);
14327}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014328
14329/*
14330 * "timer_stopall()" function
14331 */
14332 static void
14333f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14334{
14335 stop_all_timers();
14336}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014337#endif
14338
14339/*
14340 * "tolower(string)" function
14341 */
14342 static void
14343f_tolower(typval_T *argvars, typval_T *rettv)
14344{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014345 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014346 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014347}
14348
14349/*
14350 * "toupper(string)" function
14351 */
14352 static void
14353f_toupper(typval_T *argvars, typval_T *rettv)
14354{
14355 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014356 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014357}
14358
14359/*
14360 * "tr(string, fromstr, tostr)" function
14361 */
14362 static void
14363f_tr(typval_T *argvars, typval_T *rettv)
14364{
14365 char_u *in_str;
14366 char_u *fromstr;
14367 char_u *tostr;
14368 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014369 int inlen;
14370 int fromlen;
14371 int tolen;
14372 int idx;
14373 char_u *cpstr;
14374 int cplen;
14375 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014376 char_u buf[NUMBUFLEN];
14377 char_u buf2[NUMBUFLEN];
14378 garray_T ga;
14379
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014380 in_str = tv_get_string(&argvars[0]);
14381 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14382 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014383
14384 /* Default return value: empty string. */
14385 rettv->v_type = VAR_STRING;
14386 rettv->vval.v_string = NULL;
14387 if (fromstr == NULL || tostr == NULL)
14388 return; /* type error; errmsg already given */
14389 ga_init2(&ga, (int)sizeof(char), 80);
14390
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014391 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014392 /* not multi-byte: fromstr and tostr must be the same length */
14393 if (STRLEN(fromstr) != STRLEN(tostr))
14394 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014395error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014396 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014397 ga_clear(&ga);
14398 return;
14399 }
14400
14401 /* fromstr and tostr have to contain the same number of chars */
14402 while (*in_str != NUL)
14403 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014404 if (has_mbyte)
14405 {
14406 inlen = (*mb_ptr2len)(in_str);
14407 cpstr = in_str;
14408 cplen = inlen;
14409 idx = 0;
14410 for (p = fromstr; *p != NUL; p += fromlen)
14411 {
14412 fromlen = (*mb_ptr2len)(p);
14413 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14414 {
14415 for (p = tostr; *p != NUL; p += tolen)
14416 {
14417 tolen = (*mb_ptr2len)(p);
14418 if (idx-- == 0)
14419 {
14420 cplen = tolen;
14421 cpstr = p;
14422 break;
14423 }
14424 }
14425 if (*p == NUL) /* tostr is shorter than fromstr */
14426 goto error;
14427 break;
14428 }
14429 ++idx;
14430 }
14431
14432 if (first && cpstr == in_str)
14433 {
14434 /* Check that fromstr and tostr have the same number of
14435 * (multi-byte) characters. Done only once when a character
14436 * of in_str doesn't appear in fromstr. */
14437 first = FALSE;
14438 for (p = tostr; *p != NUL; p += tolen)
14439 {
14440 tolen = (*mb_ptr2len)(p);
14441 --idx;
14442 }
14443 if (idx != 0)
14444 goto error;
14445 }
14446
14447 (void)ga_grow(&ga, cplen);
14448 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14449 ga.ga_len += cplen;
14450
14451 in_str += inlen;
14452 }
14453 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014454 {
14455 /* When not using multi-byte chars we can do it faster. */
14456 p = vim_strchr(fromstr, *in_str);
14457 if (p != NULL)
14458 ga_append(&ga, tostr[p - fromstr]);
14459 else
14460 ga_append(&ga, *in_str);
14461 ++in_str;
14462 }
14463 }
14464
14465 /* add a terminating NUL */
14466 (void)ga_grow(&ga, 1);
14467 ga_append(&ga, NUL);
14468
14469 rettv->vval.v_string = ga.ga_data;
14470}
14471
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014472/*
14473 * "trim({expr})" function
14474 */
14475 static void
14476f_trim(typval_T *argvars, typval_T *rettv)
14477{
14478 char_u buf1[NUMBUFLEN];
14479 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014480 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014481 char_u *mask = NULL;
14482 char_u *tail;
14483 char_u *prev;
14484 char_u *p;
14485 int c1;
14486
14487 rettv->v_type = VAR_STRING;
14488 if (head == NULL)
14489 {
14490 rettv->vval.v_string = NULL;
14491 return;
14492 }
14493
14494 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014495 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014496
14497 while (*head != NUL)
14498 {
14499 c1 = PTR2CHAR(head);
14500 if (mask == NULL)
14501 {
14502 if (c1 > ' ' && c1 != 0xa0)
14503 break;
14504 }
14505 else
14506 {
14507 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14508 if (c1 == PTR2CHAR(p))
14509 break;
14510 if (*p == NUL)
14511 break;
14512 }
14513 MB_PTR_ADV(head);
14514 }
14515
14516 for (tail = head + STRLEN(head); tail > head; tail = prev)
14517 {
14518 prev = tail;
14519 MB_PTR_BACK(head, prev);
14520 c1 = PTR2CHAR(prev);
14521 if (mask == NULL)
14522 {
14523 if (c1 > ' ' && c1 != 0xa0)
14524 break;
14525 }
14526 else
14527 {
14528 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14529 if (c1 == PTR2CHAR(p))
14530 break;
14531 if (*p == NUL)
14532 break;
14533 }
14534 }
14535 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14536}
14537
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014538#ifdef FEAT_FLOAT
14539/*
14540 * "trunc({float})" function
14541 */
14542 static void
14543f_trunc(typval_T *argvars, typval_T *rettv)
14544{
14545 float_T f = 0.0;
14546
14547 rettv->v_type = VAR_FLOAT;
14548 if (get_float_arg(argvars, &f) == OK)
14549 /* trunc() is not in C90, use floor() or ceil() instead. */
14550 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14551 else
14552 rettv->vval.v_float = 0.0;
14553}
14554#endif
14555
14556/*
14557 * "type(expr)" function
14558 */
14559 static void
14560f_type(typval_T *argvars, typval_T *rettv)
14561{
14562 int n = -1;
14563
14564 switch (argvars[0].v_type)
14565 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014566 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14567 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014568 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014569 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14570 case VAR_LIST: n = VAR_TYPE_LIST; break;
14571 case VAR_DICT: n = VAR_TYPE_DICT; break;
14572 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014573 case VAR_SPECIAL:
14574 if (argvars[0].vval.v_number == VVAL_FALSE
14575 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014576 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014577 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014578 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014579 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014580 case VAR_JOB: n = VAR_TYPE_JOB; break;
14581 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014582 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014583 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014584 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014585 n = -1;
14586 break;
14587 }
14588 rettv->vval.v_number = n;
14589}
14590
14591/*
14592 * "undofile(name)" function
14593 */
14594 static void
14595f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14596{
14597 rettv->v_type = VAR_STRING;
14598#ifdef FEAT_PERSISTENT_UNDO
14599 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014600 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014601
14602 if (*fname == NUL)
14603 {
14604 /* If there is no file name there will be no undo file. */
14605 rettv->vval.v_string = NULL;
14606 }
14607 else
14608 {
14609 char_u *ffname = FullName_save(fname, FALSE);
14610
14611 if (ffname != NULL)
14612 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14613 vim_free(ffname);
14614 }
14615 }
14616#else
14617 rettv->vval.v_string = NULL;
14618#endif
14619}
14620
14621/*
14622 * "undotree()" function
14623 */
14624 static void
14625f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14626{
14627 if (rettv_dict_alloc(rettv) == OK)
14628 {
14629 dict_T *dict = rettv->vval.v_dict;
14630 list_T *list;
14631
Bram Moolenaare0be1672018-07-08 16:50:37 +020014632 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14633 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14634 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14635 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14636 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14637 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014638
14639 list = list_alloc();
14640 if (list != NULL)
14641 {
14642 u_eval_tree(curbuf->b_u_oldhead, list);
14643 dict_add_list(dict, "entries", list);
14644 }
14645 }
14646}
14647
14648/*
14649 * "values(dict)" function
14650 */
14651 static void
14652f_values(typval_T *argvars, typval_T *rettv)
14653{
14654 dict_list(argvars, rettv, 1);
14655}
14656
14657/*
14658 * "virtcol(string)" function
14659 */
14660 static void
14661f_virtcol(typval_T *argvars, typval_T *rettv)
14662{
14663 colnr_T vcol = 0;
14664 pos_T *fp;
14665 int fnum = curbuf->b_fnum;
14666
14667 fp = var2fpos(&argvars[0], FALSE, &fnum);
14668 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14669 && fnum == curbuf->b_fnum)
14670 {
14671 getvvcol(curwin, fp, NULL, NULL, &vcol);
14672 ++vcol;
14673 }
14674
14675 rettv->vval.v_number = vcol;
14676}
14677
14678/*
14679 * "visualmode()" function
14680 */
14681 static void
14682f_visualmode(typval_T *argvars, typval_T *rettv)
14683{
14684 char_u str[2];
14685
14686 rettv->v_type = VAR_STRING;
14687 str[0] = curbuf->b_visual_mode_eval;
14688 str[1] = NUL;
14689 rettv->vval.v_string = vim_strsave(str);
14690
14691 /* A non-zero number or non-empty string argument: reset mode. */
14692 if (non_zero_arg(&argvars[0]))
14693 curbuf->b_visual_mode_eval = NUL;
14694}
14695
14696/*
14697 * "wildmenumode()" function
14698 */
14699 static void
14700f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14701{
14702#ifdef FEAT_WILDMENU
14703 if (wild_menu_showing)
14704 rettv->vval.v_number = 1;
14705#endif
14706}
14707
14708/*
14709 * "winbufnr(nr)" function
14710 */
14711 static void
14712f_winbufnr(typval_T *argvars, typval_T *rettv)
14713{
14714 win_T *wp;
14715
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014716 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014717 if (wp == NULL)
14718 rettv->vval.v_number = -1;
14719 else
14720 rettv->vval.v_number = wp->w_buffer->b_fnum;
14721}
14722
14723/*
14724 * "wincol()" function
14725 */
14726 static void
14727f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14728{
14729 validate_cursor();
14730 rettv->vval.v_number = curwin->w_wcol + 1;
14731}
14732
14733/*
14734 * "winheight(nr)" function
14735 */
14736 static void
14737f_winheight(typval_T *argvars, typval_T *rettv)
14738{
14739 win_T *wp;
14740
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014741 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014742 if (wp == NULL)
14743 rettv->vval.v_number = -1;
14744 else
14745 rettv->vval.v_number = wp->w_height;
14746}
14747
14748/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014749 * "winlayout()" function
14750 */
14751 static void
14752f_winlayout(typval_T *argvars, typval_T *rettv)
14753{
14754 tabpage_T *tp;
14755
14756 if (rettv_list_alloc(rettv) != OK)
14757 return;
14758
14759 if (argvars[0].v_type == VAR_UNKNOWN)
14760 tp = curtab;
14761 else
14762 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014763 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014764 if (tp == NULL)
14765 return;
14766 }
14767
14768 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14769}
14770
14771/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014772 * "winline()" function
14773 */
14774 static void
14775f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14776{
14777 validate_cursor();
14778 rettv->vval.v_number = curwin->w_wrow + 1;
14779}
14780
14781/*
14782 * "winnr()" function
14783 */
14784 static void
14785f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14786{
14787 int nr = 1;
14788
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014789 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014790 rettv->vval.v_number = nr;
14791}
14792
14793/*
14794 * "winrestcmd()" function
14795 */
14796 static void
14797f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14798{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014799 win_T *wp;
14800 int winnr = 1;
14801 garray_T ga;
14802 char_u buf[50];
14803
14804 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014805 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014806 {
14807 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14808 ga_concat(&ga, buf);
14809 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14810 ga_concat(&ga, buf);
14811 ++winnr;
14812 }
14813 ga_append(&ga, NUL);
14814
14815 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014816 rettv->v_type = VAR_STRING;
14817}
14818
14819/*
14820 * "winrestview()" function
14821 */
14822 static void
14823f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14824{
14825 dict_T *dict;
14826
14827 if (argvars[0].v_type != VAR_DICT
14828 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014829 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014830 else
14831 {
14832 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014833 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014834 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014835 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014836 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014837 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014838 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14839 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014840 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014841 curwin->w_set_curswant = FALSE;
14842 }
14843
14844 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014845 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014846#ifdef FEAT_DIFF
14847 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014848 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014849#endif
14850 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014851 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014852 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014853 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014854
14855 check_cursor();
14856 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014857 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014858 changed_window_setting();
14859
14860 if (curwin->w_topline <= 0)
14861 curwin->w_topline = 1;
14862 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14863 curwin->w_topline = curbuf->b_ml.ml_line_count;
14864#ifdef FEAT_DIFF
14865 check_topfill(curwin, TRUE);
14866#endif
14867 }
14868}
14869
14870/*
14871 * "winsaveview()" function
14872 */
14873 static void
14874f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14875{
14876 dict_T *dict;
14877
14878 if (rettv_dict_alloc(rettv) == FAIL)
14879 return;
14880 dict = rettv->vval.v_dict;
14881
Bram Moolenaare0be1672018-07-08 16:50:37 +020014882 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14883 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020014884 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014885 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014886 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014887
Bram Moolenaare0be1672018-07-08 16:50:37 +020014888 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014889#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014890 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014891#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014892 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14893 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014894}
14895
14896/*
14897 * "winwidth(nr)" function
14898 */
14899 static void
14900f_winwidth(typval_T *argvars, typval_T *rettv)
14901{
14902 win_T *wp;
14903
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014904 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014905 if (wp == NULL)
14906 rettv->vval.v_number = -1;
14907 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014908 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014909}
14910
14911/*
14912 * "wordcount()" function
14913 */
14914 static void
14915f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14916{
14917 if (rettv_dict_alloc(rettv) == FAIL)
14918 return;
14919 cursor_pos_info(rettv->vval.v_dict);
14920}
14921
14922/*
14923 * "writefile()" function
14924 */
14925 static void
14926f_writefile(typval_T *argvars, typval_T *rettv)
14927{
14928 int binary = FALSE;
14929 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014930#ifdef HAVE_FSYNC
14931 int do_fsync = p_fs;
14932#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014933 char_u *fname;
14934 FILE *fd;
14935 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014936 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014937 list_T *list = NULL;
14938 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014939
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014940 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010014941 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014942 return;
14943
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014944 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014945 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014946 list = argvars[0].vval.v_list;
14947 if (list == NULL)
14948 return;
14949 for (li = list->lv_first; li != NULL; li = li->li_next)
14950 if (tv_get_string_chk(&li->li_tv) == NULL)
14951 return;
14952 }
14953 else if (argvars[0].v_type == VAR_BLOB)
14954 {
14955 blob = argvars[0].vval.v_blob;
14956 if (blob == NULL)
14957 return;
14958 }
14959 else
14960 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014961 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014962 return;
14963 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014964
14965 if (argvars[2].v_type != VAR_UNKNOWN)
14966 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014967 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014968
14969 if (arg2 == NULL)
14970 return;
14971 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014972 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014973 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014974 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014975#ifdef HAVE_FSYNC
14976 if (vim_strchr(arg2, 's') != NULL)
14977 do_fsync = TRUE;
14978 else if (vim_strchr(arg2, 'S') != NULL)
14979 do_fsync = FALSE;
14980#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014981 }
14982
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014983 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014984 if (fname == NULL)
14985 return;
14986
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014987 /* Always open the file in binary mode, library functions have a mind of
14988 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014989 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14990 append ? APPENDBIN : WRITEBIN)) == NULL)
14991 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014992 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014993 ret = -1;
14994 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014995 else if (blob)
14996 {
14997 if (write_blob(fd, blob) == FAIL)
14998 ret = -1;
14999#ifdef HAVE_FSYNC
15000 else if (do_fsync)
15001 // Ignore the error, the user wouldn't know what to do about it.
15002 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010015003 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015004#endif
15005 fclose(fd);
15006 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015007 else
15008 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015009 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015010 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015011#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010015012 else if (do_fsync)
15013 /* Ignore the error, the user wouldn't know what to do about it.
15014 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010015015 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015016#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015017 fclose(fd);
15018 }
15019
15020 rettv->vval.v_number = ret;
15021}
15022
15023/*
15024 * "xor(expr, expr)" function
15025 */
15026 static void
15027f_xor(typval_T *argvars, typval_T *rettv)
15028{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015029 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
15030 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015031}
15032
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015033#endif /* FEAT_EVAL */