blob: 4a54d6dc9de74f1ff52abc27bc31543d55c42e4f [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)
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200240static void f_isinf(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200241static void f_isnan(typval_T *argvars, typval_T *rettv);
242#endif
243static void f_items(typval_T *argvars, typval_T *rettv);
244#ifdef FEAT_JOB_CHANNEL
245static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
246static void f_job_info(typval_T *argvars, typval_T *rettv);
247static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
248static void f_job_start(typval_T *argvars, typval_T *rettv);
249static void f_job_stop(typval_T *argvars, typval_T *rettv);
250static void f_job_status(typval_T *argvars, typval_T *rettv);
251#endif
252static void f_join(typval_T *argvars, typval_T *rettv);
253static void f_js_decode(typval_T *argvars, typval_T *rettv);
254static void f_js_encode(typval_T *argvars, typval_T *rettv);
255static void f_json_decode(typval_T *argvars, typval_T *rettv);
256static void f_json_encode(typval_T *argvars, typval_T *rettv);
257static void f_keys(typval_T *argvars, typval_T *rettv);
258static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
259static void f_len(typval_T *argvars, typval_T *rettv);
260static void f_libcall(typval_T *argvars, typval_T *rettv);
261static void f_libcallnr(typval_T *argvars, typval_T *rettv);
262static void f_line(typval_T *argvars, typval_T *rettv);
263static void f_line2byte(typval_T *argvars, typval_T *rettv);
264static void f_lispindent(typval_T *argvars, typval_T *rettv);
265static void f_localtime(typval_T *argvars, typval_T *rettv);
266#ifdef FEAT_FLOAT
267static void f_log(typval_T *argvars, typval_T *rettv);
268static void f_log10(typval_T *argvars, typval_T *rettv);
269#endif
270#ifdef FEAT_LUA
271static void f_luaeval(typval_T *argvars, typval_T *rettv);
272#endif
273static void f_map(typval_T *argvars, typval_T *rettv);
274static void f_maparg(typval_T *argvars, typval_T *rettv);
275static void f_mapcheck(typval_T *argvars, typval_T *rettv);
276static void f_match(typval_T *argvars, typval_T *rettv);
277static void f_matchadd(typval_T *argvars, typval_T *rettv);
278static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
279static void f_matcharg(typval_T *argvars, typval_T *rettv);
280static void f_matchdelete(typval_T *argvars, typval_T *rettv);
281static void f_matchend(typval_T *argvars, typval_T *rettv);
282static void f_matchlist(typval_T *argvars, typval_T *rettv);
283static void f_matchstr(typval_T *argvars, typval_T *rettv);
284static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
285static void f_max(typval_T *argvars, typval_T *rettv);
286static void f_min(typval_T *argvars, typval_T *rettv);
287#ifdef vim_mkdir
288static void f_mkdir(typval_T *argvars, typval_T *rettv);
289#endif
290static void f_mode(typval_T *argvars, typval_T *rettv);
291#ifdef FEAT_MZSCHEME
292static void f_mzeval(typval_T *argvars, typval_T *rettv);
293#endif
294static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
295static void f_nr2char(typval_T *argvars, typval_T *rettv);
296static void f_or(typval_T *argvars, typval_T *rettv);
297static void f_pathshorten(typval_T *argvars, typval_T *rettv);
298#ifdef FEAT_PERL
299static void f_perleval(typval_T *argvars, typval_T *rettv);
300#endif
301#ifdef FEAT_FLOAT
302static void f_pow(typval_T *argvars, typval_T *rettv);
303#endif
304static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
305static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200306#ifdef FEAT_JOB_CHANNEL
307static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200308static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200309static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
310#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200311static void f_pumvisible(typval_T *argvars, typval_T *rettv);
312#ifdef FEAT_PYTHON3
313static void f_py3eval(typval_T *argvars, typval_T *rettv);
314#endif
315#ifdef FEAT_PYTHON
316static void f_pyeval(typval_T *argvars, typval_T *rettv);
317#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100318#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
319static void f_pyxeval(typval_T *argvars, typval_T *rettv);
320#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200321static void f_range(typval_T *argvars, typval_T *rettv);
322static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200323static void f_reg_executing(typval_T *argvars, typval_T *rettv);
324static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200325static void f_reltime(typval_T *argvars, typval_T *rettv);
326#ifdef FEAT_FLOAT
327static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
328#endif
329static void f_reltimestr(typval_T *argvars, typval_T *rettv);
330static void f_remote_expr(typval_T *argvars, typval_T *rettv);
331static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
332static void f_remote_peek(typval_T *argvars, typval_T *rettv);
333static void f_remote_read(typval_T *argvars, typval_T *rettv);
334static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100335static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200336static void f_remove(typval_T *argvars, typval_T *rettv);
337static void f_rename(typval_T *argvars, typval_T *rettv);
338static void f_repeat(typval_T *argvars, typval_T *rettv);
339static void f_resolve(typval_T *argvars, typval_T *rettv);
340static void f_reverse(typval_T *argvars, typval_T *rettv);
341#ifdef FEAT_FLOAT
342static void f_round(typval_T *argvars, typval_T *rettv);
343#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100344#ifdef FEAT_RUBY
345static void f_rubyeval(typval_T *argvars, typval_T *rettv);
346#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200347static void f_screenattr(typval_T *argvars, typval_T *rettv);
348static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100349static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200350static void f_screencol(typval_T *argvars, typval_T *rettv);
351static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100352static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200353static void f_search(typval_T *argvars, typval_T *rettv);
354static void f_searchdecl(typval_T *argvars, typval_T *rettv);
355static void f_searchpair(typval_T *argvars, typval_T *rettv);
356static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
357static void f_searchpos(typval_T *argvars, typval_T *rettv);
358static void f_server2client(typval_T *argvars, typval_T *rettv);
359static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200360static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200361static void f_setbufvar(typval_T *argvars, typval_T *rettv);
362static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
363static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
364static void f_setfperm(typval_T *argvars, typval_T *rettv);
365static void f_setline(typval_T *argvars, typval_T *rettv);
366static void f_setloclist(typval_T *argvars, typval_T *rettv);
367static void f_setmatches(typval_T *argvars, typval_T *rettv);
368static void f_setpos(typval_T *argvars, typval_T *rettv);
369static void f_setqflist(typval_T *argvars, typval_T *rettv);
370static void f_setreg(typval_T *argvars, typval_T *rettv);
371static void f_settabvar(typval_T *argvars, typval_T *rettv);
372static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100373static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200374static void f_setwinvar(typval_T *argvars, typval_T *rettv);
375#ifdef FEAT_CRYPT
376static void f_sha256(typval_T *argvars, typval_T *rettv);
377#endif /* FEAT_CRYPT */
378static void f_shellescape(typval_T *argvars, typval_T *rettv);
379static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100380#ifdef FEAT_SIGNS
381static void f_sign_define(typval_T *argvars, typval_T *rettv);
382static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
383static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100384static void f_sign_jump(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100385static void f_sign_place(typval_T *argvars, typval_T *rettv);
386static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
387static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
388#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200389static void f_simplify(typval_T *argvars, typval_T *rettv);
390#ifdef FEAT_FLOAT
391static void f_sin(typval_T *argvars, typval_T *rettv);
392static void f_sinh(typval_T *argvars, typval_T *rettv);
393#endif
394static void f_sort(typval_T *argvars, typval_T *rettv);
395static void f_soundfold(typval_T *argvars, typval_T *rettv);
396static void f_spellbadword(typval_T *argvars, typval_T *rettv);
397static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
398static void f_split(typval_T *argvars, typval_T *rettv);
399#ifdef FEAT_FLOAT
400static void f_sqrt(typval_T *argvars, typval_T *rettv);
401static void f_str2float(typval_T *argvars, typval_T *rettv);
402#endif
403static void f_str2nr(typval_T *argvars, typval_T *rettv);
404static void f_strchars(typval_T *argvars, typval_T *rettv);
405#ifdef HAVE_STRFTIME
406static void f_strftime(typval_T *argvars, typval_T *rettv);
407#endif
408static void f_strgetchar(typval_T *argvars, typval_T *rettv);
409static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200410static void f_strlen(typval_T *argvars, typval_T *rettv);
411static void f_strcharpart(typval_T *argvars, typval_T *rettv);
412static void f_strpart(typval_T *argvars, typval_T *rettv);
413static void f_strridx(typval_T *argvars, typval_T *rettv);
414static void f_strtrans(typval_T *argvars, typval_T *rettv);
415static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
416static void f_strwidth(typval_T *argvars, typval_T *rettv);
417static void f_submatch(typval_T *argvars, typval_T *rettv);
418static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200419static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200420static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200421static void f_synID(typval_T *argvars, typval_T *rettv);
422static void f_synIDattr(typval_T *argvars, typval_T *rettv);
423static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
424static void f_synstack(typval_T *argvars, typval_T *rettv);
425static void f_synconcealed(typval_T *argvars, typval_T *rettv);
426static void f_system(typval_T *argvars, typval_T *rettv);
427static void f_systemlist(typval_T *argvars, typval_T *rettv);
428static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
429static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
430static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
431static void f_taglist(typval_T *argvars, typval_T *rettv);
432static void f_tagfiles(typval_T *argvars, typval_T *rettv);
433static void f_tempname(typval_T *argvars, typval_T *rettv);
434static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
435static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200436static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200437static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100438static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100439static void f_test_refcount(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200440static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100441static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100442static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200443#ifdef FEAT_JOB_CHANNEL
444static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
445#endif
446static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
447#ifdef FEAT_JOB_CHANNEL
448static void f_test_null_job(typval_T *argvars, typval_T *rettv);
449#endif
450static void f_test_null_list(typval_T *argvars, typval_T *rettv);
451static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
452static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200453#ifdef FEAT_GUI
454static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
455#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200456static void f_test_settime(typval_T *argvars, typval_T *rettv);
457#ifdef FEAT_FLOAT
458static void f_tan(typval_T *argvars, typval_T *rettv);
459static void f_tanh(typval_T *argvars, typval_T *rettv);
460#endif
461#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200462static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200463static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200464static void f_timer_start(typval_T *argvars, typval_T *rettv);
465static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200466static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200467#endif
468static void f_tolower(typval_T *argvars, typval_T *rettv);
469static void f_toupper(typval_T *argvars, typval_T *rettv);
470static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100471static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200472#ifdef FEAT_FLOAT
473static void f_trunc(typval_T *argvars, typval_T *rettv);
474#endif
475static void f_type(typval_T *argvars, typval_T *rettv);
476static void f_undofile(typval_T *argvars, typval_T *rettv);
477static void f_undotree(typval_T *argvars, typval_T *rettv);
478static void f_uniq(typval_T *argvars, typval_T *rettv);
479static void f_values(typval_T *argvars, typval_T *rettv);
480static void f_virtcol(typval_T *argvars, typval_T *rettv);
481static void f_visualmode(typval_T *argvars, typval_T *rettv);
482static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
483static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
484static void f_win_getid(typval_T *argvars, typval_T *rettv);
485static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
486static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
487static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100488static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200489static void f_winbufnr(typval_T *argvars, typval_T *rettv);
490static void f_wincol(typval_T *argvars, typval_T *rettv);
491static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200492static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200493static void f_winline(typval_T *argvars, typval_T *rettv);
494static void f_winnr(typval_T *argvars, typval_T *rettv);
495static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
496static void f_winrestview(typval_T *argvars, typval_T *rettv);
497static void f_winsaveview(typval_T *argvars, typval_T *rettv);
498static void f_winwidth(typval_T *argvars, typval_T *rettv);
499static void f_writefile(typval_T *argvars, typval_T *rettv);
500static void f_wordcount(typval_T *argvars, typval_T *rettv);
501static void f_xor(typval_T *argvars, typval_T *rettv);
502
503/*
504 * Array with names and number of arguments of all internal functions
505 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
506 */
507static struct fst
508{
509 char *f_name; /* function name */
510 char f_min_argc; /* minimal number of arguments */
511 char f_max_argc; /* maximal number of arguments */
512 void (*f_func)(typval_T *args, typval_T *rvar);
513 /* implementation of function */
514} functions[] =
515{
516#ifdef FEAT_FLOAT
517 {"abs", 1, 1, f_abs},
518 {"acos", 1, 1, f_acos}, /* WJMc */
519#endif
520 {"add", 2, 2, f_add},
521 {"and", 2, 2, f_and},
522 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200523 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200524 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200525 {"argidx", 0, 0, f_argidx},
526 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200527 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200528#ifdef FEAT_FLOAT
529 {"asin", 1, 1, f_asin}, /* WJMc */
530#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100531 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200532 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100533 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200534 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200535 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200536 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100537 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200538 {"assert_match", 2, 3, f_assert_match},
539 {"assert_notequal", 2, 3, f_assert_notequal},
540 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100541 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200542 {"assert_true", 1, 2, f_assert_true},
543#ifdef FEAT_FLOAT
544 {"atan", 1, 1, f_atan},
545 {"atan2", 2, 2, f_atan2},
546#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100547#ifdef FEAT_BEVAL
548 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100549# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100550 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100551# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100552#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200553 {"browse", 4, 4, f_browse},
554 {"browsedir", 2, 2, f_browsedir},
555 {"bufexists", 1, 1, f_bufexists},
556 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
557 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
558 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
559 {"buflisted", 1, 1, f_buflisted},
560 {"bufloaded", 1, 1, f_bufloaded},
561 {"bufname", 1, 1, f_bufname},
562 {"bufnr", 1, 2, f_bufnr},
563 {"bufwinid", 1, 1, f_bufwinid},
564 {"bufwinnr", 1, 1, f_bufwinnr},
565 {"byte2line", 1, 1, f_byte2line},
566 {"byteidx", 2, 2, f_byteidx},
567 {"byteidxcomp", 2, 2, f_byteidxcomp},
568 {"call", 2, 3, f_call},
569#ifdef FEAT_FLOAT
570 {"ceil", 1, 1, f_ceil},
571#endif
572#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100573 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200574 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200575 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200576 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
577 {"ch_evalraw", 2, 3, f_ch_evalraw},
578 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
579 {"ch_getjob", 1, 1, f_ch_getjob},
580 {"ch_info", 1, 1, f_ch_info},
581 {"ch_log", 1, 2, f_ch_log},
582 {"ch_logfile", 1, 2, f_ch_logfile},
583 {"ch_open", 1, 2, f_ch_open},
584 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100585 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200586 {"ch_readraw", 1, 2, f_ch_readraw},
587 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
588 {"ch_sendraw", 2, 3, f_ch_sendraw},
589 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200590 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200591#endif
592 {"changenr", 0, 0, f_changenr},
593 {"char2nr", 1, 2, f_char2nr},
594 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100595 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200596 {"col", 1, 1, f_col},
597#if defined(FEAT_INS_EXPAND)
598 {"complete", 2, 2, f_complete},
599 {"complete_add", 1, 1, f_complete_add},
600 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100601 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200602#endif
603 {"confirm", 1, 4, f_confirm},
604 {"copy", 1, 1, f_copy},
605#ifdef FEAT_FLOAT
606 {"cos", 1, 1, f_cos},
607 {"cosh", 1, 1, f_cosh},
608#endif
609 {"count", 2, 4, f_count},
610 {"cscope_connection",0,3, f_cscope_connection},
611 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100612#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200613 {"debugbreak", 1, 1, f_debugbreak},
614#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200615 {"deepcopy", 1, 2, f_deepcopy},
616 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200617 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200618 {"did_filetype", 0, 0, f_did_filetype},
619 {"diff_filler", 1, 1, f_diff_filler},
620 {"diff_hlID", 2, 2, f_diff_hlID},
621 {"empty", 1, 1, f_empty},
622 {"escape", 2, 2, f_escape},
623 {"eval", 1, 1, f_eval},
624 {"eventhandler", 0, 0, f_eventhandler},
625 {"executable", 1, 1, f_executable},
626 {"execute", 1, 2, f_execute},
627 {"exepath", 1, 1, f_exepath},
628 {"exists", 1, 1, f_exists},
629#ifdef FEAT_FLOAT
630 {"exp", 1, 1, f_exp},
631#endif
632 {"expand", 1, 3, f_expand},
633 {"extend", 2, 3, f_extend},
634 {"feedkeys", 1, 2, f_feedkeys},
635 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
636 {"filereadable", 1, 1, f_filereadable},
637 {"filewritable", 1, 1, f_filewritable},
638 {"filter", 2, 2, f_filter},
639 {"finddir", 1, 3, f_finddir},
640 {"findfile", 1, 3, f_findfile},
641#ifdef FEAT_FLOAT
642 {"float2nr", 1, 1, f_float2nr},
643 {"floor", 1, 1, f_floor},
644 {"fmod", 2, 2, f_fmod},
645#endif
646 {"fnameescape", 1, 1, f_fnameescape},
647 {"fnamemodify", 2, 2, f_fnamemodify},
648 {"foldclosed", 1, 1, f_foldclosed},
649 {"foldclosedend", 1, 1, f_foldclosedend},
650 {"foldlevel", 1, 1, f_foldlevel},
651 {"foldtext", 0, 0, f_foldtext},
652 {"foldtextresult", 1, 1, f_foldtextresult},
653 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200654 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200655 {"function", 1, 3, f_function},
656 {"garbagecollect", 0, 1, f_garbagecollect},
657 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200658 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200659 {"getbufline", 2, 3, f_getbufline},
660 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100661 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200662 {"getchar", 0, 1, f_getchar},
663 {"getcharmod", 0, 0, f_getcharmod},
664 {"getcharsearch", 0, 0, f_getcharsearch},
665 {"getcmdline", 0, 0, f_getcmdline},
666 {"getcmdpos", 0, 0, f_getcmdpos},
667 {"getcmdtype", 0, 0, f_getcmdtype},
668 {"getcmdwintype", 0, 0, f_getcmdwintype},
669#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200670 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200671#endif
672 {"getcurpos", 0, 0, f_getcurpos},
673 {"getcwd", 0, 2, f_getcwd},
674 {"getfontname", 0, 1, f_getfontname},
675 {"getfperm", 1, 1, f_getfperm},
676 {"getfsize", 1, 1, f_getfsize},
677 {"getftime", 1, 1, f_getftime},
678 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100679 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200680 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200681 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100682 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200683 {"getpid", 0, 0, f_getpid},
684 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200685 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200686 {"getreg", 0, 3, f_getreg},
687 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200688 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200689 {"gettabvar", 2, 3, f_gettabvar},
690 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100691 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200692 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100693 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200694 {"getwinposx", 0, 0, f_getwinposx},
695 {"getwinposy", 0, 0, f_getwinposy},
696 {"getwinvar", 2, 3, f_getwinvar},
697 {"glob", 1, 4, f_glob},
698 {"glob2regpat", 1, 1, f_glob2regpat},
699 {"globpath", 2, 5, f_globpath},
700 {"has", 1, 1, f_has},
701 {"has_key", 2, 2, f_has_key},
702 {"haslocaldir", 0, 2, f_haslocaldir},
703 {"hasmapto", 1, 3, f_hasmapto},
704 {"highlightID", 1, 1, f_hlID}, /* obsolete */
705 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
706 {"histadd", 2, 2, f_histadd},
707 {"histdel", 1, 2, f_histdel},
708 {"histget", 1, 2, f_histget},
709 {"histnr", 1, 1, f_histnr},
710 {"hlID", 1, 1, f_hlID},
711 {"hlexists", 1, 1, f_hlexists},
712 {"hostname", 0, 0, f_hostname},
713 {"iconv", 3, 3, f_iconv},
714 {"indent", 1, 1, f_indent},
715 {"index", 2, 4, f_index},
716 {"input", 1, 3, f_input},
717 {"inputdialog", 1, 3, f_inputdialog},
718 {"inputlist", 1, 1, f_inputlist},
719 {"inputrestore", 0, 0, f_inputrestore},
720 {"inputsave", 0, 0, f_inputsave},
721 {"inputsecret", 1, 2, f_inputsecret},
722 {"insert", 2, 3, f_insert},
723 {"invert", 1, 1, f_invert},
724 {"isdirectory", 1, 1, f_isdirectory},
Bram Moolenaarfda1bff2019-04-04 13:44:37 +0200725#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
726 {"isinf", 1, 1, f_isinf},
727#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200728 {"islocked", 1, 1, f_islocked},
729#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
730 {"isnan", 1, 1, f_isnan},
731#endif
732 {"items", 1, 1, f_items},
733#ifdef FEAT_JOB_CHANNEL
734 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200735 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200736 {"job_setoptions", 2, 2, f_job_setoptions},
737 {"job_start", 1, 2, f_job_start},
738 {"job_status", 1, 1, f_job_status},
739 {"job_stop", 1, 2, f_job_stop},
740#endif
741 {"join", 1, 2, f_join},
742 {"js_decode", 1, 1, f_js_decode},
743 {"js_encode", 1, 1, f_js_encode},
744 {"json_decode", 1, 1, f_json_decode},
745 {"json_encode", 1, 1, f_json_encode},
746 {"keys", 1, 1, f_keys},
747 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
748 {"len", 1, 1, f_len},
749 {"libcall", 3, 3, f_libcall},
750 {"libcallnr", 3, 3, f_libcallnr},
751 {"line", 1, 1, f_line},
752 {"line2byte", 1, 1, f_line2byte},
753 {"lispindent", 1, 1, f_lispindent},
754 {"localtime", 0, 0, f_localtime},
755#ifdef FEAT_FLOAT
756 {"log", 1, 1, f_log},
757 {"log10", 1, 1, f_log10},
758#endif
759#ifdef FEAT_LUA
760 {"luaeval", 1, 2, f_luaeval},
761#endif
762 {"map", 2, 2, f_map},
763 {"maparg", 1, 4, f_maparg},
764 {"mapcheck", 1, 3, f_mapcheck},
765 {"match", 2, 4, f_match},
766 {"matchadd", 2, 5, f_matchadd},
767 {"matchaddpos", 2, 5, f_matchaddpos},
768 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100769 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200770 {"matchend", 2, 4, f_matchend},
771 {"matchlist", 2, 4, f_matchlist},
772 {"matchstr", 2, 4, f_matchstr},
773 {"matchstrpos", 2, 4, f_matchstrpos},
774 {"max", 1, 1, f_max},
775 {"min", 1, 1, f_min},
776#ifdef vim_mkdir
777 {"mkdir", 1, 3, f_mkdir},
778#endif
779 {"mode", 0, 1, f_mode},
780#ifdef FEAT_MZSCHEME
781 {"mzeval", 1, 1, f_mzeval},
782#endif
783 {"nextnonblank", 1, 1, f_nextnonblank},
784 {"nr2char", 1, 2, f_nr2char},
785 {"or", 2, 2, f_or},
786 {"pathshorten", 1, 1, f_pathshorten},
787#ifdef FEAT_PERL
788 {"perleval", 1, 1, f_perleval},
789#endif
790#ifdef FEAT_FLOAT
791 {"pow", 2, 2, f_pow},
792#endif
793 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100794 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200795#ifdef FEAT_JOB_CHANNEL
796 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200797 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200798 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
799#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100800#ifdef FEAT_TEXT_PROP
801 {"prop_add", 3, 3, f_prop_add},
802 {"prop_clear", 1, 3, f_prop_clear},
803 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100804 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100805 {"prop_type_add", 2, 2, f_prop_type_add},
806 {"prop_type_change", 2, 2, f_prop_type_change},
807 {"prop_type_delete", 1, 2, f_prop_type_delete},
808 {"prop_type_get", 1, 2, f_prop_type_get},
809 {"prop_type_list", 0, 1, f_prop_type_list},
810#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200811 {"pumvisible", 0, 0, f_pumvisible},
812#ifdef FEAT_PYTHON3
813 {"py3eval", 1, 1, f_py3eval},
814#endif
815#ifdef FEAT_PYTHON
816 {"pyeval", 1, 1, f_pyeval},
817#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100818#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
819 {"pyxeval", 1, 1, f_pyxeval},
820#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821 {"range", 1, 3, f_range},
822 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200823 {"reg_executing", 0, 0, f_reg_executing},
824 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200825 {"reltime", 0, 2, f_reltime},
826#ifdef FEAT_FLOAT
827 {"reltimefloat", 1, 1, f_reltimefloat},
828#endif
829 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100830 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200831 {"remote_foreground", 1, 1, f_remote_foreground},
832 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100833 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200834 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100835 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200836 {"remove", 2, 3, f_remove},
837 {"rename", 2, 2, f_rename},
838 {"repeat", 2, 2, f_repeat},
839 {"resolve", 1, 1, f_resolve},
840 {"reverse", 1, 1, f_reverse},
841#ifdef FEAT_FLOAT
842 {"round", 1, 1, f_round},
843#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100844#ifdef FEAT_RUBY
845 {"rubyeval", 1, 1, f_rubyeval},
846#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200847 {"screenattr", 2, 2, f_screenattr},
848 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100849 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200850 {"screencol", 0, 0, f_screencol},
851 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100852 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200853 {"search", 1, 4, f_search},
854 {"searchdecl", 1, 3, f_searchdecl},
855 {"searchpair", 3, 7, f_searchpair},
856 {"searchpairpos", 3, 7, f_searchpairpos},
857 {"searchpos", 1, 4, f_searchpos},
858 {"server2client", 2, 2, f_server2client},
859 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200860 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200861 {"setbufvar", 3, 3, f_setbufvar},
862 {"setcharsearch", 1, 1, f_setcharsearch},
863 {"setcmdpos", 1, 1, f_setcmdpos},
864 {"setfperm", 2, 2, f_setfperm},
865 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200866 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100867 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200868 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200869 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200870 {"setreg", 2, 3, f_setreg},
871 {"settabvar", 3, 3, f_settabvar},
872 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100873 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200874 {"setwinvar", 3, 3, f_setwinvar},
875#ifdef FEAT_CRYPT
876 {"sha256", 1, 1, f_sha256},
877#endif
878 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100879 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100880#ifdef FEAT_SIGNS
881 {"sign_define", 1, 2, f_sign_define},
882 {"sign_getdefined", 0, 1, f_sign_getdefined},
883 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100884 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100885 {"sign_place", 4, 5, f_sign_place},
886 {"sign_undefine", 0, 1, f_sign_undefine},
887 {"sign_unplace", 1, 2, f_sign_unplace},
888#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200889 {"simplify", 1, 1, f_simplify},
890#ifdef FEAT_FLOAT
891 {"sin", 1, 1, f_sin},
892 {"sinh", 1, 1, f_sinh},
893#endif
894 {"sort", 1, 3, f_sort},
895 {"soundfold", 1, 1, f_soundfold},
896 {"spellbadword", 0, 1, f_spellbadword},
897 {"spellsuggest", 1, 3, f_spellsuggest},
898 {"split", 1, 3, f_split},
899#ifdef FEAT_FLOAT
900 {"sqrt", 1, 1, f_sqrt},
901 {"str2float", 1, 1, f_str2float},
902#endif
903 {"str2nr", 1, 2, f_str2nr},
904 {"strcharpart", 2, 3, f_strcharpart},
905 {"strchars", 1, 2, f_strchars},
906 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
907#ifdef HAVE_STRFTIME
908 {"strftime", 1, 2, f_strftime},
909#endif
910 {"strgetchar", 2, 2, f_strgetchar},
911 {"stridx", 2, 3, f_stridx},
912 {"string", 1, 1, f_string},
913 {"strlen", 1, 1, f_strlen},
914 {"strpart", 2, 3, f_strpart},
915 {"strridx", 2, 3, f_strridx},
916 {"strtrans", 1, 1, f_strtrans},
917 {"strwidth", 1, 1, f_strwidth},
918 {"submatch", 1, 2, f_submatch},
919 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200920 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200921 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200922 {"synID", 3, 3, f_synID},
923 {"synIDattr", 2, 3, f_synIDattr},
924 {"synIDtrans", 1, 1, f_synIDtrans},
925 {"synconcealed", 2, 2, f_synconcealed},
926 {"synstack", 2, 2, f_synstack},
927 {"system", 1, 2, f_system},
928 {"systemlist", 1, 2, f_systemlist},
929 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
930 {"tabpagenr", 0, 1, f_tabpagenr},
931 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
932 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100933 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200934#ifdef FEAT_FLOAT
935 {"tan", 1, 1, f_tan},
936 {"tanh", 1, 1, f_tanh},
937#endif
938 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200939#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100940 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
941 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100942 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200943 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200944# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
945 {"term_getansicolors", 1, 1, f_term_getansicolors},
946# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200947 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200948 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200949 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200950 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200951 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200952 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200953 {"term_getstatus", 1, 1, f_term_getstatus},
954 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200955 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200956 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200957 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200958 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200959# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
960 {"term_setansicolors", 2, 2, f_term_setansicolors},
961# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100962 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100963 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200964 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200965 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200966 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200967#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200968 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
969 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200970 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200971 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100972 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100973 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200974#ifdef FEAT_JOB_CHANNEL
975 {"test_null_channel", 0, 0, f_test_null_channel},
976#endif
977 {"test_null_dict", 0, 0, f_test_null_dict},
978#ifdef FEAT_JOB_CHANNEL
979 {"test_null_job", 0, 0, f_test_null_job},
980#endif
981 {"test_null_list", 0, 0, f_test_null_list},
982 {"test_null_partial", 0, 0, f_test_null_partial},
983 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200984 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100985 {"test_override", 2, 2, f_test_override},
986 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200987#ifdef FEAT_GUI
988 {"test_scrollbar", 3, 3, f_test_scrollbar},
989#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200990 {"test_settime", 1, 1, f_test_settime},
991#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200992 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200993 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200994 {"timer_start", 2, 3, f_timer_start},
995 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200996 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200997#endif
998 {"tolower", 1, 1, f_tolower},
999 {"toupper", 1, 1, f_toupper},
1000 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01001001 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001002#ifdef FEAT_FLOAT
1003 {"trunc", 1, 1, f_trunc},
1004#endif
1005 {"type", 1, 1, f_type},
1006 {"undofile", 1, 1, f_undofile},
1007 {"undotree", 0, 0, f_undotree},
1008 {"uniq", 1, 3, f_uniq},
1009 {"values", 1, 1, f_values},
1010 {"virtcol", 1, 1, f_virtcol},
1011 {"visualmode", 0, 1, f_visualmode},
1012 {"wildmenumode", 0, 0, f_wildmenumode},
1013 {"win_findbuf", 1, 1, f_win_findbuf},
1014 {"win_getid", 0, 2, f_win_getid},
1015 {"win_gotoid", 1, 1, f_win_gotoid},
1016 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1017 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001018 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019 {"winbufnr", 1, 1, f_winbufnr},
1020 {"wincol", 0, 0, f_wincol},
1021 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001022 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001023 {"winline", 0, 0, f_winline},
1024 {"winnr", 0, 1, f_winnr},
1025 {"winrestcmd", 0, 0, f_winrestcmd},
1026 {"winrestview", 1, 1, f_winrestview},
1027 {"winsaveview", 0, 0, f_winsaveview},
1028 {"winwidth", 1, 1, f_winwidth},
1029 {"wordcount", 0, 0, f_wordcount},
1030 {"writefile", 2, 3, f_writefile},
1031 {"xor", 2, 2, f_xor},
1032};
1033
1034#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1035
1036/*
1037 * Function given to ExpandGeneric() to obtain the list of internal
1038 * or user defined function names.
1039 */
1040 char_u *
1041get_function_name(expand_T *xp, int idx)
1042{
1043 static int intidx = -1;
1044 char_u *name;
1045
1046 if (idx == 0)
1047 intidx = -1;
1048 if (intidx < 0)
1049 {
1050 name = get_user_func_name(xp, idx);
1051 if (name != NULL)
1052 return name;
1053 }
1054 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1055 {
1056 STRCPY(IObuff, functions[intidx].f_name);
1057 STRCAT(IObuff, "(");
1058 if (functions[intidx].f_max_argc == 0)
1059 STRCAT(IObuff, ")");
1060 return IObuff;
1061 }
1062
1063 return NULL;
1064}
1065
1066/*
1067 * Function given to ExpandGeneric() to obtain the list of internal or
1068 * user defined variable or function names.
1069 */
1070 char_u *
1071get_expr_name(expand_T *xp, int idx)
1072{
1073 static int intidx = -1;
1074 char_u *name;
1075
1076 if (idx == 0)
1077 intidx = -1;
1078 if (intidx < 0)
1079 {
1080 name = get_function_name(xp, idx);
1081 if (name != NULL)
1082 return name;
1083 }
1084 return get_user_var_name(xp, ++intidx);
1085}
1086
1087#endif /* FEAT_CMDL_COMPL */
1088
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001089/*
1090 * Find internal function in table above.
1091 * Return index, or -1 if not found
1092 */
1093 int
1094find_internal_func(
1095 char_u *name) /* name of the function */
1096{
1097 int first = 0;
1098 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1099 int cmp;
1100 int x;
1101
1102 /*
1103 * Find the function name in the table. Binary search.
1104 */
1105 while (first <= last)
1106 {
1107 x = first + ((unsigned)(last - first) >> 1);
1108 cmp = STRCMP(name, functions[x].f_name);
1109 if (cmp < 0)
1110 last = x - 1;
1111 else if (cmp > 0)
1112 first = x + 1;
1113 else
1114 return x;
1115 }
1116 return -1;
1117}
1118
1119 int
1120call_internal_func(
1121 char_u *name,
1122 int argcount,
1123 typval_T *argvars,
1124 typval_T *rettv)
1125{
1126 int i;
1127
1128 i = find_internal_func(name);
1129 if (i < 0)
1130 return ERROR_UNKNOWN;
1131 if (argcount < functions[i].f_min_argc)
1132 return ERROR_TOOFEW;
1133 if (argcount > functions[i].f_max_argc)
1134 return ERROR_TOOMANY;
1135 argvars[argcount].v_type = VAR_UNKNOWN;
1136 functions[i].f_func(argvars, rettv);
1137 return ERROR_NONE;
1138}
1139
1140/*
1141 * Return TRUE for a non-zero Number and a non-empty String.
1142 */
1143 static int
1144non_zero_arg(typval_T *argvars)
1145{
1146 return ((argvars[0].v_type == VAR_NUMBER
1147 && argvars[0].vval.v_number != 0)
1148 || (argvars[0].v_type == VAR_SPECIAL
1149 && argvars[0].vval.v_number == VVAL_TRUE)
1150 || (argvars[0].v_type == VAR_STRING
1151 && argvars[0].vval.v_string != NULL
1152 && *argvars[0].vval.v_string != NUL));
1153}
1154
1155/*
1156 * Get the lnum from the first argument.
1157 * Also accepts ".", "$", etc., but that only works for the current buffer.
1158 * Returns -1 on error.
1159 */
1160 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001161tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001162{
1163 typval_T rettv;
1164 linenr_T lnum;
1165
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001166 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001167 if (lnum == 0) /* no valid number, try using line() */
1168 {
1169 rettv.v_type = VAR_NUMBER;
1170 f_line(argvars, &rettv);
1171 lnum = (linenr_T)rettv.vval.v_number;
1172 clear_tv(&rettv);
1173 }
1174 return lnum;
1175}
1176
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001177/*
1178 * Get the lnum from the first argument.
1179 * Also accepts "$", then "buf" is used.
1180 * Returns 0 on error.
1181 */
1182 static linenr_T
1183tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1184{
1185 if (argvars[0].v_type == VAR_STRING
1186 && argvars[0].vval.v_string != NULL
1187 && argvars[0].vval.v_string[0] == '$'
1188 && buf != NULL)
1189 return buf->b_ml.ml_line_count;
1190 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1191}
1192
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001193#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001194/*
1195 * Get the float value of "argvars[0]" into "f".
1196 * Returns FAIL when the argument is not a Number or Float.
1197 */
1198 static int
1199get_float_arg(typval_T *argvars, float_T *f)
1200{
1201 if (argvars[0].v_type == VAR_FLOAT)
1202 {
1203 *f = argvars[0].vval.v_float;
1204 return OK;
1205 }
1206 if (argvars[0].v_type == VAR_NUMBER)
1207 {
1208 *f = (float_T)argvars[0].vval.v_number;
1209 return OK;
1210 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001211 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001212 return FAIL;
1213}
1214
1215/*
1216 * "abs(expr)" function
1217 */
1218 static void
1219f_abs(typval_T *argvars, typval_T *rettv)
1220{
1221 if (argvars[0].v_type == VAR_FLOAT)
1222 {
1223 rettv->v_type = VAR_FLOAT;
1224 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1225 }
1226 else
1227 {
1228 varnumber_T n;
1229 int error = FALSE;
1230
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001231 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001232 if (error)
1233 rettv->vval.v_number = -1;
1234 else if (n > 0)
1235 rettv->vval.v_number = n;
1236 else
1237 rettv->vval.v_number = -n;
1238 }
1239}
1240
1241/*
1242 * "acos()" function
1243 */
1244 static void
1245f_acos(typval_T *argvars, typval_T *rettv)
1246{
1247 float_T f = 0.0;
1248
1249 rettv->v_type = VAR_FLOAT;
1250 if (get_float_arg(argvars, &f) == OK)
1251 rettv->vval.v_float = acos(f);
1252 else
1253 rettv->vval.v_float = 0.0;
1254}
1255#endif
1256
1257/*
1258 * "add(list, item)" function
1259 */
1260 static void
1261f_add(typval_T *argvars, typval_T *rettv)
1262{
1263 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001264 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001265
1266 rettv->vval.v_number = 1; /* Default: Failed */
1267 if (argvars[0].v_type == VAR_LIST)
1268 {
1269 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001270 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001271 (char_u *)N_("add() argument"), TRUE)
1272 && list_append_tv(l, &argvars[1]) == OK)
1273 copy_tv(&argvars[0], rettv);
1274 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001275 else if (argvars[0].v_type == VAR_BLOB)
1276 {
1277 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001278 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001279 (char_u *)N_("add() argument"), TRUE))
1280 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001281 int error = FALSE;
1282 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1283
1284 if (!error)
1285 {
1286 ga_append(&b->bv_ga, (int)n);
1287 copy_tv(&argvars[0], rettv);
1288 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001289 }
1290 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001291 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001292 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001293}
1294
1295/*
1296 * "and(expr, expr)" function
1297 */
1298 static void
1299f_and(typval_T *argvars, typval_T *rettv)
1300{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001301 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1302 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001303}
1304
1305/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001306 * If there is a window for "curbuf", make it the current window.
1307 */
1308 static void
1309find_win_for_curbuf(void)
1310{
1311 wininfo_T *wip;
1312
1313 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1314 {
1315 if (wip->wi_win != NULL)
1316 {
1317 curwin = wip->wi_win;
1318 break;
1319 }
1320 }
1321}
1322
1323/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001324 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001325 */
1326 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001327set_buffer_lines(
1328 buf_T *buf,
1329 linenr_T lnum_arg,
1330 int append,
1331 typval_T *lines,
1332 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001333{
Bram Moolenaarca851592018-06-06 21:04:07 +02001334 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1335 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001336 list_T *l = NULL;
1337 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001338 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001339 linenr_T append_lnum;
1340 buf_T *curbuf_save = NULL;
1341 win_T *curwin_save = NULL;
1342 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001343
Bram Moolenaarca851592018-06-06 21:04:07 +02001344 /* When using the current buffer ml_mfp will be set if needed. Useful when
1345 * setline() is used on startup. For other buffers the buffer must be
1346 * loaded. */
1347 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001348 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001349 rettv->vval.v_number = 1; /* FAIL */
1350 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001351 }
1352
Bram Moolenaarca851592018-06-06 21:04:07 +02001353 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001354 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001355 curbuf_save = curbuf;
1356 curwin_save = curwin;
1357 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001358 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001359 }
1360
1361 if (append)
1362 // appendbufline() uses the line number below which we insert
1363 append_lnum = lnum - 1;
1364 else
1365 // setbufline() uses the line number above which we insert, we only
1366 // append if it's below the last line
1367 append_lnum = curbuf->b_ml.ml_line_count;
1368
1369 if (lines->v_type == VAR_LIST)
1370 {
1371 l = lines->vval.v_list;
1372 li = l->lv_first;
1373 }
1374 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001375 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001376
1377 /* default result is zero == OK */
1378 for (;;)
1379 {
1380 if (l != NULL)
1381 {
1382 /* list argument, get next string */
1383 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001384 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001385 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001386 li = li->li_next;
1387 }
1388
Bram Moolenaarca851592018-06-06 21:04:07 +02001389 rettv->vval.v_number = 1; /* FAIL */
1390 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1391 break;
1392
1393 /* When coming here from Insert mode, sync undo, so that this can be
1394 * undone separately from what was previously inserted. */
1395 if (u_sync_once == 2)
1396 {
1397 u_sync_once = 1; /* notify that u_sync() was called */
1398 u_sync(TRUE);
1399 }
1400
1401 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1402 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001403 // Existing line, replace it.
1404 // Removes any existing text properties.
1405 if (u_savesub(lnum) == OK && ml_replace_len(
1406 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001407 {
1408 changed_bytes(lnum, 0);
1409 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1410 check_cursor_col();
1411 rettv->vval.v_number = 0; /* OK */
1412 }
1413 }
1414 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1415 {
1416 /* append the line */
1417 ++added;
1418 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1419 rettv->vval.v_number = 0; /* OK */
1420 }
1421
1422 if (l == NULL) /* only one string argument */
1423 break;
1424 ++lnum;
1425 }
1426
1427 if (added > 0)
1428 {
1429 win_T *wp;
1430 tabpage_T *tp;
1431
1432 appended_lines_mark(append_lnum, added);
1433 FOR_ALL_TAB_WINDOWS(tp, wp)
1434 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1435 wp->w_cursor.lnum += added;
1436 check_cursor_col();
1437
Bram Moolenaarf2732452018-06-03 14:47:35 +02001438#ifdef FEAT_JOB_CHANNEL
1439 if (bt_prompt(curbuf) && (State & INSERT))
1440 // show the line with the prompt
1441 update_topline();
1442#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001443 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001444
1445 if (!is_curbuf)
1446 {
1447 curbuf = curbuf_save;
1448 curwin = curwin_save;
1449 }
1450}
1451
1452/*
1453 * "append(lnum, string/list)" function
1454 */
1455 static void
1456f_append(typval_T *argvars, typval_T *rettv)
1457{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001458 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001459
1460 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1461}
1462
1463/*
1464 * "appendbufline(buf, lnum, string/list)" function
1465 */
1466 static void
1467f_appendbufline(typval_T *argvars, typval_T *rettv)
1468{
1469 linenr_T lnum;
1470 buf_T *buf;
1471
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001472 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001473 if (buf == NULL)
1474 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001475 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001476 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001477 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001478 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1479 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480}
1481
1482/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001483 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001484 */
1485 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001486f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001487{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001488 win_T *wp;
1489
1490 if (argvars[0].v_type == VAR_UNKNOWN)
1491 // use the current window
1492 rettv->vval.v_number = ARGCOUNT;
1493 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001494 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001495 // use the global argument list
1496 rettv->vval.v_number = GARGCOUNT;
1497 else
1498 {
1499 // use the argument list of the specified window
1500 wp = find_win_by_nr_or_id(&argvars[0]);
1501 if (wp != NULL)
1502 rettv->vval.v_number = WARGCOUNT(wp);
1503 else
1504 rettv->vval.v_number = -1;
1505 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001506}
1507
1508/*
1509 * "argidx()" function
1510 */
1511 static void
1512f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1513{
1514 rettv->vval.v_number = curwin->w_arg_idx;
1515}
1516
1517/*
1518 * "arglistid()" function
1519 */
1520 static void
1521f_arglistid(typval_T *argvars, typval_T *rettv)
1522{
1523 win_T *wp;
1524
1525 rettv->vval.v_number = -1;
1526 wp = find_tabwin(&argvars[0], &argvars[1]);
1527 if (wp != NULL)
1528 rettv->vval.v_number = wp->w_alist->id;
1529}
1530
1531/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001532 * Get the argument list for a given window
1533 */
1534 static void
1535get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1536{
1537 int idx;
1538
1539 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1540 for (idx = 0; idx < argcount; ++idx)
1541 list_append_string(rettv->vval.v_list,
1542 alist_name(&arglist[idx]), -1);
1543}
1544
1545/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001546 * "argv(nr)" function
1547 */
1548 static void
1549f_argv(typval_T *argvars, typval_T *rettv)
1550{
1551 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001552 aentry_T *arglist = NULL;
1553 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001554
1555 if (argvars[0].v_type != VAR_UNKNOWN)
1556 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001557 if (argvars[1].v_type == VAR_UNKNOWN)
1558 {
1559 arglist = ARGLIST;
1560 argcount = ARGCOUNT;
1561 }
1562 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001563 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001564 {
1565 arglist = GARGLIST;
1566 argcount = GARGCOUNT;
1567 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001568 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001569 {
1570 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1571
1572 if (wp != NULL)
1573 {
1574 /* Use the argument list of the specified window */
1575 arglist = WARGLIST(wp);
1576 argcount = WARGCOUNT(wp);
1577 }
1578 }
1579
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001580 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001581 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001582 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001583 if (arglist != NULL && idx >= 0 && idx < argcount)
1584 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1585 else if (idx == -1)
1586 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001587 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001588 else
1589 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001590}
1591
1592/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001593 * "assert_beeps(cmd [, error])" function
1594 */
1595 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001596f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001597{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001598 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001599}
1600
1601/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001602 * "assert_equal(expected, actual[, msg])" function
1603 */
1604 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001605f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001606{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001607 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001608}
1609
1610/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001611 * "assert_equalfile(fname-one, fname-two)" function
1612 */
1613 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001614f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001615{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001616 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001617}
1618
1619/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001620 * "assert_notequal(expected, actual[, msg])" function
1621 */
1622 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001623f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001624{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001625 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001626}
1627
1628/*
1629 * "assert_exception(string[, msg])" function
1630 */
1631 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001632f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001633{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001634 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001635}
1636
1637/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001638 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001639 */
1640 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001641f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001642{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001643 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001644}
1645
1646/*
1647 * "assert_false(actual[, msg])" function
1648 */
1649 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001650f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001651{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001652 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001653}
1654
1655/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001656 * "assert_inrange(lower, upper[, msg])" function
1657 */
1658 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001659f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001660{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001661 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001662}
1663
1664/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001665 * "assert_match(pattern, actual[, msg])" function
1666 */
1667 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001668f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001669{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001670 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001671}
1672
1673/*
1674 * "assert_notmatch(pattern, actual[, msg])" function
1675 */
1676 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001677f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001678{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001679 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001680}
1681
1682/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001683 * "assert_report(msg)" function
1684 */
1685 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001686f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001687{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001688 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001689}
1690
1691/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001692 * "assert_true(actual[, msg])" function
1693 */
1694 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001695f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001696{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001697 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001698}
1699
1700#ifdef FEAT_FLOAT
1701/*
1702 * "asin()" function
1703 */
1704 static void
1705f_asin(typval_T *argvars, typval_T *rettv)
1706{
1707 float_T f = 0.0;
1708
1709 rettv->v_type = VAR_FLOAT;
1710 if (get_float_arg(argvars, &f) == OK)
1711 rettv->vval.v_float = asin(f);
1712 else
1713 rettv->vval.v_float = 0.0;
1714}
1715
1716/*
1717 * "atan()" function
1718 */
1719 static void
1720f_atan(typval_T *argvars, typval_T *rettv)
1721{
1722 float_T f = 0.0;
1723
1724 rettv->v_type = VAR_FLOAT;
1725 if (get_float_arg(argvars, &f) == OK)
1726 rettv->vval.v_float = atan(f);
1727 else
1728 rettv->vval.v_float = 0.0;
1729}
1730
1731/*
1732 * "atan2()" function
1733 */
1734 static void
1735f_atan2(typval_T *argvars, typval_T *rettv)
1736{
1737 float_T fx = 0.0, fy = 0.0;
1738
1739 rettv->v_type = VAR_FLOAT;
1740 if (get_float_arg(argvars, &fx) == OK
1741 && get_float_arg(&argvars[1], &fy) == OK)
1742 rettv->vval.v_float = atan2(fx, fy);
1743 else
1744 rettv->vval.v_float = 0.0;
1745}
1746#endif
1747
1748/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001749 * "balloon_show()" function
1750 */
1751#ifdef FEAT_BEVAL
1752 static void
1753f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1754{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001755 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001756 {
1757 if (argvars[0].v_type == VAR_LIST
1758# ifdef FEAT_GUI
1759 && !gui.in_use
1760# endif
1761 )
1762 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1763 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001764 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001765 }
1766}
1767
Bram Moolenaar669a8282017-11-19 20:13:05 +01001768# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001769 static void
1770f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1771{
1772 if (rettv_list_alloc(rettv) == OK)
1773 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001774 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001775
1776 if (msg != NULL)
1777 {
1778 pumitem_T *array;
1779 int size = split_message(msg, &array);
1780 int i;
1781
1782 /* Skip the first and last item, they are always empty. */
1783 for (i = 1; i < size - 1; ++i)
1784 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001785 while (size > 0)
1786 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001787 vim_free(array);
1788 }
1789 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001790}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001791# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001792#endif
1793
1794/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001795 * "browse(save, title, initdir, default)" function
1796 */
1797 static void
1798f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1799{
1800#ifdef FEAT_BROWSE
1801 int save;
1802 char_u *title;
1803 char_u *initdir;
1804 char_u *defname;
1805 char_u buf[NUMBUFLEN];
1806 char_u buf2[NUMBUFLEN];
1807 int error = FALSE;
1808
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001809 save = (int)tv_get_number_chk(&argvars[0], &error);
1810 title = tv_get_string_chk(&argvars[1]);
1811 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1812 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001813
1814 if (error || title == NULL || initdir == NULL || defname == NULL)
1815 rettv->vval.v_string = NULL;
1816 else
1817 rettv->vval.v_string =
1818 do_browse(save ? BROWSE_SAVE : 0,
1819 title, defname, NULL, initdir, NULL, curbuf);
1820#else
1821 rettv->vval.v_string = NULL;
1822#endif
1823 rettv->v_type = VAR_STRING;
1824}
1825
1826/*
1827 * "browsedir(title, initdir)" function
1828 */
1829 static void
1830f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1831{
1832#ifdef FEAT_BROWSE
1833 char_u *title;
1834 char_u *initdir;
1835 char_u buf[NUMBUFLEN];
1836
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001837 title = tv_get_string_chk(&argvars[0]);
1838 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001839
1840 if (title == NULL || initdir == NULL)
1841 rettv->vval.v_string = NULL;
1842 else
1843 rettv->vval.v_string = do_browse(BROWSE_DIR,
1844 title, NULL, NULL, initdir, NULL, curbuf);
1845#else
1846 rettv->vval.v_string = NULL;
1847#endif
1848 rettv->v_type = VAR_STRING;
1849}
1850
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001851/*
1852 * Find a buffer by number or exact name.
1853 */
1854 static buf_T *
1855find_buffer(typval_T *avar)
1856{
1857 buf_T *buf = NULL;
1858
1859 if (avar->v_type == VAR_NUMBER)
1860 buf = buflist_findnr((int)avar->vval.v_number);
1861 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1862 {
1863 buf = buflist_findname_exp(avar->vval.v_string);
1864 if (buf == NULL)
1865 {
1866 /* No full path name match, try a match with a URL or a "nofile"
1867 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001868 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001869 if (buf->b_fname != NULL
1870 && (path_with_url(buf->b_fname)
1871#ifdef FEAT_QUICKFIX
1872 || bt_nofile(buf)
1873#endif
1874 )
1875 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1876 break;
1877 }
1878 }
1879 return buf;
1880}
1881
1882/*
1883 * "bufexists(expr)" function
1884 */
1885 static void
1886f_bufexists(typval_T *argvars, typval_T *rettv)
1887{
1888 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1889}
1890
1891/*
1892 * "buflisted(expr)" function
1893 */
1894 static void
1895f_buflisted(typval_T *argvars, typval_T *rettv)
1896{
1897 buf_T *buf;
1898
1899 buf = find_buffer(&argvars[0]);
1900 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1901}
1902
1903/*
1904 * "bufloaded(expr)" function
1905 */
1906 static void
1907f_bufloaded(typval_T *argvars, typval_T *rettv)
1908{
1909 buf_T *buf;
1910
1911 buf = find_buffer(&argvars[0]);
1912 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1913}
1914
1915 buf_T *
1916buflist_find_by_name(char_u *name, int curtab_only)
1917{
1918 int save_magic;
1919 char_u *save_cpo;
1920 buf_T *buf;
1921
1922 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1923 save_magic = p_magic;
1924 p_magic = TRUE;
1925 save_cpo = p_cpo;
1926 p_cpo = (char_u *)"";
1927
1928 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1929 TRUE, FALSE, curtab_only));
1930
1931 p_magic = save_magic;
1932 p_cpo = save_cpo;
1933 return buf;
1934}
1935
1936/*
1937 * Get buffer by number or pattern.
1938 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001939 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001940tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001941{
1942 char_u *name = tv->vval.v_string;
1943 buf_T *buf;
1944
1945 if (tv->v_type == VAR_NUMBER)
1946 return buflist_findnr((int)tv->vval.v_number);
1947 if (tv->v_type != VAR_STRING)
1948 return NULL;
1949 if (name == NULL || *name == NUL)
1950 return curbuf;
1951 if (name[0] == '$' && name[1] == NUL)
1952 return lastbuf;
1953
1954 buf = buflist_find_by_name(name, curtab_only);
1955
1956 /* If not found, try expanding the name, like done for bufexists(). */
1957 if (buf == NULL)
1958 buf = find_buffer(tv);
1959
1960 return buf;
1961}
1962
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001963#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001964/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001965 * Get the buffer from "arg" and give an error and return NULL if it is not
1966 * valid.
1967 */
1968 static buf_T *
1969get_buf_arg(typval_T *arg)
1970{
1971 buf_T *buf;
1972
1973 ++emsg_off;
1974 buf = tv_get_buf(arg, FALSE);
1975 --emsg_off;
1976 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001977 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001978 return buf;
1979}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001980#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001981
1982/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001983 * "bufname(expr)" function
1984 */
1985 static void
1986f_bufname(typval_T *argvars, typval_T *rettv)
1987{
1988 buf_T *buf;
1989
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001990 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001991 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001992 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001993 rettv->v_type = VAR_STRING;
1994 if (buf != NULL && buf->b_fname != NULL)
1995 rettv->vval.v_string = vim_strsave(buf->b_fname);
1996 else
1997 rettv->vval.v_string = NULL;
1998 --emsg_off;
1999}
2000
2001/*
2002 * "bufnr(expr)" function
2003 */
2004 static void
2005f_bufnr(typval_T *argvars, typval_T *rettv)
2006{
2007 buf_T *buf;
2008 int error = FALSE;
2009 char_u *name;
2010
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002011 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002012 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002013 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002014 --emsg_off;
2015
2016 /* If the buffer isn't found and the second argument is not zero create a
2017 * new buffer. */
2018 if (buf == NULL
2019 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002020 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002021 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002022 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002023 && !error)
2024 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2025
2026 if (buf != NULL)
2027 rettv->vval.v_number = buf->b_fnum;
2028 else
2029 rettv->vval.v_number = -1;
2030}
2031
2032 static void
2033buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2034{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002035 win_T *wp;
2036 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002037 buf_T *buf;
2038
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002039 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002040 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002041 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002042 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002043 {
2044 ++winnr;
2045 if (wp->w_buffer == buf)
2046 break;
2047 }
2048 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002049 --emsg_off;
2050}
2051
2052/*
2053 * "bufwinid(nr)" function
2054 */
2055 static void
2056f_bufwinid(typval_T *argvars, typval_T *rettv)
2057{
2058 buf_win_common(argvars, rettv, FALSE);
2059}
2060
2061/*
2062 * "bufwinnr(nr)" function
2063 */
2064 static void
2065f_bufwinnr(typval_T *argvars, typval_T *rettv)
2066{
2067 buf_win_common(argvars, rettv, TRUE);
2068}
2069
2070/*
2071 * "byte2line(byte)" function
2072 */
2073 static void
2074f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2075{
2076#ifndef FEAT_BYTEOFF
2077 rettv->vval.v_number = -1;
2078#else
2079 long boff = 0;
2080
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002081 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002082 if (boff < 0)
2083 rettv->vval.v_number = -1;
2084 else
2085 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2086 (linenr_T)0, &boff);
2087#endif
2088}
2089
2090 static void
2091byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2092{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002093 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002094 char_u *str;
2095 varnumber_T idx;
2096
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002097 str = tv_get_string_chk(&argvars[0]);
2098 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002099 rettv->vval.v_number = -1;
2100 if (str == NULL || idx < 0)
2101 return;
2102
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002103 t = str;
2104 for ( ; idx > 0; idx--)
2105 {
2106 if (*t == NUL) /* EOL reached */
2107 return;
2108 if (enc_utf8 && comp)
2109 t += utf_ptr2len(t);
2110 else
2111 t += (*mb_ptr2len)(t);
2112 }
2113 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002114}
2115
2116/*
2117 * "byteidx()" function
2118 */
2119 static void
2120f_byteidx(typval_T *argvars, typval_T *rettv)
2121{
2122 byteidx(argvars, rettv, FALSE);
2123}
2124
2125/*
2126 * "byteidxcomp()" function
2127 */
2128 static void
2129f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2130{
2131 byteidx(argvars, rettv, TRUE);
2132}
2133
2134/*
2135 * "call(func, arglist [, dict])" function
2136 */
2137 static void
2138f_call(typval_T *argvars, typval_T *rettv)
2139{
2140 char_u *func;
2141 partial_T *partial = NULL;
2142 dict_T *selfdict = NULL;
2143
2144 if (argvars[1].v_type != VAR_LIST)
2145 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002146 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002147 return;
2148 }
2149 if (argvars[1].vval.v_list == NULL)
2150 return;
2151
2152 if (argvars[0].v_type == VAR_FUNC)
2153 func = argvars[0].vval.v_string;
2154 else if (argvars[0].v_type == VAR_PARTIAL)
2155 {
2156 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002157 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002158 }
2159 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002160 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002161 if (*func == NUL)
2162 return; /* type error or empty name */
2163
2164 if (argvars[2].v_type != VAR_UNKNOWN)
2165 {
2166 if (argvars[2].v_type != VAR_DICT)
2167 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002168 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002169 return;
2170 }
2171 selfdict = argvars[2].vval.v_dict;
2172 }
2173
2174 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2175}
2176
2177#ifdef FEAT_FLOAT
2178/*
2179 * "ceil({float})" function
2180 */
2181 static void
2182f_ceil(typval_T *argvars, typval_T *rettv)
2183{
2184 float_T f = 0.0;
2185
2186 rettv->v_type = VAR_FLOAT;
2187 if (get_float_arg(argvars, &f) == OK)
2188 rettv->vval.v_float = ceil(f);
2189 else
2190 rettv->vval.v_float = 0.0;
2191}
2192#endif
2193
2194#ifdef FEAT_JOB_CHANNEL
2195/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002196 * "ch_canread()" function
2197 */
2198 static void
2199f_ch_canread(typval_T *argvars, typval_T *rettv)
2200{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002201 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002202
2203 rettv->vval.v_number = 0;
2204 if (channel != NULL)
2205 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2206 || channel_has_readahead(channel, PART_OUT)
2207 || channel_has_readahead(channel, PART_ERR);
2208}
2209
2210/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002211 * "ch_close()" function
2212 */
2213 static void
2214f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2215{
2216 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2217
2218 if (channel != NULL)
2219 {
2220 channel_close(channel, FALSE);
2221 channel_clear(channel);
2222 }
2223}
2224
2225/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002226 * "ch_close()" function
2227 */
2228 static void
2229f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2230{
2231 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2232
2233 if (channel != NULL)
2234 channel_close_in(channel);
2235}
2236
2237/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002238 * "ch_getbufnr()" function
2239 */
2240 static void
2241f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2242{
2243 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2244
2245 rettv->vval.v_number = -1;
2246 if (channel != NULL)
2247 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002248 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002249 int part;
2250
2251 if (STRCMP(what, "err") == 0)
2252 part = PART_ERR;
2253 else if (STRCMP(what, "out") == 0)
2254 part = PART_OUT;
2255 else if (STRCMP(what, "in") == 0)
2256 part = PART_IN;
2257 else
2258 part = PART_SOCK;
2259 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2260 rettv->vval.v_number =
2261 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2262 }
2263}
2264
2265/*
2266 * "ch_getjob()" function
2267 */
2268 static void
2269f_ch_getjob(typval_T *argvars, typval_T *rettv)
2270{
2271 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2272
2273 if (channel != NULL)
2274 {
2275 rettv->v_type = VAR_JOB;
2276 rettv->vval.v_job = channel->ch_job;
2277 if (channel->ch_job != NULL)
2278 ++channel->ch_job->jv_refcount;
2279 }
2280}
2281
2282/*
2283 * "ch_info()" function
2284 */
2285 static void
2286f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2287{
2288 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2289
2290 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2291 channel_info(channel, rettv->vval.v_dict);
2292}
2293
2294/*
2295 * "ch_log()" function
2296 */
2297 static void
2298f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2299{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002300 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002301 channel_T *channel = NULL;
2302
2303 if (argvars[1].v_type != VAR_UNKNOWN)
2304 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2305
Bram Moolenaard5359b22018-04-05 22:44:39 +02002306 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002307}
2308
2309/*
2310 * "ch_logfile()" function
2311 */
2312 static void
2313f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2314{
2315 char_u *fname;
2316 char_u *opt = (char_u *)"";
2317 char_u buf[NUMBUFLEN];
2318
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002319 /* Don't open a file in restricted mode. */
2320 if (check_restricted() || check_secure())
2321 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002322 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002323 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002324 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002325 ch_logfile(fname, opt);
2326}
2327
2328/*
2329 * "ch_open()" function
2330 */
2331 static void
2332f_ch_open(typval_T *argvars, typval_T *rettv)
2333{
2334 rettv->v_type = VAR_CHANNEL;
2335 if (check_restricted() || check_secure())
2336 return;
2337 rettv->vval.v_channel = channel_open_func(argvars);
2338}
2339
2340/*
2341 * "ch_read()" function
2342 */
2343 static void
2344f_ch_read(typval_T *argvars, typval_T *rettv)
2345{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002346 common_channel_read(argvars, rettv, FALSE, FALSE);
2347}
2348
2349/*
2350 * "ch_readblob()" function
2351 */
2352 static void
2353f_ch_readblob(typval_T *argvars, typval_T *rettv)
2354{
2355 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002356}
2357
2358/*
2359 * "ch_readraw()" function
2360 */
2361 static void
2362f_ch_readraw(typval_T *argvars, typval_T *rettv)
2363{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002364 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002365}
2366
2367/*
2368 * "ch_evalexpr()" function
2369 */
2370 static void
2371f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2372{
2373 ch_expr_common(argvars, rettv, TRUE);
2374}
2375
2376/*
2377 * "ch_sendexpr()" function
2378 */
2379 static void
2380f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2381{
2382 ch_expr_common(argvars, rettv, FALSE);
2383}
2384
2385/*
2386 * "ch_evalraw()" function
2387 */
2388 static void
2389f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2390{
2391 ch_raw_common(argvars, rettv, TRUE);
2392}
2393
2394/*
2395 * "ch_sendraw()" function
2396 */
2397 static void
2398f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2399{
2400 ch_raw_common(argvars, rettv, FALSE);
2401}
2402
2403/*
2404 * "ch_setoptions()" function
2405 */
2406 static void
2407f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2408{
2409 channel_T *channel;
2410 jobopt_T opt;
2411
2412 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2413 if (channel == NULL)
2414 return;
2415 clear_job_options(&opt);
2416 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002417 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002418 channel_set_options(channel, &opt);
2419 free_job_options(&opt);
2420}
2421
2422/*
2423 * "ch_status()" function
2424 */
2425 static void
2426f_ch_status(typval_T *argvars, typval_T *rettv)
2427{
2428 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002429 jobopt_T opt;
2430 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002431
2432 /* return an empty string by default */
2433 rettv->v_type = VAR_STRING;
2434 rettv->vval.v_string = NULL;
2435
2436 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002437
2438 if (argvars[1].v_type != VAR_UNKNOWN)
2439 {
2440 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002441 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002442 && (opt.jo_set & JO_PART))
2443 part = opt.jo_part;
2444 }
2445
2446 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002447}
2448#endif
2449
2450/*
2451 * "changenr()" function
2452 */
2453 static void
2454f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2455{
2456 rettv->vval.v_number = curbuf->b_u_seq_cur;
2457}
2458
2459/*
2460 * "char2nr(string)" function
2461 */
2462 static void
2463f_char2nr(typval_T *argvars, typval_T *rettv)
2464{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002465 if (has_mbyte)
2466 {
2467 int utf8 = 0;
2468
2469 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002470 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002471
2472 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002473 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002474 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002475 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002476 }
2477 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002478 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002479}
2480
2481/*
2482 * "cindent(lnum)" function
2483 */
2484 static void
2485f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2486{
2487#ifdef FEAT_CINDENT
2488 pos_T pos;
2489 linenr_T lnum;
2490
2491 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002492 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002493 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2494 {
2495 curwin->w_cursor.lnum = lnum;
2496 rettv->vval.v_number = get_c_indent();
2497 curwin->w_cursor = pos;
2498 }
2499 else
2500#endif
2501 rettv->vval.v_number = -1;
2502}
2503
Bram Moolenaaraff74912019-03-30 18:11:49 +01002504 static win_T *
2505get_optional_window(typval_T *argvars, int idx)
2506{
2507 win_T *win = curwin;
2508
2509 if (argvars[idx].v_type != VAR_UNKNOWN)
2510 {
2511 win = find_win_by_nr_or_id(&argvars[idx]);
2512 if (win == NULL)
2513 {
2514 emsg(_(e_invalwindow));
2515 return NULL;
2516 }
2517 }
2518 return win;
2519}
2520
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002521/*
2522 * "clearmatches()" function
2523 */
2524 static void
2525f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2526{
2527#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01002528 win_T *win = get_optional_window(argvars, 0);
2529
2530 if (win != NULL)
2531 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002532#endif
2533}
2534
2535/*
2536 * "col(string)" function
2537 */
2538 static void
2539f_col(typval_T *argvars, typval_T *rettv)
2540{
2541 colnr_T col = 0;
2542 pos_T *fp;
2543 int fnum = curbuf->b_fnum;
2544
2545 fp = var2fpos(&argvars[0], FALSE, &fnum);
2546 if (fp != NULL && fnum == curbuf->b_fnum)
2547 {
2548 if (fp->col == MAXCOL)
2549 {
2550 /* '> can be MAXCOL, get the length of the line then */
2551 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2552 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2553 else
2554 col = MAXCOL;
2555 }
2556 else
2557 {
2558 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002559 /* col(".") when the cursor is on the NUL at the end of the line
2560 * because of "coladd" can be seen as an extra column. */
2561 if (virtual_active() && fp == &curwin->w_cursor)
2562 {
2563 char_u *p = ml_get_cursor();
2564
2565 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2566 curwin->w_virtcol - curwin->w_cursor.coladd))
2567 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002568 int l;
2569
2570 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2571 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002572 }
2573 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002574 }
2575 }
2576 rettv->vval.v_number = col;
2577}
2578
2579#if defined(FEAT_INS_EXPAND)
2580/*
2581 * "complete()" function
2582 */
2583 static void
2584f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2585{
2586 int startcol;
2587
2588 if ((State & INSERT) == 0)
2589 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002590 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002591 return;
2592 }
2593
2594 /* Check for undo allowed here, because if something was already inserted
2595 * the line was already saved for undo and this check isn't done. */
2596 if (!undo_allowed())
2597 return;
2598
2599 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2600 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002601 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 return;
2603 }
2604
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002605 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002606 if (startcol <= 0)
2607 return;
2608
2609 set_completion(startcol - 1, argvars[1].vval.v_list);
2610}
2611
2612/*
2613 * "complete_add()" function
2614 */
2615 static void
2616f_complete_add(typval_T *argvars, typval_T *rettv)
2617{
2618 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2619}
2620
2621/*
2622 * "complete_check()" function
2623 */
2624 static void
2625f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2626{
2627 int saved = RedrawingDisabled;
2628
2629 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002630 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002631 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002632 RedrawingDisabled = saved;
2633}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002634
2635/*
2636 * "complete_info()" function
2637 */
2638 static void
2639f_complete_info(typval_T *argvars, typval_T *rettv)
2640{
2641 list_T *what_list = NULL;
2642
2643 if (rettv_dict_alloc(rettv) != OK)
2644 return;
2645
2646 if (argvars[0].v_type != VAR_UNKNOWN)
2647 {
2648 if (argvars[0].v_type != VAR_LIST)
2649 {
2650 emsg(_(e_listreq));
2651 return;
2652 }
2653 what_list = argvars[0].vval.v_list;
2654 }
2655 get_complete_info(what_list, rettv->vval.v_dict);
2656}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002657#endif
2658
2659/*
2660 * "confirm(message, buttons[, default [, type]])" function
2661 */
2662 static void
2663f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2664{
2665#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2666 char_u *message;
2667 char_u *buttons = NULL;
2668 char_u buf[NUMBUFLEN];
2669 char_u buf2[NUMBUFLEN];
2670 int def = 1;
2671 int type = VIM_GENERIC;
2672 char_u *typestr;
2673 int error = FALSE;
2674
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002675 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002676 if (message == NULL)
2677 error = TRUE;
2678 if (argvars[1].v_type != VAR_UNKNOWN)
2679 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002680 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002681 if (buttons == NULL)
2682 error = TRUE;
2683 if (argvars[2].v_type != VAR_UNKNOWN)
2684 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002685 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002686 if (argvars[3].v_type != VAR_UNKNOWN)
2687 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002688 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002689 if (typestr == NULL)
2690 error = TRUE;
2691 else
2692 {
2693 switch (TOUPPER_ASC(*typestr))
2694 {
2695 case 'E': type = VIM_ERROR; break;
2696 case 'Q': type = VIM_QUESTION; break;
2697 case 'I': type = VIM_INFO; break;
2698 case 'W': type = VIM_WARNING; break;
2699 case 'G': type = VIM_GENERIC; break;
2700 }
2701 }
2702 }
2703 }
2704 }
2705
2706 if (buttons == NULL || *buttons == NUL)
2707 buttons = (char_u *)_("&Ok");
2708
2709 if (!error)
2710 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2711 def, NULL, FALSE);
2712#endif
2713}
2714
2715/*
2716 * "copy()" function
2717 */
2718 static void
2719f_copy(typval_T *argvars, typval_T *rettv)
2720{
2721 item_copy(&argvars[0], rettv, FALSE, 0);
2722}
2723
2724#ifdef FEAT_FLOAT
2725/*
2726 * "cos()" function
2727 */
2728 static void
2729f_cos(typval_T *argvars, typval_T *rettv)
2730{
2731 float_T f = 0.0;
2732
2733 rettv->v_type = VAR_FLOAT;
2734 if (get_float_arg(argvars, &f) == OK)
2735 rettv->vval.v_float = cos(f);
2736 else
2737 rettv->vval.v_float = 0.0;
2738}
2739
2740/*
2741 * "cosh()" function
2742 */
2743 static void
2744f_cosh(typval_T *argvars, typval_T *rettv)
2745{
2746 float_T f = 0.0;
2747
2748 rettv->v_type = VAR_FLOAT;
2749 if (get_float_arg(argvars, &f) == OK)
2750 rettv->vval.v_float = cosh(f);
2751 else
2752 rettv->vval.v_float = 0.0;
2753}
2754#endif
2755
2756/*
2757 * "count()" function
2758 */
2759 static void
2760f_count(typval_T *argvars, typval_T *rettv)
2761{
2762 long n = 0;
2763 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002764 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002765
Bram Moolenaar9966b212017-07-28 16:46:57 +02002766 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002767 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002768
2769 if (argvars[0].v_type == VAR_STRING)
2770 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002771 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002772 char_u *p = argvars[0].vval.v_string;
2773 char_u *next;
2774
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002775 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002776 {
2777 if (ic)
2778 {
2779 size_t len = STRLEN(expr);
2780
2781 while (*p != NUL)
2782 {
2783 if (MB_STRNICMP(p, expr, len) == 0)
2784 {
2785 ++n;
2786 p += len;
2787 }
2788 else
2789 MB_PTR_ADV(p);
2790 }
2791 }
2792 else
2793 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2794 != NULL)
2795 {
2796 ++n;
2797 p = next + STRLEN(expr);
2798 }
2799 }
2800
2801 }
2802 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002803 {
2804 listitem_T *li;
2805 list_T *l;
2806 long idx;
2807
2808 if ((l = argvars[0].vval.v_list) != NULL)
2809 {
2810 li = l->lv_first;
2811 if (argvars[2].v_type != VAR_UNKNOWN)
2812 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002813 if (argvars[3].v_type != VAR_UNKNOWN)
2814 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002815 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002816 if (!error)
2817 {
2818 li = list_find(l, idx);
2819 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002820 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002821 }
2822 }
2823 if (error)
2824 li = NULL;
2825 }
2826
2827 for ( ; li != NULL; li = li->li_next)
2828 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2829 ++n;
2830 }
2831 }
2832 else if (argvars[0].v_type == VAR_DICT)
2833 {
2834 int todo;
2835 dict_T *d;
2836 hashitem_T *hi;
2837
2838 if ((d = argvars[0].vval.v_dict) != NULL)
2839 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 if (argvars[2].v_type != VAR_UNKNOWN)
2841 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002842 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002843 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002844 }
2845
2846 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2847 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2848 {
2849 if (!HASHITEM_EMPTY(hi))
2850 {
2851 --todo;
2852 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2853 ++n;
2854 }
2855 }
2856 }
2857 }
2858 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002859 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002860 rettv->vval.v_number = n;
2861}
2862
2863/*
2864 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2865 *
2866 * Checks the existence of a cscope connection.
2867 */
2868 static void
2869f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2870{
2871#ifdef FEAT_CSCOPE
2872 int num = 0;
2873 char_u *dbpath = NULL;
2874 char_u *prepend = NULL;
2875 char_u buf[NUMBUFLEN];
2876
2877 if (argvars[0].v_type != VAR_UNKNOWN
2878 && argvars[1].v_type != VAR_UNKNOWN)
2879 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002880 num = (int)tv_get_number(&argvars[0]);
2881 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002882 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002883 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002884 }
2885
2886 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2887#endif
2888}
2889
2890/*
2891 * "cursor(lnum, col)" function, or
2892 * "cursor(list)"
2893 *
2894 * Moves the cursor to the specified line and column.
2895 * Returns 0 when the position could be set, -1 otherwise.
2896 */
2897 static void
2898f_cursor(typval_T *argvars, typval_T *rettv)
2899{
2900 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002901 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002902 int set_curswant = TRUE;
2903
2904 rettv->vval.v_number = -1;
2905 if (argvars[1].v_type == VAR_UNKNOWN)
2906 {
2907 pos_T pos;
2908 colnr_T curswant = -1;
2909
2910 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2911 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002912 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002913 return;
2914 }
2915 line = pos.lnum;
2916 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002917 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002918 if (curswant >= 0)
2919 {
2920 curwin->w_curswant = curswant - 1;
2921 set_curswant = FALSE;
2922 }
2923 }
2924 else
2925 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002926 line = tv_get_lnum(argvars);
2927 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002928 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002929 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002930 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002931 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002932 return; /* type error; errmsg already given */
2933 if (line > 0)
2934 curwin->w_cursor.lnum = line;
2935 if (col > 0)
2936 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002937 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002938
2939 /* Make sure the cursor is in a valid position. */
2940 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002941 /* Correct cursor for multi-byte character. */
2942 if (has_mbyte)
2943 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002944
2945 curwin->w_set_curswant = set_curswant;
2946 rettv->vval.v_number = 0;
2947}
2948
Bram Moolenaar4f974752019-02-17 17:44:42 +01002949#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002950/*
2951 * "debugbreak()" function
2952 */
2953 static void
2954f_debugbreak(typval_T *argvars, typval_T *rettv)
2955{
2956 int pid;
2957
2958 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002959 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002960 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002961 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002962 else
2963 {
2964 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2965
2966 if (hProcess != NULL)
2967 {
2968 DebugBreakProcess(hProcess);
2969 CloseHandle(hProcess);
2970 rettv->vval.v_number = OK;
2971 }
2972 }
2973}
2974#endif
2975
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002976/*
2977 * "deepcopy()" function
2978 */
2979 static void
2980f_deepcopy(typval_T *argvars, typval_T *rettv)
2981{
2982 int noref = 0;
2983 int copyID;
2984
2985 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002986 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002987 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002988 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002989 else
2990 {
2991 copyID = get_copyID();
2992 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2993 }
2994}
2995
2996/*
2997 * "delete()" function
2998 */
2999 static void
3000f_delete(typval_T *argvars, typval_T *rettv)
3001{
3002 char_u nbuf[NUMBUFLEN];
3003 char_u *name;
3004 char_u *flags;
3005
3006 rettv->vval.v_number = -1;
3007 if (check_restricted() || check_secure())
3008 return;
3009
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003010 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003011 if (name == NULL || *name == NUL)
3012 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003013 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003014 return;
3015 }
3016
3017 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003018 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003019 else
3020 flags = (char_u *)"";
3021
3022 if (*flags == NUL)
3023 /* delete a file */
3024 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
3025 else if (STRCMP(flags, "d") == 0)
3026 /* delete an empty directory */
3027 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
3028 else if (STRCMP(flags, "rf") == 0)
3029 /* delete a directory recursively */
3030 rettv->vval.v_number = delete_recursive(name);
3031 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003032 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003033}
3034
3035/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02003036 * "deletebufline()" function
3037 */
3038 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02003039f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02003040{
3041 buf_T *buf;
3042 linenr_T first, last;
3043 linenr_T lnum;
3044 long count;
3045 int is_curbuf;
3046 buf_T *curbuf_save = NULL;
3047 win_T *curwin_save = NULL;
3048 tabpage_T *tp;
3049 win_T *wp;
3050
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003051 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003052 if (buf == NULL)
3053 {
3054 rettv->vval.v_number = 1; /* FAIL */
3055 return;
3056 }
3057 is_curbuf = buf == curbuf;
3058
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003059 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003060 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003061 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003062 else
3063 last = first;
3064
3065 if (buf->b_ml.ml_mfp == NULL || first < 1
3066 || first > buf->b_ml.ml_line_count || last < first)
3067 {
3068 rettv->vval.v_number = 1; /* FAIL */
3069 return;
3070 }
3071
3072 if (!is_curbuf)
3073 {
3074 curbuf_save = curbuf;
3075 curwin_save = curwin;
3076 curbuf = buf;
3077 find_win_for_curbuf();
3078 }
3079 if (last > curbuf->b_ml.ml_line_count)
3080 last = curbuf->b_ml.ml_line_count;
3081 count = last - first + 1;
3082
3083 // When coming here from Insert mode, sync undo, so that this can be
3084 // undone separately from what was previously inserted.
3085 if (u_sync_once == 2)
3086 {
3087 u_sync_once = 1; // notify that u_sync() was called
3088 u_sync(TRUE);
3089 }
3090
3091 if (u_save(first - 1, last + 1) == FAIL)
3092 {
3093 rettv->vval.v_number = 1; /* FAIL */
3094 return;
3095 }
3096
3097 for (lnum = first; lnum <= last; ++lnum)
3098 ml_delete(first, TRUE);
3099
3100 FOR_ALL_TAB_WINDOWS(tp, wp)
3101 if (wp->w_buffer == buf)
3102 {
3103 if (wp->w_cursor.lnum > last)
3104 wp->w_cursor.lnum -= count;
3105 else if (wp->w_cursor.lnum> first)
3106 wp->w_cursor.lnum = first;
3107 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3108 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3109 }
3110 check_cursor_col();
3111 deleted_lines_mark(first, count);
3112
3113 if (!is_curbuf)
3114 {
3115 curbuf = curbuf_save;
3116 curwin = curwin_save;
3117 }
3118}
3119
3120/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003121 * "did_filetype()" function
3122 */
3123 static void
3124f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3125{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003126 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003127}
3128
3129/*
3130 * "diff_filler()" function
3131 */
3132 static void
3133f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3134{
3135#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003136 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003137#endif
3138}
3139
3140/*
3141 * "diff_hlID()" function
3142 */
3143 static void
3144f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3145{
3146#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003147 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003148 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003149 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003150 static int fnum = 0;
3151 static int change_start = 0;
3152 static int change_end = 0;
3153 static hlf_T hlID = (hlf_T)0;
3154 int filler_lines;
3155 int col;
3156
3157 if (lnum < 0) /* ignore type error in {lnum} arg */
3158 lnum = 0;
3159 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003160 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003161 || fnum != curbuf->b_fnum)
3162 {
3163 /* New line, buffer, change: need to get the values. */
3164 filler_lines = diff_check(curwin, lnum);
3165 if (filler_lines < 0)
3166 {
3167 if (filler_lines == -1)
3168 {
3169 change_start = MAXCOL;
3170 change_end = -1;
3171 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3172 hlID = HLF_ADD; /* added line */
3173 else
3174 hlID = HLF_CHD; /* changed line */
3175 }
3176 else
3177 hlID = HLF_ADD; /* added line */
3178 }
3179 else
3180 hlID = (hlf_T)0;
3181 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003182 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003183 fnum = curbuf->b_fnum;
3184 }
3185
3186 if (hlID == HLF_CHD || hlID == HLF_TXD)
3187 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003188 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003189 if (col >= change_start && col <= change_end)
3190 hlID = HLF_TXD; /* changed text */
3191 else
3192 hlID = HLF_CHD; /* changed line */
3193 }
3194 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3195#endif
3196}
3197
3198/*
3199 * "empty({expr})" function
3200 */
3201 static void
3202f_empty(typval_T *argvars, typval_T *rettv)
3203{
3204 int n = FALSE;
3205
3206 switch (argvars[0].v_type)
3207 {
3208 case VAR_STRING:
3209 case VAR_FUNC:
3210 n = argvars[0].vval.v_string == NULL
3211 || *argvars[0].vval.v_string == NUL;
3212 break;
3213 case VAR_PARTIAL:
3214 n = FALSE;
3215 break;
3216 case VAR_NUMBER:
3217 n = argvars[0].vval.v_number == 0;
3218 break;
3219 case VAR_FLOAT:
3220#ifdef FEAT_FLOAT
3221 n = argvars[0].vval.v_float == 0.0;
3222 break;
3223#endif
3224 case VAR_LIST:
3225 n = argvars[0].vval.v_list == NULL
3226 || argvars[0].vval.v_list->lv_first == NULL;
3227 break;
3228 case VAR_DICT:
3229 n = argvars[0].vval.v_dict == NULL
3230 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3231 break;
3232 case VAR_SPECIAL:
3233 n = argvars[0].vval.v_number != VVAL_TRUE;
3234 break;
3235
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003236 case VAR_BLOB:
3237 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003238 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3239 break;
3240
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003241 case VAR_JOB:
3242#ifdef FEAT_JOB_CHANNEL
3243 n = argvars[0].vval.v_job == NULL
3244 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3245 break;
3246#endif
3247 case VAR_CHANNEL:
3248#ifdef FEAT_JOB_CHANNEL
3249 n = argvars[0].vval.v_channel == NULL
3250 || !channel_is_open(argvars[0].vval.v_channel);
3251 break;
3252#endif
3253 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003254 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003255 n = TRUE;
3256 break;
3257 }
3258
3259 rettv->vval.v_number = n;
3260}
3261
3262/*
3263 * "escape({string}, {chars})" function
3264 */
3265 static void
3266f_escape(typval_T *argvars, typval_T *rettv)
3267{
3268 char_u buf[NUMBUFLEN];
3269
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003270 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3271 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003272 rettv->v_type = VAR_STRING;
3273}
3274
3275/*
3276 * "eval()" function
3277 */
3278 static void
3279f_eval(typval_T *argvars, typval_T *rettv)
3280{
3281 char_u *s, *p;
3282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003283 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003284 if (s != NULL)
3285 s = skipwhite(s);
3286
3287 p = s;
3288 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3289 {
3290 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003291 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003292 need_clr_eos = FALSE;
3293 rettv->v_type = VAR_NUMBER;
3294 rettv->vval.v_number = 0;
3295 }
3296 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003297 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003298}
3299
3300/*
3301 * "eventhandler()" function
3302 */
3303 static void
3304f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3305{
3306 rettv->vval.v_number = vgetc_busy;
3307}
3308
3309/*
3310 * "executable()" function
3311 */
3312 static void
3313f_executable(typval_T *argvars, typval_T *rettv)
3314{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003315 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003316
3317 /* Check in $PATH and also check directly if there is a directory name. */
3318 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3319 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3320}
3321
3322static garray_T redir_execute_ga;
3323
3324/*
3325 * Append "value[value_len]" to the execute() output.
3326 */
3327 void
3328execute_redir_str(char_u *value, int value_len)
3329{
3330 int len;
3331
3332 if (value_len == -1)
3333 len = (int)STRLEN(value); /* Append the entire string */
3334 else
3335 len = value_len; /* Append only "value_len" characters */
3336 if (ga_grow(&redir_execute_ga, len) == OK)
3337 {
3338 mch_memmove((char *)redir_execute_ga.ga_data
3339 + redir_execute_ga.ga_len, value, len);
3340 redir_execute_ga.ga_len += len;
3341 }
3342}
3343
3344/*
3345 * Get next line from a list.
3346 * Called by do_cmdline() to get the next line.
3347 * Returns allocated string, or NULL for end of function.
3348 */
3349
3350 static char_u *
3351get_list_line(
3352 int c UNUSED,
3353 void *cookie,
3354 int indent UNUSED)
3355{
3356 listitem_T **p = (listitem_T **)cookie;
3357 listitem_T *item = *p;
3358 char_u buf[NUMBUFLEN];
3359 char_u *s;
3360
3361 if (item == NULL)
3362 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003363 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003364 *p = item->li_next;
3365 return s == NULL ? NULL : vim_strsave(s);
3366}
3367
3368/*
3369 * "execute()" function
3370 */
3371 static void
3372f_execute(typval_T *argvars, typval_T *rettv)
3373{
3374 char_u *cmd = NULL;
3375 list_T *list = NULL;
3376 int save_msg_silent = msg_silent;
3377 int save_emsg_silent = emsg_silent;
3378 int save_emsg_noredir = emsg_noredir;
3379 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003380 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003381 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003382 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003383 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003384
3385 rettv->vval.v_string = NULL;
3386 rettv->v_type = VAR_STRING;
3387
3388 if (argvars[0].v_type == VAR_LIST)
3389 {
3390 list = argvars[0].vval.v_list;
3391 if (list == NULL || list->lv_first == NULL)
3392 /* empty list, no commands, empty output */
3393 return;
3394 ++list->lv_refcount;
3395 }
3396 else
3397 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003398 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003399 if (cmd == NULL)
3400 return;
3401 }
3402
3403 if (argvars[1].v_type != VAR_UNKNOWN)
3404 {
3405 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003406 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003407
3408 if (s == NULL)
3409 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003410 if (*s == NUL)
3411 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003412 if (STRNCMP(s, "silent", 6) == 0)
3413 ++msg_silent;
3414 if (STRCMP(s, "silent!") == 0)
3415 {
3416 emsg_silent = TRUE;
3417 emsg_noredir = TRUE;
3418 }
3419 }
3420 else
3421 ++msg_silent;
3422
3423 if (redir_execute)
3424 save_ga = redir_execute_ga;
3425 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3426 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003427 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003428 if (!echo_output)
3429 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003430
3431 if (cmd != NULL)
3432 do_cmdline_cmd(cmd);
3433 else
3434 {
3435 listitem_T *item = list->lv_first;
3436
3437 do_cmdline(NULL, get_list_line, (void *)&item,
3438 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3439 --list->lv_refcount;
3440 }
3441
Bram Moolenaard297f352017-01-29 20:31:21 +01003442 /* Need to append a NUL to the result. */
3443 if (ga_grow(&redir_execute_ga, 1) == OK)
3444 {
3445 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3446 rettv->vval.v_string = redir_execute_ga.ga_data;
3447 }
3448 else
3449 {
3450 ga_clear(&redir_execute_ga);
3451 rettv->vval.v_string = NULL;
3452 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003453 msg_silent = save_msg_silent;
3454 emsg_silent = save_emsg_silent;
3455 emsg_noredir = save_emsg_noredir;
3456
3457 redir_execute = save_redir_execute;
3458 if (redir_execute)
3459 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003460 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003461
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003462 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003463 if (echo_output)
3464 // When not working silently: put it in column zero. A following
3465 // "echon" will overwrite the message, unavoidably.
3466 msg_col = 0;
3467 else
3468 // When working silently: Put it back where it was, since nothing
3469 // should have been written.
3470 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003471}
3472
3473/*
3474 * "exepath()" function
3475 */
3476 static void
3477f_exepath(typval_T *argvars, typval_T *rettv)
3478{
3479 char_u *p = NULL;
3480
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003481 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003482 rettv->v_type = VAR_STRING;
3483 rettv->vval.v_string = p;
3484}
3485
3486/*
3487 * "exists()" function
3488 */
3489 static void
3490f_exists(typval_T *argvars, typval_T *rettv)
3491{
3492 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003493 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003494
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003495 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003496 if (*p == '$') /* environment variable */
3497 {
3498 /* first try "normal" environment variables (fast) */
3499 if (mch_getenv(p + 1) != NULL)
3500 n = TRUE;
3501 else
3502 {
3503 /* try expanding things like $VIM and ${HOME} */
3504 p = expand_env_save(p);
3505 if (p != NULL && *p != '$')
3506 n = TRUE;
3507 vim_free(p);
3508 }
3509 }
3510 else if (*p == '&' || *p == '+') /* option */
3511 {
3512 n = (get_option_tv(&p, NULL, TRUE) == OK);
3513 if (*skipwhite(p) != NUL)
3514 n = FALSE; /* trailing garbage */
3515 }
3516 else if (*p == '*') /* internal or user defined function */
3517 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003518 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003519 }
3520 else if (*p == ':')
3521 {
3522 n = cmd_exists(p + 1);
3523 }
3524 else if (*p == '#')
3525 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003526 if (p[1] == '#')
3527 n = autocmd_supported(p + 2);
3528 else
3529 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003530 }
3531 else /* internal variable */
3532 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003533 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003534 }
3535
3536 rettv->vval.v_number = n;
3537}
3538
3539#ifdef FEAT_FLOAT
3540/*
3541 * "exp()" function
3542 */
3543 static void
3544f_exp(typval_T *argvars, typval_T *rettv)
3545{
3546 float_T f = 0.0;
3547
3548 rettv->v_type = VAR_FLOAT;
3549 if (get_float_arg(argvars, &f) == OK)
3550 rettv->vval.v_float = exp(f);
3551 else
3552 rettv->vval.v_float = 0.0;
3553}
3554#endif
3555
3556/*
3557 * "expand()" function
3558 */
3559 static void
3560f_expand(typval_T *argvars, typval_T *rettv)
3561{
3562 char_u *s;
3563 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003564 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003565 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3566 expand_T xpc;
3567 int error = FALSE;
3568 char_u *result;
3569
3570 rettv->v_type = VAR_STRING;
3571 if (argvars[1].v_type != VAR_UNKNOWN
3572 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003573 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003574 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003575 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003576
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003577 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003578 if (*s == '%' || *s == '#' || *s == '<')
3579 {
3580 ++emsg_off;
3581 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3582 --emsg_off;
3583 if (rettv->v_type == VAR_LIST)
3584 {
3585 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3586 list_append_string(rettv->vval.v_list, result, -1);
3587 else
3588 vim_free(result);
3589 }
3590 else
3591 rettv->vval.v_string = result;
3592 }
3593 else
3594 {
3595 /* When the optional second argument is non-zero, don't remove matches
3596 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3597 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003598 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003599 options |= WILD_KEEP_ALL;
3600 if (!error)
3601 {
3602 ExpandInit(&xpc);
3603 xpc.xp_context = EXPAND_FILES;
3604 if (p_wic)
3605 options += WILD_ICASE;
3606 if (rettv->v_type == VAR_STRING)
3607 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3608 options, WILD_ALL);
3609 else if (rettv_list_alloc(rettv) != FAIL)
3610 {
3611 int i;
3612
3613 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3614 for (i = 0; i < xpc.xp_numfiles; i++)
3615 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3616 ExpandCleanup(&xpc);
3617 }
3618 }
3619 else
3620 rettv->vval.v_string = NULL;
3621 }
3622}
3623
3624/*
3625 * "extend(list, list [, idx])" function
3626 * "extend(dict, dict [, action])" function
3627 */
3628 static void
3629f_extend(typval_T *argvars, typval_T *rettv)
3630{
3631 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3632
3633 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3634 {
3635 list_T *l1, *l2;
3636 listitem_T *item;
3637 long before;
3638 int error = FALSE;
3639
3640 l1 = argvars[0].vval.v_list;
3641 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003642 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003643 && l2 != NULL)
3644 {
3645 if (argvars[2].v_type != VAR_UNKNOWN)
3646 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003647 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003648 if (error)
3649 return; /* type error; errmsg already given */
3650
3651 if (before == l1->lv_len)
3652 item = NULL;
3653 else
3654 {
3655 item = list_find(l1, before);
3656 if (item == NULL)
3657 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003658 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003659 return;
3660 }
3661 }
3662 }
3663 else
3664 item = NULL;
3665 list_extend(l1, l2, item);
3666
3667 copy_tv(&argvars[0], rettv);
3668 }
3669 }
3670 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3671 {
3672 dict_T *d1, *d2;
3673 char_u *action;
3674 int i;
3675
3676 d1 = argvars[0].vval.v_dict;
3677 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003678 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003679 && d2 != NULL)
3680 {
3681 /* Check the third argument. */
3682 if (argvars[2].v_type != VAR_UNKNOWN)
3683 {
3684 static char *(av[]) = {"keep", "force", "error"};
3685
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003686 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003687 if (action == NULL)
3688 return; /* type error; errmsg already given */
3689 for (i = 0; i < 3; ++i)
3690 if (STRCMP(action, av[i]) == 0)
3691 break;
3692 if (i == 3)
3693 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003694 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003695 return;
3696 }
3697 }
3698 else
3699 action = (char_u *)"force";
3700
3701 dict_extend(d1, d2, action);
3702
3703 copy_tv(&argvars[0], rettv);
3704 }
3705 }
3706 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003707 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003708}
3709
3710/*
3711 * "feedkeys()" function
3712 */
3713 static void
3714f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3715{
3716 int remap = TRUE;
3717 int insert = FALSE;
3718 char_u *keys, *flags;
3719 char_u nbuf[NUMBUFLEN];
3720 int typed = FALSE;
3721 int execute = FALSE;
3722 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003723 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003724 char_u *keys_esc;
3725
3726 /* This is not allowed in the sandbox. If the commands would still be
3727 * executed in the sandbox it would be OK, but it probably happens later,
3728 * when "sandbox" is no longer set. */
3729 if (check_secure())
3730 return;
3731
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003732 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003733
3734 if (argvars[1].v_type != VAR_UNKNOWN)
3735 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003736 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003737 for ( ; *flags != NUL; ++flags)
3738 {
3739 switch (*flags)
3740 {
3741 case 'n': remap = FALSE; break;
3742 case 'm': remap = TRUE; break;
3743 case 't': typed = TRUE; break;
3744 case 'i': insert = TRUE; break;
3745 case 'x': execute = TRUE; break;
3746 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003747 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003748 }
3749 }
3750 }
3751
3752 if (*keys != NUL || execute)
3753 {
3754 /* Need to escape K_SPECIAL and CSI before putting the string in the
3755 * typeahead buffer. */
3756 keys_esc = vim_strsave_escape_csi(keys);
3757 if (keys_esc != NULL)
3758 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003759 if (lowlevel)
3760 {
3761#ifdef USE_INPUT_BUF
3762 add_to_input_buf(keys, (int)STRLEN(keys));
3763#else
3764 emsg(_("E980: lowlevel input not supported"));
3765#endif
3766 }
3767 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003768 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003769 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003770 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003771 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003772#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003773 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003774#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003775 )
3776 typebuf_was_filled = TRUE;
3777 }
3778 vim_free(keys_esc);
3779
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003780 if (execute)
3781 {
3782 int save_msg_scroll = msg_scroll;
3783
3784 /* Avoid a 1 second delay when the keys start Insert mode. */
3785 msg_scroll = FALSE;
3786
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003787 if (!dangerous)
3788 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003789 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003790 if (!dangerous)
3791 --ex_normal_busy;
3792
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003793 msg_scroll |= save_msg_scroll;
3794 }
3795 }
3796 }
3797}
3798
3799/*
3800 * "filereadable()" function
3801 */
3802 static void
3803f_filereadable(typval_T *argvars, typval_T *rettv)
3804{
3805 int fd;
3806 char_u *p;
3807 int n;
3808
3809#ifndef O_NONBLOCK
3810# define O_NONBLOCK 0
3811#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003812 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003813 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3814 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3815 {
3816 n = TRUE;
3817 close(fd);
3818 }
3819 else
3820 n = FALSE;
3821
3822 rettv->vval.v_number = n;
3823}
3824
3825/*
3826 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3827 * rights to write into.
3828 */
3829 static void
3830f_filewritable(typval_T *argvars, typval_T *rettv)
3831{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003832 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003833}
3834
3835 static void
3836findfilendir(
3837 typval_T *argvars UNUSED,
3838 typval_T *rettv,
3839 int find_what UNUSED)
3840{
3841#ifdef FEAT_SEARCHPATH
3842 char_u *fname;
3843 char_u *fresult = NULL;
3844 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3845 char_u *p;
3846 char_u pathbuf[NUMBUFLEN];
3847 int count = 1;
3848 int first = TRUE;
3849 int error = FALSE;
3850#endif
3851
3852 rettv->vval.v_string = NULL;
3853 rettv->v_type = VAR_STRING;
3854
3855#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003856 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003857
3858 if (argvars[1].v_type != VAR_UNKNOWN)
3859 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003860 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003861 if (p == NULL)
3862 error = TRUE;
3863 else
3864 {
3865 if (*p != NUL)
3866 path = p;
3867
3868 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003869 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003870 }
3871 }
3872
3873 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3874 error = TRUE;
3875
3876 if (*fname != NUL && !error)
3877 {
3878 do
3879 {
3880 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3881 vim_free(fresult);
3882 fresult = find_file_in_path_option(first ? fname : NULL,
3883 first ? (int)STRLEN(fname) : 0,
3884 0, first, path,
3885 find_what,
3886 curbuf->b_ffname,
3887 find_what == FINDFILE_DIR
3888 ? (char_u *)"" : curbuf->b_p_sua);
3889 first = FALSE;
3890
3891 if (fresult != NULL && rettv->v_type == VAR_LIST)
3892 list_append_string(rettv->vval.v_list, fresult, -1);
3893
3894 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3895 }
3896
3897 if (rettv->v_type == VAR_STRING)
3898 rettv->vval.v_string = fresult;
3899#endif
3900}
3901
3902/*
3903 * "filter()" function
3904 */
3905 static void
3906f_filter(typval_T *argvars, typval_T *rettv)
3907{
3908 filter_map(argvars, rettv, FALSE);
3909}
3910
3911/*
3912 * "finddir({fname}[, {path}[, {count}]])" function
3913 */
3914 static void
3915f_finddir(typval_T *argvars, typval_T *rettv)
3916{
3917 findfilendir(argvars, rettv, FINDFILE_DIR);
3918}
3919
3920/*
3921 * "findfile({fname}[, {path}[, {count}]])" function
3922 */
3923 static void
3924f_findfile(typval_T *argvars, typval_T *rettv)
3925{
3926 findfilendir(argvars, rettv, FINDFILE_FILE);
3927}
3928
3929#ifdef FEAT_FLOAT
3930/*
3931 * "float2nr({float})" function
3932 */
3933 static void
3934f_float2nr(typval_T *argvars, typval_T *rettv)
3935{
3936 float_T f = 0.0;
3937
3938 if (get_float_arg(argvars, &f) == OK)
3939 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003940 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003941 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003942 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003943 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003944 else
3945 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003946 }
3947}
3948
3949/*
3950 * "floor({float})" function
3951 */
3952 static void
3953f_floor(typval_T *argvars, typval_T *rettv)
3954{
3955 float_T f = 0.0;
3956
3957 rettv->v_type = VAR_FLOAT;
3958 if (get_float_arg(argvars, &f) == OK)
3959 rettv->vval.v_float = floor(f);
3960 else
3961 rettv->vval.v_float = 0.0;
3962}
3963
3964/*
3965 * "fmod()" function
3966 */
3967 static void
3968f_fmod(typval_T *argvars, typval_T *rettv)
3969{
3970 float_T fx = 0.0, fy = 0.0;
3971
3972 rettv->v_type = VAR_FLOAT;
3973 if (get_float_arg(argvars, &fx) == OK
3974 && get_float_arg(&argvars[1], &fy) == OK)
3975 rettv->vval.v_float = fmod(fx, fy);
3976 else
3977 rettv->vval.v_float = 0.0;
3978}
3979#endif
3980
3981/*
3982 * "fnameescape({string})" function
3983 */
3984 static void
3985f_fnameescape(typval_T *argvars, typval_T *rettv)
3986{
3987 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003988 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003989 rettv->v_type = VAR_STRING;
3990}
3991
3992/*
3993 * "fnamemodify({fname}, {mods})" function
3994 */
3995 static void
3996f_fnamemodify(typval_T *argvars, typval_T *rettv)
3997{
3998 char_u *fname;
3999 char_u *mods;
4000 int usedlen = 0;
4001 int len;
4002 char_u *fbuf = NULL;
4003 char_u buf[NUMBUFLEN];
4004
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004005 fname = tv_get_string_chk(&argvars[0]);
4006 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004007 if (fname == NULL || mods == NULL)
4008 fname = NULL;
4009 else
4010 {
4011 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02004012 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004013 }
4014
4015 rettv->v_type = VAR_STRING;
4016 if (fname == NULL)
4017 rettv->vval.v_string = NULL;
4018 else
4019 rettv->vval.v_string = vim_strnsave(fname, len);
4020 vim_free(fbuf);
4021}
4022
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004023/*
4024 * "foldclosed()" function
4025 */
4026 static void
4027foldclosed_both(
4028 typval_T *argvars UNUSED,
4029 typval_T *rettv,
4030 int end UNUSED)
4031{
4032#ifdef FEAT_FOLDING
4033 linenr_T lnum;
4034 linenr_T first, last;
4035
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004036 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004037 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4038 {
4039 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
4040 {
4041 if (end)
4042 rettv->vval.v_number = (varnumber_T)last;
4043 else
4044 rettv->vval.v_number = (varnumber_T)first;
4045 return;
4046 }
4047 }
4048#endif
4049 rettv->vval.v_number = -1;
4050}
4051
4052/*
4053 * "foldclosed()" function
4054 */
4055 static void
4056f_foldclosed(typval_T *argvars, typval_T *rettv)
4057{
4058 foldclosed_both(argvars, rettv, FALSE);
4059}
4060
4061/*
4062 * "foldclosedend()" function
4063 */
4064 static void
4065f_foldclosedend(typval_T *argvars, typval_T *rettv)
4066{
4067 foldclosed_both(argvars, rettv, TRUE);
4068}
4069
4070/*
4071 * "foldlevel()" function
4072 */
4073 static void
4074f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4075{
4076#ifdef FEAT_FOLDING
4077 linenr_T lnum;
4078
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004079 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004080 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4081 rettv->vval.v_number = foldLevel(lnum);
4082#endif
4083}
4084
4085/*
4086 * "foldtext()" function
4087 */
4088 static void
4089f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4090{
4091#ifdef FEAT_FOLDING
4092 linenr_T foldstart;
4093 linenr_T foldend;
4094 char_u *dashes;
4095 linenr_T lnum;
4096 char_u *s;
4097 char_u *r;
4098 int len;
4099 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004100 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004101#endif
4102
4103 rettv->v_type = VAR_STRING;
4104 rettv->vval.v_string = NULL;
4105#ifdef FEAT_FOLDING
4106 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4107 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4108 dashes = get_vim_var_str(VV_FOLDDASHES);
4109 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4110 && dashes != NULL)
4111 {
4112 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004113 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004114 if (!linewhite(lnum))
4115 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004116
4117 /* Find interesting text in this line. */
4118 s = skipwhite(ml_get(lnum));
4119 /* skip C comment-start */
4120 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4121 {
4122 s = skipwhite(s + 2);
4123 if (*skipwhite(s) == NUL
4124 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4125 {
4126 s = skipwhite(ml_get(lnum + 1));
4127 if (*s == '*')
4128 s = skipwhite(s + 1);
4129 }
4130 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004131 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004132 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004133 r = alloc((unsigned)(STRLEN(txt)
4134 + STRLEN(dashes) /* for %s */
4135 + 20 /* for %3ld */
4136 + STRLEN(s))); /* concatenated */
4137 if (r != NULL)
4138 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004139 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004140 len = (int)STRLEN(r);
4141 STRCAT(r, s);
4142 /* remove 'foldmarker' and 'commentstring' */
4143 foldtext_cleanup(r + len);
4144 rettv->vval.v_string = r;
4145 }
4146 }
4147#endif
4148}
4149
4150/*
4151 * "foldtextresult(lnum)" function
4152 */
4153 static void
4154f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4155{
4156#ifdef FEAT_FOLDING
4157 linenr_T lnum;
4158 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004159 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004160 foldinfo_T foldinfo;
4161 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004162 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004163#endif
4164
4165 rettv->v_type = VAR_STRING;
4166 rettv->vval.v_string = NULL;
4167#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004168 if (entered)
4169 return; /* reject recursive use */
4170 entered = TRUE;
4171
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004172 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004173 /* treat illegal types and illegal string values for {lnum} the same */
4174 if (lnum < 0)
4175 lnum = 0;
4176 fold_count = foldedCount(curwin, lnum, &foldinfo);
4177 if (fold_count > 0)
4178 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004179 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4180 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004181 if (text == buf)
4182 text = vim_strsave(text);
4183 rettv->vval.v_string = text;
4184 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004185
4186 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004187#endif
4188}
4189
4190/*
4191 * "foreground()" function
4192 */
4193 static void
4194f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4195{
4196#ifdef FEAT_GUI
4197 if (gui.in_use)
4198 gui_mch_set_foreground();
4199#else
Bram Moolenaar4f974752019-02-17 17:44:42 +01004200# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004201 win32_set_foreground();
4202# endif
4203#endif
4204}
4205
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004206 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004207common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004208{
4209 char_u *s;
4210 char_u *name;
4211 int use_string = FALSE;
4212 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004213 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004214
4215 if (argvars[0].v_type == VAR_FUNC)
4216 {
4217 /* function(MyFunc, [arg], dict) */
4218 s = argvars[0].vval.v_string;
4219 }
4220 else if (argvars[0].v_type == VAR_PARTIAL
4221 && argvars[0].vval.v_partial != NULL)
4222 {
4223 /* function(dict.MyFunc, [arg]) */
4224 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004225 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004226 }
4227 else
4228 {
4229 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004230 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004231 use_string = TRUE;
4232 }
4233
Bram Moolenaar843b8842016-08-21 14:36:15 +02004234 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004235 {
4236 name = s;
4237 trans_name = trans_function_name(&name, FALSE,
4238 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4239 if (*name != NUL)
4240 s = NULL;
4241 }
4242
Bram Moolenaar843b8842016-08-21 14:36:15 +02004243 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4244 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004245 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004246 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004247 else if (trans_name != NULL && (is_funcref
4248 ? find_func(trans_name) == NULL
4249 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004250 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004251 else
4252 {
4253 int dict_idx = 0;
4254 int arg_idx = 0;
4255 list_T *list = NULL;
4256
4257 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4258 {
4259 char sid_buf[25];
4260 int off = *s == 's' ? 2 : 5;
4261
4262 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4263 * also be called from another script. Using trans_function_name()
4264 * would also work, but some plugins depend on the name being
4265 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004266 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004267 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4268 if (name != NULL)
4269 {
4270 STRCPY(name, sid_buf);
4271 STRCAT(name, s + off);
4272 }
4273 }
4274 else
4275 name = vim_strsave(s);
4276
4277 if (argvars[1].v_type != VAR_UNKNOWN)
4278 {
4279 if (argvars[2].v_type != VAR_UNKNOWN)
4280 {
4281 /* function(name, [args], dict) */
4282 arg_idx = 1;
4283 dict_idx = 2;
4284 }
4285 else if (argvars[1].v_type == VAR_DICT)
4286 /* function(name, dict) */
4287 dict_idx = 1;
4288 else
4289 /* function(name, [args]) */
4290 arg_idx = 1;
4291 if (dict_idx > 0)
4292 {
4293 if (argvars[dict_idx].v_type != VAR_DICT)
4294 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004295 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004296 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004297 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004298 }
4299 if (argvars[dict_idx].vval.v_dict == NULL)
4300 dict_idx = 0;
4301 }
4302 if (arg_idx > 0)
4303 {
4304 if (argvars[arg_idx].v_type != VAR_LIST)
4305 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004306 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004307 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004308 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004309 }
4310 list = argvars[arg_idx].vval.v_list;
4311 if (list == NULL || list->lv_len == 0)
4312 arg_idx = 0;
4313 }
4314 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004315 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004316 {
4317 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4318
4319 /* result is a VAR_PARTIAL */
4320 if (pt == NULL)
4321 vim_free(name);
4322 else
4323 {
4324 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4325 {
4326 listitem_T *li;
4327 int i = 0;
4328 int arg_len = 0;
4329 int lv_len = 0;
4330
4331 if (arg_pt != NULL)
4332 arg_len = arg_pt->pt_argc;
4333 if (list != NULL)
4334 lv_len = list->lv_len;
4335 pt->pt_argc = arg_len + lv_len;
4336 pt->pt_argv = (typval_T *)alloc(
4337 sizeof(typval_T) * pt->pt_argc);
4338 if (pt->pt_argv == NULL)
4339 {
4340 vim_free(pt);
4341 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004342 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004343 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004344 for (i = 0; i < arg_len; i++)
4345 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4346 if (lv_len > 0)
4347 for (li = list->lv_first; li != NULL;
4348 li = li->li_next)
4349 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004350 }
4351
4352 /* For "function(dict.func, [], dict)" and "func" is a partial
4353 * use "dict". That is backwards compatible. */
4354 if (dict_idx > 0)
4355 {
4356 /* The dict is bound explicitly, pt_auto is FALSE. */
4357 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4358 ++pt->pt_dict->dv_refcount;
4359 }
4360 else if (arg_pt != NULL)
4361 {
4362 /* If the dict was bound automatically the result is also
4363 * bound automatically. */
4364 pt->pt_dict = arg_pt->pt_dict;
4365 pt->pt_auto = arg_pt->pt_auto;
4366 if (pt->pt_dict != NULL)
4367 ++pt->pt_dict->dv_refcount;
4368 }
4369
4370 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004371 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4372 {
4373 pt->pt_func = arg_pt->pt_func;
4374 func_ptr_ref(pt->pt_func);
4375 vim_free(name);
4376 }
4377 else if (is_funcref)
4378 {
4379 pt->pt_func = find_func(trans_name);
4380 func_ptr_ref(pt->pt_func);
4381 vim_free(name);
4382 }
4383 else
4384 {
4385 pt->pt_name = name;
4386 func_ref(name);
4387 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004388 }
4389 rettv->v_type = VAR_PARTIAL;
4390 rettv->vval.v_partial = pt;
4391 }
4392 else
4393 {
4394 /* result is a VAR_FUNC */
4395 rettv->v_type = VAR_FUNC;
4396 rettv->vval.v_string = name;
4397 func_ref(name);
4398 }
4399 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004400theend:
4401 vim_free(trans_name);
4402}
4403
4404/*
4405 * "funcref()" function
4406 */
4407 static void
4408f_funcref(typval_T *argvars, typval_T *rettv)
4409{
4410 common_function(argvars, rettv, TRUE);
4411}
4412
4413/*
4414 * "function()" function
4415 */
4416 static void
4417f_function(typval_T *argvars, typval_T *rettv)
4418{
4419 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004420}
4421
4422/*
4423 * "garbagecollect()" function
4424 */
4425 static void
4426f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4427{
4428 /* This is postponed until we are back at the toplevel, because we may be
4429 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4430 want_garbage_collect = TRUE;
4431
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004432 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004433 garbage_collect_at_exit = TRUE;
4434}
4435
4436/*
4437 * "get()" function
4438 */
4439 static void
4440f_get(typval_T *argvars, typval_T *rettv)
4441{
4442 listitem_T *li;
4443 list_T *l;
4444 dictitem_T *di;
4445 dict_T *d;
4446 typval_T *tv = NULL;
4447
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004448 if (argvars[0].v_type == VAR_BLOB)
4449 {
4450 int error = FALSE;
4451 int idx = tv_get_number_chk(&argvars[1], &error);
4452
4453 if (!error)
4454 {
4455 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004456 if (idx < 0)
4457 idx = blob_len(argvars[0].vval.v_blob) + idx;
4458 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4459 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004460 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004461 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004462 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004463 tv = rettv;
4464 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004465 }
4466 }
4467 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004468 {
4469 if ((l = argvars[0].vval.v_list) != NULL)
4470 {
4471 int error = FALSE;
4472
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004473 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004474 if (!error && li != NULL)
4475 tv = &li->li_tv;
4476 }
4477 }
4478 else if (argvars[0].v_type == VAR_DICT)
4479 {
4480 if ((d = argvars[0].vval.v_dict) != NULL)
4481 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004482 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004483 if (di != NULL)
4484 tv = &di->di_tv;
4485 }
4486 }
4487 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4488 {
4489 partial_T *pt;
4490 partial_T fref_pt;
4491
4492 if (argvars[0].v_type == VAR_PARTIAL)
4493 pt = argvars[0].vval.v_partial;
4494 else
4495 {
4496 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4497 fref_pt.pt_name = argvars[0].vval.v_string;
4498 pt = &fref_pt;
4499 }
4500
4501 if (pt != NULL)
4502 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004503 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004504 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004505
4506 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4507 {
4508 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004509 n = partial_name(pt);
4510 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004511 rettv->vval.v_string = NULL;
4512 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004513 {
4514 rettv->vval.v_string = vim_strsave(n);
4515 if (rettv->v_type == VAR_FUNC)
4516 func_ref(rettv->vval.v_string);
4517 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004518 }
4519 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004520 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004521 else if (STRCMP(what, "args") == 0)
4522 {
4523 rettv->v_type = VAR_LIST;
4524 if (rettv_list_alloc(rettv) == OK)
4525 {
4526 int i;
4527
4528 for (i = 0; i < pt->pt_argc; ++i)
4529 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4530 }
4531 }
4532 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004533 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004534 return;
4535 }
4536 }
4537 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004538 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004539
4540 if (tv == NULL)
4541 {
4542 if (argvars[2].v_type != VAR_UNKNOWN)
4543 copy_tv(&argvars[2], rettv);
4544 }
4545 else
4546 copy_tv(tv, rettv);
4547}
4548
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004549/*
4550 * Returns buffer options, variables and other attributes in a dictionary.
4551 */
4552 static dict_T *
4553get_buffer_info(buf_T *buf)
4554{
4555 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004556 tabpage_T *tp;
4557 win_T *wp;
4558 list_T *windows;
4559
4560 dict = dict_alloc();
4561 if (dict == NULL)
4562 return NULL;
4563
Bram Moolenaare0be1672018-07-08 16:50:37 +02004564 dict_add_number(dict, "bufnr", buf->b_fnum);
4565 dict_add_string(dict, "name", buf->b_ffname);
4566 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4567 : buflist_findlnum(buf));
4568 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4569 dict_add_number(dict, "listed", buf->b_p_bl);
4570 dict_add_number(dict, "changed", bufIsChanged(buf));
4571 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4572 dict_add_number(dict, "hidden",
4573 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004574
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004575 /* Get a reference to buffer variables */
4576 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004577
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004578 /* List of windows displaying this buffer */
4579 windows = list_alloc();
4580 if (windows != NULL)
4581 {
4582 FOR_ALL_TAB_WINDOWS(tp, wp)
4583 if (wp->w_buffer == buf)
4584 list_append_number(windows, (varnumber_T)wp->w_id);
4585 dict_add_list(dict, "windows", windows);
4586 }
4587
4588#ifdef FEAT_SIGNS
4589 if (buf->b_signlist != NULL)
4590 {
4591 /* List of signs placed in this buffer */
4592 list_T *signs = list_alloc();
4593 if (signs != NULL)
4594 {
4595 get_buffer_signs(buf, signs);
4596 dict_add_list(dict, "signs", signs);
4597 }
4598 }
4599#endif
4600
4601 return dict;
4602}
4603
4604/*
4605 * "getbufinfo()" function
4606 */
4607 static void
4608f_getbufinfo(typval_T *argvars, typval_T *rettv)
4609{
4610 buf_T *buf = NULL;
4611 buf_T *argbuf = NULL;
4612 dict_T *d;
4613 int filtered = FALSE;
4614 int sel_buflisted = FALSE;
4615 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004616 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004617
4618 if (rettv_list_alloc(rettv) != OK)
4619 return;
4620
4621 /* List of all the buffers or selected buffers */
4622 if (argvars[0].v_type == VAR_DICT)
4623 {
4624 dict_T *sel_d = argvars[0].vval.v_dict;
4625
4626 if (sel_d != NULL)
4627 {
4628 dictitem_T *di;
4629
4630 filtered = TRUE;
4631
4632 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004633 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004634 sel_buflisted = TRUE;
4635
4636 di = dict_find(sel_d, (char_u *)"bufloaded", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004637 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004638 sel_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004639
4640 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004641 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004642 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004643 }
4644 }
4645 else if (argvars[0].v_type != VAR_UNKNOWN)
4646 {
4647 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004648 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004649 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004650 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004651 --emsg_off;
4652 if (argbuf == NULL)
4653 return;
4654 }
4655
4656 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004657 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004658 {
4659 if (argbuf != NULL && argbuf != buf)
4660 continue;
4661 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004662 || (sel_buflisted && !buf->b_p_bl)
4663 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004664 continue;
4665
4666 d = get_buffer_info(buf);
4667 if (d != NULL)
4668 list_append_dict(rettv->vval.v_list, d);
4669 if (argbuf != NULL)
4670 return;
4671 }
4672}
4673
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004674/*
4675 * Get line or list of lines from buffer "buf" into "rettv".
4676 * Return a range (from start to end) of lines in rettv from the specified
4677 * buffer.
4678 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4679 */
4680 static void
4681get_buffer_lines(
4682 buf_T *buf,
4683 linenr_T start,
4684 linenr_T end,
4685 int retlist,
4686 typval_T *rettv)
4687{
4688 char_u *p;
4689
4690 rettv->v_type = VAR_STRING;
4691 rettv->vval.v_string = NULL;
4692 if (retlist && rettv_list_alloc(rettv) == FAIL)
4693 return;
4694
4695 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4696 return;
4697
4698 if (!retlist)
4699 {
4700 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4701 p = ml_get_buf(buf, start, FALSE);
4702 else
4703 p = (char_u *)"";
4704 rettv->vval.v_string = vim_strsave(p);
4705 }
4706 else
4707 {
4708 if (end < start)
4709 return;
4710
4711 if (start < 1)
4712 start = 1;
4713 if (end > buf->b_ml.ml_line_count)
4714 end = buf->b_ml.ml_line_count;
4715 while (start <= end)
4716 if (list_append_string(rettv->vval.v_list,
4717 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4718 break;
4719 }
4720}
4721
4722/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004723 * "getbufline()" function
4724 */
4725 static void
4726f_getbufline(typval_T *argvars, typval_T *rettv)
4727{
4728 linenr_T lnum;
4729 linenr_T end;
4730 buf_T *buf;
4731
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004732 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004733 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004734 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004735 --emsg_off;
4736
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004737 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004738 if (argvars[2].v_type == VAR_UNKNOWN)
4739 end = lnum;
4740 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004741 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004742
4743 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4744}
4745
4746/*
4747 * "getbufvar()" function
4748 */
4749 static void
4750f_getbufvar(typval_T *argvars, typval_T *rettv)
4751{
4752 buf_T *buf;
4753 buf_T *save_curbuf;
4754 char_u *varname;
4755 dictitem_T *v;
4756 int done = FALSE;
4757
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004758 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4759 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004760 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004761 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004762
4763 rettv->v_type = VAR_STRING;
4764 rettv->vval.v_string = NULL;
4765
4766 if (buf != NULL && varname != NULL)
4767 {
4768 /* set curbuf to be our buf, temporarily */
4769 save_curbuf = curbuf;
4770 curbuf = buf;
4771
Bram Moolenaar30567352016-08-27 21:25:44 +02004772 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004773 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004774 if (varname[1] == NUL)
4775 {
4776 /* get all buffer-local options in a dict */
4777 dict_T *opts = get_winbuf_options(TRUE);
4778
4779 if (opts != NULL)
4780 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004781 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004782 done = TRUE;
4783 }
4784 }
4785 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4786 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004787 done = TRUE;
4788 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004789 else
4790 {
4791 /* Look up the variable. */
4792 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4793 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4794 'b', varname, FALSE);
4795 if (v != NULL)
4796 {
4797 copy_tv(&v->di_tv, rettv);
4798 done = TRUE;
4799 }
4800 }
4801
4802 /* restore previous notion of curbuf */
4803 curbuf = save_curbuf;
4804 }
4805
4806 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4807 /* use the default value */
4808 copy_tv(&argvars[2], rettv);
4809
4810 --emsg_off;
4811}
4812
4813/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004814 * "getchangelist()" function
4815 */
4816 static void
4817f_getchangelist(typval_T *argvars, typval_T *rettv)
4818{
4819#ifdef FEAT_JUMPLIST
4820 buf_T *buf;
4821 int i;
4822 list_T *l;
4823 dict_T *d;
4824#endif
4825
4826 if (rettv_list_alloc(rettv) != OK)
4827 return;
4828
4829#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004830 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004831 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004832 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004833 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004834 if (buf == NULL)
4835 return;
4836
4837 l = list_alloc();
4838 if (l == NULL)
4839 return;
4840
4841 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4842 return;
4843 /*
4844 * The current window change list index tracks only the position in the
4845 * current buffer change list. For other buffers, use the change list
4846 * length as the current index.
4847 */
4848 list_append_number(rettv->vval.v_list,
4849 (varnumber_T)((buf == curwin->w_buffer)
4850 ? curwin->w_changelistidx : buf->b_changelistlen));
4851
4852 for (i = 0; i < buf->b_changelistlen; ++i)
4853 {
4854 if (buf->b_changelist[i].lnum == 0)
4855 continue;
4856 if ((d = dict_alloc()) == NULL)
4857 return;
4858 if (list_append_dict(l, d) == FAIL)
4859 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004860 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4861 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004862 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004863 }
4864#endif
4865}
4866/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004867 * "getchar()" function
4868 */
4869 static void
4870f_getchar(typval_T *argvars, typval_T *rettv)
4871{
4872 varnumber_T n;
4873 int error = FALSE;
4874
Bram Moolenaar84d93902018-09-11 20:10:20 +02004875#ifdef MESSAGE_QUEUE
4876 // vpeekc() used to check for messages, but that caused problems, invoking
4877 // a callback where it was not expected. Some plugins use getchar(1) in a
4878 // loop to await a message, therefore make sure we check for messages here.
4879 parse_queued_messages();
4880#endif
4881
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004882 /* Position the cursor. Needed after a message that ends in a space. */
4883 windgoto(msg_row, msg_col);
4884
4885 ++no_mapping;
4886 ++allow_keys;
4887 for (;;)
4888 {
4889 if (argvars[0].v_type == VAR_UNKNOWN)
4890 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004891 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004892 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004893 /* getchar(1): only check if char avail */
4894 n = vpeekc_any();
4895 else if (error || vpeekc_any() == NUL)
4896 /* illegal argument or getchar(0) and no char avail: return zero */
4897 n = 0;
4898 else
4899 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004900 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004901
4902 if (n == K_IGNORE)
4903 continue;
4904 break;
4905 }
4906 --no_mapping;
4907 --allow_keys;
4908
4909 set_vim_var_nr(VV_MOUSE_WIN, 0);
4910 set_vim_var_nr(VV_MOUSE_WINID, 0);
4911 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4912 set_vim_var_nr(VV_MOUSE_COL, 0);
4913
4914 rettv->vval.v_number = n;
4915 if (IS_SPECIAL(n) || mod_mask != 0)
4916 {
4917 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4918 int i = 0;
4919
4920 /* Turn a special key into three bytes, plus modifier. */
4921 if (mod_mask != 0)
4922 {
4923 temp[i++] = K_SPECIAL;
4924 temp[i++] = KS_MODIFIER;
4925 temp[i++] = mod_mask;
4926 }
4927 if (IS_SPECIAL(n))
4928 {
4929 temp[i++] = K_SPECIAL;
4930 temp[i++] = K_SECOND(n);
4931 temp[i++] = K_THIRD(n);
4932 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004933 else if (has_mbyte)
4934 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004935 else
4936 temp[i++] = n;
4937 temp[i++] = NUL;
4938 rettv->v_type = VAR_STRING;
4939 rettv->vval.v_string = vim_strsave(temp);
4940
4941#ifdef FEAT_MOUSE
4942 if (is_mouse_key(n))
4943 {
4944 int row = mouse_row;
4945 int col = mouse_col;
4946 win_T *win;
4947 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004948 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004949 int winnr = 1;
4950
4951 if (row >= 0 && col >= 0)
4952 {
4953 /* Find the window at the mouse coordinates and compute the
4954 * text position. */
4955 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004956 if (win == NULL)
4957 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004958 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004959 for (wp = firstwin; wp != win; wp = wp->w_next)
4960 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004961 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4962 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4963 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4964 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4965 }
4966 }
4967#endif
4968 }
4969}
4970
4971/*
4972 * "getcharmod()" function
4973 */
4974 static void
4975f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4976{
4977 rettv->vval.v_number = mod_mask;
4978}
4979
4980/*
4981 * "getcharsearch()" function
4982 */
4983 static void
4984f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4985{
4986 if (rettv_dict_alloc(rettv) != FAIL)
4987 {
4988 dict_T *dict = rettv->vval.v_dict;
4989
Bram Moolenaare0be1672018-07-08 16:50:37 +02004990 dict_add_string(dict, "char", last_csearch());
4991 dict_add_number(dict, "forward", last_csearch_forward());
4992 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004993 }
4994}
4995
4996/*
4997 * "getcmdline()" function
4998 */
4999 static void
5000f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
5001{
5002 rettv->v_type = VAR_STRING;
5003 rettv->vval.v_string = get_cmdline_str();
5004}
5005
5006/*
5007 * "getcmdpos()" function
5008 */
5009 static void
5010f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
5011{
5012 rettv->vval.v_number = get_cmdline_pos() + 1;
5013}
5014
5015/*
5016 * "getcmdtype()" function
5017 */
5018 static void
5019f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
5020{
5021 rettv->v_type = VAR_STRING;
5022 rettv->vval.v_string = alloc(2);
5023 if (rettv->vval.v_string != NULL)
5024 {
5025 rettv->vval.v_string[0] = get_cmdline_type();
5026 rettv->vval.v_string[1] = NUL;
5027 }
5028}
5029
5030/*
5031 * "getcmdwintype()" function
5032 */
5033 static void
5034f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
5035{
5036 rettv->v_type = VAR_STRING;
5037 rettv->vval.v_string = NULL;
5038#ifdef FEAT_CMDWIN
5039 rettv->vval.v_string = alloc(2);
5040 if (rettv->vval.v_string != NULL)
5041 {
5042 rettv->vval.v_string[0] = cmdwin_type;
5043 rettv->vval.v_string[1] = NUL;
5044 }
5045#endif
5046}
5047
5048#if defined(FEAT_CMDL_COMPL)
5049/*
5050 * "getcompletion()" function
5051 */
5052 static void
5053f_getcompletion(typval_T *argvars, typval_T *rettv)
5054{
5055 char_u *pat;
5056 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005057 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005058 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5059 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005061 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005062 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005063
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005064 if (p_wic)
5065 options |= WILD_ICASE;
5066
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005067 /* For filtered results, 'wildignore' is used */
5068 if (!filtered)
5069 options |= WILD_KEEP_ALL;
5070
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005071 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005072 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005073 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005074 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005075 if (xpc.xp_context == EXPAND_NOTHING)
5076 {
5077 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005078 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005079 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005080 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005081 return;
5082 }
5083
5084# if defined(FEAT_MENU)
5085 if (xpc.xp_context == EXPAND_MENUS)
5086 {
5087 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5088 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5089 }
5090# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005091#ifdef FEAT_CSCOPE
5092 if (xpc.xp_context == EXPAND_CSCOPE)
5093 {
5094 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5095 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5096 }
5097#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005098#ifdef FEAT_SIGNS
5099 if (xpc.xp_context == EXPAND_SIGN)
5100 {
5101 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5102 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5103 }
5104#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005105
5106 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5107 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5108 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005109 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005110
5111 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5112
5113 for (i = 0; i < xpc.xp_numfiles; i++)
5114 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5115 }
5116 vim_free(pat);
5117 ExpandCleanup(&xpc);
5118}
5119#endif
5120
5121/*
5122 * "getcwd()" function
5123 */
5124 static void
5125f_getcwd(typval_T *argvars, typval_T *rettv)
5126{
5127 win_T *wp = NULL;
5128 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005129 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005130
5131 rettv->v_type = VAR_STRING;
5132 rettv->vval.v_string = NULL;
5133
Bram Moolenaar54591292018-02-09 20:53:59 +01005134 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5135 global = TRUE;
5136 else
5137 wp = find_tabwin(&argvars[0], &argvars[1]);
5138
5139 if (wp != NULL && wp->w_localdir != NULL)
5140 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5141 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005142 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005143 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005144 rettv->vval.v_string = vim_strsave(globaldir);
5145 else
5146 {
5147 cwd = alloc(MAXPATHL);
5148 if (cwd != NULL)
5149 {
5150 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5151 rettv->vval.v_string = vim_strsave(cwd);
5152 vim_free(cwd);
5153 }
5154 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005155 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005156#ifdef BACKSLASH_IN_FILENAME
5157 if (rettv->vval.v_string != NULL)
5158 slash_adjust(rettv->vval.v_string);
5159#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005160}
5161
5162/*
5163 * "getfontname()" function
5164 */
5165 static void
5166f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5167{
5168 rettv->v_type = VAR_STRING;
5169 rettv->vval.v_string = NULL;
5170#ifdef FEAT_GUI
5171 if (gui.in_use)
5172 {
5173 GuiFont font;
5174 char_u *name = NULL;
5175
5176 if (argvars[0].v_type == VAR_UNKNOWN)
5177 {
5178 /* Get the "Normal" font. Either the name saved by
5179 * hl_set_font_name() or from the font ID. */
5180 font = gui.norm_font;
5181 name = hl_get_font_name();
5182 }
5183 else
5184 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005185 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005186 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5187 return;
5188 font = gui_mch_get_font(name, FALSE);
5189 if (font == NOFONT)
5190 return; /* Invalid font name, return empty string. */
5191 }
5192 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5193 if (argvars[0].v_type != VAR_UNKNOWN)
5194 gui_mch_free_font(font);
5195 }
5196#endif
5197}
5198
5199/*
5200 * "getfperm({fname})" function
5201 */
5202 static void
5203f_getfperm(typval_T *argvars, typval_T *rettv)
5204{
5205 char_u *fname;
5206 stat_T st;
5207 char_u *perm = NULL;
5208 char_u flags[] = "rwx";
5209 int i;
5210
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005211 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005212
5213 rettv->v_type = VAR_STRING;
5214 if (mch_stat((char *)fname, &st) >= 0)
5215 {
5216 perm = vim_strsave((char_u *)"---------");
5217 if (perm != NULL)
5218 {
5219 for (i = 0; i < 9; i++)
5220 {
5221 if (st.st_mode & (1 << (8 - i)))
5222 perm[i] = flags[i % 3];
5223 }
5224 }
5225 }
5226 rettv->vval.v_string = perm;
5227}
5228
5229/*
5230 * "getfsize({fname})" function
5231 */
5232 static void
5233f_getfsize(typval_T *argvars, typval_T *rettv)
5234{
5235 char_u *fname;
5236 stat_T st;
5237
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005238 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005239
5240 rettv->v_type = VAR_NUMBER;
5241
5242 if (mch_stat((char *)fname, &st) >= 0)
5243 {
5244 if (mch_isdir(fname))
5245 rettv->vval.v_number = 0;
5246 else
5247 {
5248 rettv->vval.v_number = (varnumber_T)st.st_size;
5249
5250 /* non-perfect check for overflow */
5251 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5252 rettv->vval.v_number = -2;
5253 }
5254 }
5255 else
5256 rettv->vval.v_number = -1;
5257}
5258
5259/*
5260 * "getftime({fname})" function
5261 */
5262 static void
5263f_getftime(typval_T *argvars, typval_T *rettv)
5264{
5265 char_u *fname;
5266 stat_T st;
5267
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005268 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005269
5270 if (mch_stat((char *)fname, &st) >= 0)
5271 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5272 else
5273 rettv->vval.v_number = -1;
5274}
5275
5276/*
5277 * "getftype({fname})" function
5278 */
5279 static void
5280f_getftype(typval_T *argvars, typval_T *rettv)
5281{
5282 char_u *fname;
5283 stat_T st;
5284 char_u *type = NULL;
5285 char *t;
5286
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005287 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288
5289 rettv->v_type = VAR_STRING;
5290 if (mch_lstat((char *)fname, &st) >= 0)
5291 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 if (S_ISREG(st.st_mode))
5293 t = "file";
5294 else if (S_ISDIR(st.st_mode))
5295 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296 else if (S_ISLNK(st.st_mode))
5297 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 else if (S_ISBLK(st.st_mode))
5299 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005300 else if (S_ISCHR(st.st_mode))
5301 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005302 else if (S_ISFIFO(st.st_mode))
5303 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005304 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005305 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005306 else
5307 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005308 type = vim_strsave((char_u *)t);
5309 }
5310 rettv->vval.v_string = type;
5311}
5312
5313/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005314 * "getjumplist()" function
5315 */
5316 static void
5317f_getjumplist(typval_T *argvars, typval_T *rettv)
5318{
5319#ifdef FEAT_JUMPLIST
5320 win_T *wp;
5321 int i;
5322 list_T *l;
5323 dict_T *d;
5324#endif
5325
5326 if (rettv_list_alloc(rettv) != OK)
5327 return;
5328
5329#ifdef FEAT_JUMPLIST
5330 wp = find_tabwin(&argvars[0], &argvars[1]);
5331 if (wp == NULL)
5332 return;
5333
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005334 cleanup_jumplist(wp, TRUE);
5335
Bram Moolenaar4f505882018-02-10 21:06:32 +01005336 l = list_alloc();
5337 if (l == NULL)
5338 return;
5339
5340 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5341 return;
5342 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5343
5344 for (i = 0; i < wp->w_jumplistlen; ++i)
5345 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005346 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5347 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005348 if ((d = dict_alloc()) == NULL)
5349 return;
5350 if (list_append_dict(l, d) == FAIL)
5351 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005352 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5353 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005354 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005355 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005356 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005357 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005358 }
5359#endif
5360}
5361
5362/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005363 * "getline(lnum, [end])" function
5364 */
5365 static void
5366f_getline(typval_T *argvars, typval_T *rettv)
5367{
5368 linenr_T lnum;
5369 linenr_T end;
5370 int retlist;
5371
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005372 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005373 if (argvars[1].v_type == VAR_UNKNOWN)
5374 {
5375 end = 0;
5376 retlist = FALSE;
5377 }
5378 else
5379 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005380 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005381 retlist = TRUE;
5382 }
5383
5384 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5385}
5386
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005387#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005388 static void
5389get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5390{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005391 if (what_arg->v_type == VAR_UNKNOWN)
5392 {
5393 if (rettv_list_alloc(rettv) == OK)
5394 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005395 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005396 }
5397 else
5398 {
5399 if (rettv_dict_alloc(rettv) == OK)
5400 if (is_qf || (wp != NULL))
5401 {
5402 if (what_arg->v_type == VAR_DICT)
5403 {
5404 dict_T *d = what_arg->vval.v_dict;
5405
5406 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005407 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005408 }
5409 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005410 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005411 }
5412 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005413}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005414#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005415
5416/*
5417 * "getloclist()" function
5418 */
5419 static void
5420f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5421{
5422#ifdef FEAT_QUICKFIX
5423 win_T *wp;
5424
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005425 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005426 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5427#endif
5428}
5429
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005430/*
5431 * "getmatches()" function
5432 */
5433 static void
5434f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5435{
5436#ifdef FEAT_SEARCH_EXTRA
5437 dict_T *dict;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005438 matchitem_T *cur;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005439 int i;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005440 win_T *win = get_optional_window(argvars, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005441
Bram Moolenaaraff74912019-03-30 18:11:49 +01005442 if (rettv_list_alloc(rettv) == FAIL || win == NULL)
5443 return;
5444
5445 cur = win->w_match_head;
5446 while (cur != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005447 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005448 dict = dict_alloc();
5449 if (dict == NULL)
5450 return;
5451 if (cur->match.regprog == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005452 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005453 /* match added with matchaddpos() */
5454 for (i = 0; i < MAXPOSMATCH; ++i)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005455 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005456 llpos_T *llpos;
5457 char buf[6];
5458 list_T *l;
5459
5460 llpos = &cur->pos.pos[i];
5461 if (llpos->lnum == 0)
5462 break;
5463 l = list_alloc();
5464 if (l == NULL)
5465 break;
5466 list_append_number(l, (varnumber_T)llpos->lnum);
5467 if (llpos->col > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005468 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005469 list_append_number(l, (varnumber_T)llpos->col);
5470 list_append_number(l, (varnumber_T)llpos->len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005471 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005472 sprintf(buf, "pos%d", i + 1);
5473 dict_add_list(dict, buf, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005474 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005475 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005476 else
5477 {
5478 dict_add_string(dict, "pattern", cur->pattern);
5479 }
5480 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5481 dict_add_number(dict, "priority", (long)cur->priority);
5482 dict_add_number(dict, "id", (long)cur->id);
5483# if defined(FEAT_CONCEAL)
5484 if (cur->conceal_char)
5485 {
5486 char_u buf[MB_MAXBYTES + 1];
5487
5488 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5489 dict_add_string(dict, "conceal", (char_u *)&buf);
5490 }
5491# endif
5492 list_append_dict(rettv->vval.v_list, dict);
5493 cur = cur->next;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005494 }
5495#endif
5496}
5497
5498/*
5499 * "getpid()" function
5500 */
5501 static void
5502f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5503{
5504 rettv->vval.v_number = mch_get_pid();
5505}
5506
5507 static void
5508getpos_both(
5509 typval_T *argvars,
5510 typval_T *rettv,
5511 int getcurpos)
5512{
5513 pos_T *fp;
5514 list_T *l;
5515 int fnum = -1;
5516
5517 if (rettv_list_alloc(rettv) == OK)
5518 {
5519 l = rettv->vval.v_list;
5520 if (getcurpos)
5521 fp = &curwin->w_cursor;
5522 else
5523 fp = var2fpos(&argvars[0], TRUE, &fnum);
5524 if (fnum != -1)
5525 list_append_number(l, (varnumber_T)fnum);
5526 else
5527 list_append_number(l, (varnumber_T)0);
5528 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5529 : (varnumber_T)0);
5530 list_append_number(l, (fp != NULL)
5531 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5532 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005533 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005534 (varnumber_T)0);
5535 if (getcurpos)
5536 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005537 int save_set_curswant = curwin->w_set_curswant;
5538 colnr_T save_curswant = curwin->w_curswant;
5539 colnr_T save_virtcol = curwin->w_virtcol;
5540
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005541 update_curswant();
5542 list_append_number(l, curwin->w_curswant == MAXCOL ?
5543 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005544
5545 // Do not change "curswant", as it is unexpected that a get
5546 // function has a side effect.
5547 if (save_set_curswant)
5548 {
5549 curwin->w_set_curswant = save_set_curswant;
5550 curwin->w_curswant = save_curswant;
5551 curwin->w_virtcol = save_virtcol;
5552 curwin->w_valid &= ~VALID_VIRTCOL;
5553 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005554 }
5555 }
5556 else
5557 rettv->vval.v_number = FALSE;
5558}
5559
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005560/*
5561 * "getcurpos()" function
5562 */
5563 static void
5564f_getcurpos(typval_T *argvars, typval_T *rettv)
5565{
5566 getpos_both(argvars, rettv, TRUE);
5567}
5568
5569/*
5570 * "getpos(string)" function
5571 */
5572 static void
5573f_getpos(typval_T *argvars, typval_T *rettv)
5574{
5575 getpos_both(argvars, rettv, FALSE);
5576}
5577
5578/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005579 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005580 */
5581 static void
5582f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5583{
5584#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005585 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005586#endif
5587}
5588
5589/*
5590 * "getreg()" function
5591 */
5592 static void
5593f_getreg(typval_T *argvars, typval_T *rettv)
5594{
5595 char_u *strregname;
5596 int regname;
5597 int arg2 = FALSE;
5598 int return_list = FALSE;
5599 int error = FALSE;
5600
5601 if (argvars[0].v_type != VAR_UNKNOWN)
5602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005603 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604 error = strregname == NULL;
5605 if (argvars[1].v_type != VAR_UNKNOWN)
5606 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005607 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005608 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005609 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005610 }
5611 }
5612 else
5613 strregname = get_vim_var_str(VV_REG);
5614
5615 if (error)
5616 return;
5617
5618 regname = (strregname == NULL ? '"' : *strregname);
5619 if (regname == 0)
5620 regname = '"';
5621
5622 if (return_list)
5623 {
5624 rettv->v_type = VAR_LIST;
5625 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5626 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5627 if (rettv->vval.v_list == NULL)
5628 (void)rettv_list_alloc(rettv);
5629 else
5630 ++rettv->vval.v_list->lv_refcount;
5631 }
5632 else
5633 {
5634 rettv->v_type = VAR_STRING;
5635 rettv->vval.v_string = get_reg_contents(regname,
5636 arg2 ? GREG_EXPR_SRC : 0);
5637 }
5638}
5639
5640/*
5641 * "getregtype()" function
5642 */
5643 static void
5644f_getregtype(typval_T *argvars, typval_T *rettv)
5645{
5646 char_u *strregname;
5647 int regname;
5648 char_u buf[NUMBUFLEN + 2];
5649 long reglen = 0;
5650
5651 if (argvars[0].v_type != VAR_UNKNOWN)
5652 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005653 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005654 if (strregname == NULL) /* type error; errmsg already given */
5655 {
5656 rettv->v_type = VAR_STRING;
5657 rettv->vval.v_string = NULL;
5658 return;
5659 }
5660 }
5661 else
5662 /* Default to v:register */
5663 strregname = get_vim_var_str(VV_REG);
5664
5665 regname = (strregname == NULL ? '"' : *strregname);
5666 if (regname == 0)
5667 regname = '"';
5668
5669 buf[0] = NUL;
5670 buf[1] = NUL;
5671 switch (get_reg_type(regname, &reglen))
5672 {
5673 case MLINE: buf[0] = 'V'; break;
5674 case MCHAR: buf[0] = 'v'; break;
5675 case MBLOCK:
5676 buf[0] = Ctrl_V;
5677 sprintf((char *)buf + 1, "%ld", reglen + 1);
5678 break;
5679 }
5680 rettv->v_type = VAR_STRING;
5681 rettv->vval.v_string = vim_strsave(buf);
5682}
5683
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005684/*
5685 * Returns information (variables, options, etc.) about a tab page
5686 * as a dictionary.
5687 */
5688 static dict_T *
5689get_tabpage_info(tabpage_T *tp, int tp_idx)
5690{
5691 win_T *wp;
5692 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005693 list_T *l;
5694
5695 dict = dict_alloc();
5696 if (dict == NULL)
5697 return NULL;
5698
Bram Moolenaare0be1672018-07-08 16:50:37 +02005699 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005700
5701 l = list_alloc();
5702 if (l != NULL)
5703 {
5704 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5705 wp; wp = wp->w_next)
5706 list_append_number(l, (varnumber_T)wp->w_id);
5707 dict_add_list(dict, "windows", l);
5708 }
5709
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005710 /* Make a reference to tabpage variables */
5711 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005712
5713 return dict;
5714}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005715
5716/*
5717 * "gettabinfo()" function
5718 */
5719 static void
5720f_gettabinfo(typval_T *argvars, typval_T *rettv)
5721{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005722 tabpage_T *tp, *tparg = NULL;
5723 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005724 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005725
5726 if (rettv_list_alloc(rettv) != OK)
5727 return;
5728
5729 if (argvars[0].v_type != VAR_UNKNOWN)
5730 {
5731 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005732 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005733 if (tparg == NULL)
5734 return;
5735 }
5736
5737 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005738 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005739 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005740 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005741 if (tparg != NULL && tp != tparg)
5742 continue;
5743 d = get_tabpage_info(tp, tpnr);
5744 if (d != NULL)
5745 list_append_dict(rettv->vval.v_list, d);
5746 if (tparg != NULL)
5747 return;
5748 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005749}
5750
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005751/*
5752 * "gettabvar()" function
5753 */
5754 static void
5755f_gettabvar(typval_T *argvars, typval_T *rettv)
5756{
5757 win_T *oldcurwin;
5758 tabpage_T *tp, *oldtabpage;
5759 dictitem_T *v;
5760 char_u *varname;
5761 int done = FALSE;
5762
5763 rettv->v_type = VAR_STRING;
5764 rettv->vval.v_string = NULL;
5765
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005766 varname = tv_get_string_chk(&argvars[1]);
5767 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005768 if (tp != NULL && varname != NULL)
5769 {
5770 /* Set tp to be our tabpage, temporarily. Also set the window to the
5771 * first window in the tabpage, otherwise the window is not valid. */
5772 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005773 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5774 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005775 {
5776 /* look up the variable */
5777 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5778 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5779 if (v != NULL)
5780 {
5781 copy_tv(&v->di_tv, rettv);
5782 done = TRUE;
5783 }
5784 }
5785
5786 /* restore previous notion of curwin */
5787 restore_win(oldcurwin, oldtabpage, TRUE);
5788 }
5789
5790 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5791 copy_tv(&argvars[2], rettv);
5792}
5793
5794/*
5795 * "gettabwinvar()" function
5796 */
5797 static void
5798f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5799{
5800 getwinvar(argvars, rettv, 1);
5801}
5802
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005803/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005804 * "gettagstack()" function
5805 */
5806 static void
5807f_gettagstack(typval_T *argvars, typval_T *rettv)
5808{
5809 win_T *wp = curwin; // default is current window
5810
5811 if (rettv_dict_alloc(rettv) != OK)
5812 return;
5813
5814 if (argvars[0].v_type != VAR_UNKNOWN)
5815 {
5816 wp = find_win_by_nr_or_id(&argvars[0]);
5817 if (wp == NULL)
5818 return;
5819 }
5820
5821 get_tagstack(wp, rettv->vval.v_dict);
5822}
5823
5824/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005825 * Returns information about a window as a dictionary.
5826 */
5827 static dict_T *
5828get_win_info(win_T *wp, short tpnr, short winnr)
5829{
5830 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005831
5832 dict = dict_alloc();
5833 if (dict == NULL)
5834 return NULL;
5835
Bram Moolenaare0be1672018-07-08 16:50:37 +02005836 dict_add_number(dict, "tabnr", tpnr);
5837 dict_add_number(dict, "winnr", winnr);
5838 dict_add_number(dict, "winid", wp->w_id);
5839 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005840 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005841 dict_add_number(dict, "topline", wp->w_topline);
5842 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005843#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005844 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005845#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005846 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005847 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005848 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005849
Bram Moolenaar69905d12017-08-13 18:14:47 +02005850#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005851 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005852#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005853#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005854 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5855 dict_add_number(dict, "loclist",
5856 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005857#endif
5858
Bram Moolenaar30567352016-08-27 21:25:44 +02005859 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005860 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005861
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005862 return dict;
5863}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005864
5865/*
5866 * "getwininfo()" function
5867 */
5868 static void
5869f_getwininfo(typval_T *argvars, typval_T *rettv)
5870{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005871 tabpage_T *tp;
5872 win_T *wp = NULL, *wparg = NULL;
5873 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005874 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005875
5876 if (rettv_list_alloc(rettv) != OK)
5877 return;
5878
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005879 if (argvars[0].v_type != VAR_UNKNOWN)
5880 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005881 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005882 if (wparg == NULL)
5883 return;
5884 }
5885
5886 /* Collect information about either all the windows across all the tab
5887 * pages or one particular window.
5888 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005889 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005890 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005891 tabnr++;
5892 winnr = 0;
5893 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005894 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005895 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005896 if (wparg != NULL && wp != wparg)
5897 continue;
5898 d = get_win_info(wp, tabnr, winnr);
5899 if (d != NULL)
5900 list_append_dict(rettv->vval.v_list, d);
5901 if (wparg != NULL)
5902 /* found information about a specific window */
5903 return;
5904 }
5905 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005906}
5907
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005908/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005909 * "win_findbuf()" function
5910 */
5911 static void
5912f_win_findbuf(typval_T *argvars, typval_T *rettv)
5913{
5914 if (rettv_list_alloc(rettv) != FAIL)
5915 win_findbuf(argvars, rettv->vval.v_list);
5916}
5917
5918/*
5919 * "win_getid()" function
5920 */
5921 static void
5922f_win_getid(typval_T *argvars, typval_T *rettv)
5923{
5924 rettv->vval.v_number = win_getid(argvars);
5925}
5926
5927/*
5928 * "win_gotoid()" function
5929 */
5930 static void
5931f_win_gotoid(typval_T *argvars, typval_T *rettv)
5932{
5933 rettv->vval.v_number = win_gotoid(argvars);
5934}
5935
5936/*
5937 * "win_id2tabwin()" function
5938 */
5939 static void
5940f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5941{
5942 if (rettv_list_alloc(rettv) != FAIL)
5943 win_id2tabwin(argvars, rettv->vval.v_list);
5944}
5945
5946/*
5947 * "win_id2win()" function
5948 */
5949 static void
5950f_win_id2win(typval_T *argvars, typval_T *rettv)
5951{
5952 rettv->vval.v_number = win_id2win(argvars);
5953}
5954
5955/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005956 * "win_screenpos()" function
5957 */
5958 static void
5959f_win_screenpos(typval_T *argvars, typval_T *rettv)
5960{
5961 win_T *wp;
5962
5963 if (rettv_list_alloc(rettv) == FAIL)
5964 return;
5965
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005966 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005967 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5968 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5969}
5970
5971/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005972 * "getwinpos({timeout})" function
5973 */
5974 static void
5975f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5976{
5977 int x = -1;
5978 int y = -1;
5979
5980 if (rettv_list_alloc(rettv) == FAIL)
5981 return;
5982#ifdef FEAT_GUI
5983 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005984 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005985# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5986 else
5987# endif
5988#endif
5989#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5990 {
5991 varnumber_T timeout = 100;
5992
5993 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005994 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005995 term_get_winpos(&x, &y, timeout);
5996 }
5997#endif
5998 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5999 list_append_number(rettv->vval.v_list, (varnumber_T)y);
6000}
6001
6002
6003/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006004 * "getwinposx()" function
6005 */
6006 static void
6007f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
6008{
6009 rettv->vval.v_number = -1;
6010#ifdef FEAT_GUI
6011 if (gui.in_use)
6012 {
6013 int x, y;
6014
6015 if (gui_mch_get_winpos(&x, &y) == OK)
6016 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02006017 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006018 }
6019#endif
6020#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6021 {
6022 int x, y;
6023
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006024 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006025 rettv->vval.v_number = x;
6026 }
6027#endif
6028}
6029
6030/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006031 * "getwinposy()" function
6032 */
6033 static void
6034f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
6035{
6036 rettv->vval.v_number = -1;
6037#ifdef FEAT_GUI
6038 if (gui.in_use)
6039 {
6040 int x, y;
6041
6042 if (gui_mch_get_winpos(&x, &y) == OK)
6043 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02006044 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006045 }
6046#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006047#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6048 {
6049 int x, y;
6050
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006051 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006052 rettv->vval.v_number = y;
6053 }
6054#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006055}
6056
6057/*
6058 * "getwinvar()" function
6059 */
6060 static void
6061f_getwinvar(typval_T *argvars, typval_T *rettv)
6062{
6063 getwinvar(argvars, rettv, 0);
6064}
6065
6066/*
6067 * "glob()" function
6068 */
6069 static void
6070f_glob(typval_T *argvars, typval_T *rettv)
6071{
6072 int options = WILD_SILENT|WILD_USE_NL;
6073 expand_T xpc;
6074 int error = FALSE;
6075
6076 /* When the optional second argument is non-zero, don't remove matches
6077 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6078 rettv->v_type = VAR_STRING;
6079 if (argvars[1].v_type != VAR_UNKNOWN)
6080 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006081 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006082 options |= WILD_KEEP_ALL;
6083 if (argvars[2].v_type != VAR_UNKNOWN)
6084 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006085 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006086 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006087 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 Moolenaar45cf6e92017-04-30 20:25:19 +02006140 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006141 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006142 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006143 flags |= WILD_ALLLINKS;
6144 }
6145 }
6146 if (file != NULL && !error)
6147 {
6148 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006149 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006150 if (rettv->v_type == VAR_STRING)
6151 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6152 else if (rettv_list_alloc(rettv) != FAIL)
6153 for (i = 0; i < ga.ga_len; ++i)
6154 list_append_string(rettv->vval.v_list,
6155 ((char_u **)(ga.ga_data))[i], -1);
6156 ga_clear_strings(&ga);
6157 }
6158 else
6159 rettv->vval.v_string = NULL;
6160}
6161
6162/*
6163 * "glob2regpat()" function
6164 */
6165 static void
6166f_glob2regpat(typval_T *argvars, typval_T *rettv)
6167{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006168 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006169
6170 rettv->v_type = VAR_STRING;
6171 rettv->vval.v_string = (pat == NULL)
6172 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6173}
6174
6175/* for VIM_VERSION_ defines */
6176#include "version.h"
6177
6178/*
6179 * "has()" function
6180 */
6181 static void
6182f_has(typval_T *argvars, typval_T *rettv)
6183{
6184 int i;
6185 char_u *name;
6186 int n = FALSE;
6187 static char *(has_list[]) =
6188 {
6189#ifdef AMIGA
6190 "amiga",
6191# ifdef FEAT_ARP
6192 "arp",
6193# endif
6194#endif
6195#ifdef __BEOS__
6196 "beos",
6197#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006198#if defined(BSD) && !defined(MACOS_X)
6199 "bsd",
6200#endif
6201#ifdef hpux
6202 "hpux",
6203#endif
6204#ifdef __linux__
6205 "linux",
6206#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006207#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006208 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6209 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006210# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006211 "macunix", /* Mac OS X, with the darwin feature */
6212 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006213# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006214#endif
6215#ifdef __QNX__
6216 "qnx",
6217#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006218#ifdef SUN_SYSTEM
6219 "sun",
6220#else
6221 "moon",
6222#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006223#ifdef UNIX
6224 "unix",
6225#endif
6226#ifdef VMS
6227 "vms",
6228#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006229#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006230 "win32",
6231#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006232#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006233 "win32unix",
6234#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006235#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006236 "win64",
6237#endif
6238#ifdef EBCDIC
6239 "ebcdic",
6240#endif
6241#ifndef CASE_INSENSITIVE_FILENAME
6242 "fname_case",
6243#endif
6244#ifdef HAVE_ACL
6245 "acl",
6246#endif
6247#ifdef FEAT_ARABIC
6248 "arabic",
6249#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006250 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006251#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006252 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006253#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006254#ifdef FEAT_AUTOSERVERNAME
6255 "autoservername",
6256#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006257#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006258 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006259# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006260 "balloon_multiline",
6261# endif
6262#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006263#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006264 "balloon_eval_term",
6265#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006266#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6267 "builtin_terms",
6268# ifdef ALL_BUILTIN_TCAPS
6269 "all_builtin_terms",
6270# endif
6271#endif
6272#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006273 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006274 || defined(FEAT_GUI_MOTIF))
6275 "browsefilter",
6276#endif
6277#ifdef FEAT_BYTEOFF
6278 "byte_offset",
6279#endif
6280#ifdef FEAT_JOB_CHANNEL
6281 "channel",
6282#endif
6283#ifdef FEAT_CINDENT
6284 "cindent",
6285#endif
6286#ifdef FEAT_CLIENTSERVER
6287 "clientserver",
6288#endif
6289#ifdef FEAT_CLIPBOARD
6290 "clipboard",
6291#endif
6292#ifdef FEAT_CMDL_COMPL
6293 "cmdline_compl",
6294#endif
6295#ifdef FEAT_CMDHIST
6296 "cmdline_hist",
6297#endif
6298#ifdef FEAT_COMMENTS
6299 "comments",
6300#endif
6301#ifdef FEAT_CONCEAL
6302 "conceal",
6303#endif
6304#ifdef FEAT_CRYPT
6305 "cryptv",
6306 "crypt-blowfish",
6307 "crypt-blowfish2",
6308#endif
6309#ifdef FEAT_CSCOPE
6310 "cscope",
6311#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006312 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006313#ifdef CURSOR_SHAPE
6314 "cursorshape",
6315#endif
6316#ifdef DEBUG
6317 "debug",
6318#endif
6319#ifdef FEAT_CON_DIALOG
6320 "dialog_con",
6321#endif
6322#ifdef FEAT_GUI_DIALOG
6323 "dialog_gui",
6324#endif
6325#ifdef FEAT_DIFF
6326 "diff",
6327#endif
6328#ifdef FEAT_DIGRAPHS
6329 "digraphs",
6330#endif
6331#ifdef FEAT_DIRECTX
6332 "directx",
6333#endif
6334#ifdef FEAT_DND
6335 "dnd",
6336#endif
6337#ifdef FEAT_EMACS_TAGS
6338 "emacs_tags",
6339#endif
6340 "eval", /* always present, of course! */
6341 "ex_extra", /* graduated feature */
6342#ifdef FEAT_SEARCH_EXTRA
6343 "extra_search",
6344#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006345#ifdef FEAT_SEARCHPATH
6346 "file_in_path",
6347#endif
6348#ifdef FEAT_FILTERPIPE
6349 "filterpipe",
6350#endif
6351#ifdef FEAT_FIND_ID
6352 "find_in_path",
6353#endif
6354#ifdef FEAT_FLOAT
6355 "float",
6356#endif
6357#ifdef FEAT_FOLDING
6358 "folding",
6359#endif
6360#ifdef FEAT_FOOTER
6361 "footer",
6362#endif
6363#if !defined(USE_SYSTEM) && defined(UNIX)
6364 "fork",
6365#endif
6366#ifdef FEAT_GETTEXT
6367 "gettext",
6368#endif
6369#ifdef FEAT_GUI
6370 "gui",
6371#endif
6372#ifdef FEAT_GUI_ATHENA
6373# ifdef FEAT_GUI_NEXTAW
6374 "gui_neXtaw",
6375# else
6376 "gui_athena",
6377# endif
6378#endif
6379#ifdef FEAT_GUI_GTK
6380 "gui_gtk",
6381# ifdef USE_GTK3
6382 "gui_gtk3",
6383# else
6384 "gui_gtk2",
6385# endif
6386#endif
6387#ifdef FEAT_GUI_GNOME
6388 "gui_gnome",
6389#endif
6390#ifdef FEAT_GUI_MAC
6391 "gui_mac",
6392#endif
6393#ifdef FEAT_GUI_MOTIF
6394 "gui_motif",
6395#endif
6396#ifdef FEAT_GUI_PHOTON
6397 "gui_photon",
6398#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006399#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006400 "gui_win32",
6401#endif
6402#ifdef FEAT_HANGULIN
6403 "hangul_input",
6404#endif
6405#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6406 "iconv",
6407#endif
6408#ifdef FEAT_INS_EXPAND
6409 "insert_expand",
6410#endif
6411#ifdef FEAT_JOB_CHANNEL
6412 "job",
6413#endif
6414#ifdef FEAT_JUMPLIST
6415 "jumplist",
6416#endif
6417#ifdef FEAT_KEYMAP
6418 "keymap",
6419#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006420 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006421#ifdef FEAT_LANGMAP
6422 "langmap",
6423#endif
6424#ifdef FEAT_LIBCALL
6425 "libcall",
6426#endif
6427#ifdef FEAT_LINEBREAK
6428 "linebreak",
6429#endif
6430#ifdef FEAT_LISP
6431 "lispindent",
6432#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006433 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006434#ifdef FEAT_LOCALMAP
6435 "localmap",
6436#endif
6437#ifdef FEAT_LUA
6438# ifndef DYNAMIC_LUA
6439 "lua",
6440# endif
6441#endif
6442#ifdef FEAT_MENU
6443 "menu",
6444#endif
6445#ifdef FEAT_SESSION
6446 "mksession",
6447#endif
6448#ifdef FEAT_MODIFY_FNAME
6449 "modify_fname",
6450#endif
6451#ifdef FEAT_MOUSE
6452 "mouse",
6453#endif
6454#ifdef FEAT_MOUSESHAPE
6455 "mouseshape",
6456#endif
6457#if defined(UNIX) || defined(VMS)
6458# ifdef FEAT_MOUSE_DEC
6459 "mouse_dec",
6460# endif
6461# ifdef FEAT_MOUSE_GPM
6462 "mouse_gpm",
6463# endif
6464# ifdef FEAT_MOUSE_JSB
6465 "mouse_jsbterm",
6466# endif
6467# ifdef FEAT_MOUSE_NET
6468 "mouse_netterm",
6469# endif
6470# ifdef FEAT_MOUSE_PTERM
6471 "mouse_pterm",
6472# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006473# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006474 "mouse_sgr",
6475# endif
6476# ifdef FEAT_SYSMOUSE
6477 "mouse_sysmouse",
6478# endif
6479# ifdef FEAT_MOUSE_URXVT
6480 "mouse_urxvt",
6481# endif
6482# ifdef FEAT_MOUSE_XTERM
6483 "mouse_xterm",
6484# endif
6485#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006486 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006487#ifdef FEAT_MBYTE_IME
6488 "multi_byte_ime",
6489#endif
6490#ifdef FEAT_MULTI_LANG
6491 "multi_lang",
6492#endif
6493#ifdef FEAT_MZSCHEME
6494#ifndef DYNAMIC_MZSCHEME
6495 "mzscheme",
6496#endif
6497#endif
6498#ifdef FEAT_NUM64
6499 "num64",
6500#endif
6501#ifdef FEAT_OLE
6502 "ole",
6503#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006504#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006505 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006506#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006507#ifdef FEAT_PATH_EXTRA
6508 "path_extra",
6509#endif
6510#ifdef FEAT_PERL
6511#ifndef DYNAMIC_PERL
6512 "perl",
6513#endif
6514#endif
6515#ifdef FEAT_PERSISTENT_UNDO
6516 "persistent_undo",
6517#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006518#if defined(FEAT_PYTHON)
6519 "python_compiled",
6520# if defined(DYNAMIC_PYTHON)
6521 "python_dynamic",
6522# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006523 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006524 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006525# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006526#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006527#if defined(FEAT_PYTHON3)
6528 "python3_compiled",
6529# if defined(DYNAMIC_PYTHON3)
6530 "python3_dynamic",
6531# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006532 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006533 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006534# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006535#endif
6536#ifdef FEAT_POSTSCRIPT
6537 "postscript",
6538#endif
6539#ifdef FEAT_PRINTER
6540 "printer",
6541#endif
6542#ifdef FEAT_PROFILE
6543 "profile",
6544#endif
6545#ifdef FEAT_RELTIME
6546 "reltime",
6547#endif
6548#ifdef FEAT_QUICKFIX
6549 "quickfix",
6550#endif
6551#ifdef FEAT_RIGHTLEFT
6552 "rightleft",
6553#endif
6554#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6555 "ruby",
6556#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006557 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006558#ifdef FEAT_CMDL_INFO
6559 "showcmd",
6560 "cmdline_info",
6561#endif
6562#ifdef FEAT_SIGNS
6563 "signs",
6564#endif
6565#ifdef FEAT_SMARTINDENT
6566 "smartindent",
6567#endif
6568#ifdef STARTUPTIME
6569 "startuptime",
6570#endif
6571#ifdef FEAT_STL_OPT
6572 "statusline",
6573#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006574#ifdef FEAT_NETBEANS_INTG
6575 "netbeans_intg",
6576#endif
6577#ifdef FEAT_SPELL
6578 "spell",
6579#endif
6580#ifdef FEAT_SYN_HL
6581 "syntax",
6582#endif
6583#if defined(USE_SYSTEM) || !defined(UNIX)
6584 "system",
6585#endif
6586#ifdef FEAT_TAG_BINS
6587 "tag_binary",
6588#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006589#ifdef FEAT_TCL
6590# ifndef DYNAMIC_TCL
6591 "tcl",
6592# endif
6593#endif
6594#ifdef FEAT_TERMGUICOLORS
6595 "termguicolors",
6596#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006597#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006598 "terminal",
6599#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006600#ifdef TERMINFO
6601 "terminfo",
6602#endif
6603#ifdef FEAT_TERMRESPONSE
6604 "termresponse",
6605#endif
6606#ifdef FEAT_TEXTOBJ
6607 "textobjects",
6608#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006609#ifdef FEAT_TEXT_PROP
6610 "textprop",
6611#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006612#ifdef HAVE_TGETENT
6613 "tgetent",
6614#endif
6615#ifdef FEAT_TIMERS
6616 "timers",
6617#endif
6618#ifdef FEAT_TITLE
6619 "title",
6620#endif
6621#ifdef FEAT_TOOLBAR
6622 "toolbar",
6623#endif
6624#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6625 "unnamedplus",
6626#endif
6627#ifdef FEAT_USR_CMDS
6628 "user-commands", /* was accidentally included in 5.4 */
6629 "user_commands",
6630#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006631#ifdef FEAT_VARTABS
6632 "vartabs",
6633#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006634#ifdef FEAT_VIMINFO
6635 "viminfo",
6636#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006637 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006638 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006639 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006641 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006642#ifdef FEAT_VTP
6643 "vtp",
6644#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006645#ifdef FEAT_WILDIGN
6646 "wildignore",
6647#endif
6648#ifdef FEAT_WILDMENU
6649 "wildmenu",
6650#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006651 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006652#ifdef FEAT_WAK
6653 "winaltkeys",
6654#endif
6655#ifdef FEAT_WRITEBACKUP
6656 "writebackup",
6657#endif
6658#ifdef FEAT_XIM
6659 "xim",
6660#endif
6661#ifdef FEAT_XFONTSET
6662 "xfontset",
6663#endif
6664#ifdef FEAT_XPM_W32
6665 "xpm",
6666 "xpm_w32", /* for backward compatibility */
6667#else
6668# if defined(HAVE_XPM)
6669 "xpm",
6670# endif
6671#endif
6672#ifdef USE_XSMP
6673 "xsmp",
6674#endif
6675#ifdef USE_XSMP_INTERACT
6676 "xsmp_interact",
6677#endif
6678#ifdef FEAT_XCLIPBOARD
6679 "xterm_clipboard",
6680#endif
6681#ifdef FEAT_XTERM_SAVE
6682 "xterm_save",
6683#endif
6684#if defined(UNIX) && defined(FEAT_X11)
6685 "X11",
6686#endif
6687 NULL
6688 };
6689
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006690 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006691 for (i = 0; has_list[i] != NULL; ++i)
6692 if (STRICMP(name, has_list[i]) == 0)
6693 {
6694 n = TRUE;
6695 break;
6696 }
6697
6698 if (n == FALSE)
6699 {
6700 if (STRNICMP(name, "patch", 5) == 0)
6701 {
6702 if (name[5] == '-'
6703 && STRLEN(name) >= 11
6704 && vim_isdigit(name[6])
6705 && vim_isdigit(name[8])
6706 && vim_isdigit(name[10]))
6707 {
6708 int major = atoi((char *)name + 6);
6709 int minor = atoi((char *)name + 8);
6710
6711 /* Expect "patch-9.9.01234". */
6712 n = (major < VIM_VERSION_MAJOR
6713 || (major == VIM_VERSION_MAJOR
6714 && (minor < VIM_VERSION_MINOR
6715 || (minor == VIM_VERSION_MINOR
6716 && has_patch(atoi((char *)name + 10))))));
6717 }
6718 else
6719 n = has_patch(atoi((char *)name + 5));
6720 }
6721 else if (STRICMP(name, "vim_starting") == 0)
6722 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006723 else if (STRICMP(name, "ttyin") == 0)
6724 n = mch_input_isatty();
6725 else if (STRICMP(name, "ttyout") == 0)
6726 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006727 else if (STRICMP(name, "multi_byte_encoding") == 0)
6728 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006729#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006730 else if (STRICMP(name, "balloon_multiline") == 0)
6731 n = multiline_balloon_available();
6732#endif
6733#ifdef DYNAMIC_TCL
6734 else if (STRICMP(name, "tcl") == 0)
6735 n = tcl_enabled(FALSE);
6736#endif
6737#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6738 else if (STRICMP(name, "iconv") == 0)
6739 n = iconv_enabled(FALSE);
6740#endif
6741#ifdef DYNAMIC_LUA
6742 else if (STRICMP(name, "lua") == 0)
6743 n = lua_enabled(FALSE);
6744#endif
6745#ifdef DYNAMIC_MZSCHEME
6746 else if (STRICMP(name, "mzscheme") == 0)
6747 n = mzscheme_enabled(FALSE);
6748#endif
6749#ifdef DYNAMIC_RUBY
6750 else if (STRICMP(name, "ruby") == 0)
6751 n = ruby_enabled(FALSE);
6752#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006753#ifdef DYNAMIC_PYTHON
6754 else if (STRICMP(name, "python") == 0)
6755 n = python_enabled(FALSE);
6756#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006757#ifdef DYNAMIC_PYTHON3
6758 else if (STRICMP(name, "python3") == 0)
6759 n = python3_enabled(FALSE);
6760#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006761#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6762 else if (STRICMP(name, "pythonx") == 0)
6763 {
6764# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6765 if (p_pyx == 0)
6766 n = python3_enabled(FALSE) || python_enabled(FALSE);
6767 else if (p_pyx == 3)
6768 n = python3_enabled(FALSE);
6769 else if (p_pyx == 2)
6770 n = python_enabled(FALSE);
6771# elif defined(DYNAMIC_PYTHON)
6772 n = python_enabled(FALSE);
6773# elif defined(DYNAMIC_PYTHON3)
6774 n = python3_enabled(FALSE);
6775# endif
6776 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006777#endif
6778#ifdef DYNAMIC_PERL
6779 else if (STRICMP(name, "perl") == 0)
6780 n = perl_enabled(FALSE);
6781#endif
6782#ifdef FEAT_GUI
6783 else if (STRICMP(name, "gui_running") == 0)
6784 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006785# ifdef FEAT_BROWSE
6786 else if (STRICMP(name, "browse") == 0)
6787 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6788# endif
6789#endif
6790#ifdef FEAT_SYN_HL
6791 else if (STRICMP(name, "syntax_items") == 0)
6792 n = syntax_present(curwin);
6793#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006794#ifdef FEAT_VTP
6795 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006796 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006797#endif
6798#ifdef FEAT_NETBEANS_INTG
6799 else if (STRICMP(name, "netbeans_enabled") == 0)
6800 n = netbeans_active();
6801#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006802#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006803 else if (STRICMP(name, "terminal") == 0)
6804 n = terminal_enabled();
6805#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006806#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006807 else if (STRICMP(name, "conpty") == 0)
6808 n = use_conpty();
6809#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006810 }
6811
6812 rettv->vval.v_number = n;
6813}
6814
6815/*
6816 * "has_key()" function
6817 */
6818 static void
6819f_has_key(typval_T *argvars, typval_T *rettv)
6820{
6821 if (argvars[0].v_type != VAR_DICT)
6822 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006823 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006824 return;
6825 }
6826 if (argvars[0].vval.v_dict == NULL)
6827 return;
6828
6829 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006830 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006831}
6832
6833/*
6834 * "haslocaldir()" function
6835 */
6836 static void
6837f_haslocaldir(typval_T *argvars, typval_T *rettv)
6838{
6839 win_T *wp = NULL;
6840
6841 wp = find_tabwin(&argvars[0], &argvars[1]);
6842 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6843}
6844
6845/*
6846 * "hasmapto()" function
6847 */
6848 static void
6849f_hasmapto(typval_T *argvars, typval_T *rettv)
6850{
6851 char_u *name;
6852 char_u *mode;
6853 char_u buf[NUMBUFLEN];
6854 int abbr = FALSE;
6855
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006856 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006857 if (argvars[1].v_type == VAR_UNKNOWN)
6858 mode = (char_u *)"nvo";
6859 else
6860 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006861 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006862 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006863 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006864 }
6865
6866 if (map_to_exists(name, mode, abbr))
6867 rettv->vval.v_number = TRUE;
6868 else
6869 rettv->vval.v_number = FALSE;
6870}
6871
6872/*
6873 * "histadd()" function
6874 */
6875 static void
6876f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6877{
6878#ifdef FEAT_CMDHIST
6879 int histype;
6880 char_u *str;
6881 char_u buf[NUMBUFLEN];
6882#endif
6883
6884 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006885 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006886 return;
6887#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006888 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006889 histype = str != NULL ? get_histtype(str) : -1;
6890 if (histype >= 0)
6891 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006892 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006893 if (*str != NUL)
6894 {
6895 init_history();
6896 add_to_history(histype, str, FALSE, NUL);
6897 rettv->vval.v_number = TRUE;
6898 return;
6899 }
6900 }
6901#endif
6902}
6903
6904/*
6905 * "histdel()" function
6906 */
6907 static void
6908f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6909{
6910#ifdef FEAT_CMDHIST
6911 int n;
6912 char_u buf[NUMBUFLEN];
6913 char_u *str;
6914
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006915 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006916 if (str == NULL)
6917 n = 0;
6918 else if (argvars[1].v_type == VAR_UNKNOWN)
6919 /* only one argument: clear entire history */
6920 n = clr_history(get_histtype(str));
6921 else if (argvars[1].v_type == VAR_NUMBER)
6922 /* index given: remove that entry */
6923 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006924 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006925 else
6926 /* string given: remove all matching entries */
6927 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006928 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006929 rettv->vval.v_number = n;
6930#endif
6931}
6932
6933/*
6934 * "histget()" function
6935 */
6936 static void
6937f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6938{
6939#ifdef FEAT_CMDHIST
6940 int type;
6941 int idx;
6942 char_u *str;
6943
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006944 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006945 if (str == NULL)
6946 rettv->vval.v_string = NULL;
6947 else
6948 {
6949 type = get_histtype(str);
6950 if (argvars[1].v_type == VAR_UNKNOWN)
6951 idx = get_history_idx(type);
6952 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006953 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006954 /* -1 on type error */
6955 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6956 }
6957#else
6958 rettv->vval.v_string = NULL;
6959#endif
6960 rettv->v_type = VAR_STRING;
6961}
6962
6963/*
6964 * "histnr()" function
6965 */
6966 static void
6967f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6968{
6969 int i;
6970
6971#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006972 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006973
6974 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6975 if (i >= HIST_CMD && i < HIST_COUNT)
6976 i = get_history_idx(i);
6977 else
6978#endif
6979 i = -1;
6980 rettv->vval.v_number = i;
6981}
6982
6983/*
6984 * "highlightID(name)" function
6985 */
6986 static void
6987f_hlID(typval_T *argvars, typval_T *rettv)
6988{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006989 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006990}
6991
6992/*
6993 * "highlight_exists()" function
6994 */
6995 static void
6996f_hlexists(typval_T *argvars, typval_T *rettv)
6997{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006998 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006999}
7000
7001/*
7002 * "hostname()" function
7003 */
7004 static void
7005f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
7006{
7007 char_u hostname[256];
7008
7009 mch_get_host_name(hostname, 256);
7010 rettv->v_type = VAR_STRING;
7011 rettv->vval.v_string = vim_strsave(hostname);
7012}
7013
7014/*
7015 * iconv() function
7016 */
7017 static void
7018f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
7019{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007020 char_u buf1[NUMBUFLEN];
7021 char_u buf2[NUMBUFLEN];
7022 char_u *from, *to, *str;
7023 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007024
7025 rettv->v_type = VAR_STRING;
7026 rettv->vval.v_string = NULL;
7027
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007028 str = tv_get_string(&argvars[0]);
7029 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
7030 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007031 vimconv.vc_type = CONV_NONE;
7032 convert_setup(&vimconv, from, to);
7033
7034 /* If the encodings are equal, no conversion needed. */
7035 if (vimconv.vc_type == CONV_NONE)
7036 rettv->vval.v_string = vim_strsave(str);
7037 else
7038 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
7039
7040 convert_setup(&vimconv, NULL, NULL);
7041 vim_free(from);
7042 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007043}
7044
7045/*
7046 * "indent()" function
7047 */
7048 static void
7049f_indent(typval_T *argvars, typval_T *rettv)
7050{
7051 linenr_T lnum;
7052
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007053 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007054 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7055 rettv->vval.v_number = get_indent_lnum(lnum);
7056 else
7057 rettv->vval.v_number = -1;
7058}
7059
7060/*
7061 * "index()" function
7062 */
7063 static void
7064f_index(typval_T *argvars, typval_T *rettv)
7065{
7066 list_T *l;
7067 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007068 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007069 long idx = 0;
7070 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007071 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007072
7073 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007074 if (argvars[0].v_type == VAR_BLOB)
7075 {
7076 typval_T tv;
7077 int start = 0;
7078
7079 if (argvars[2].v_type != VAR_UNKNOWN)
7080 {
7081 start = tv_get_number_chk(&argvars[2], &error);
7082 if (error)
7083 return;
7084 }
7085 b = argvars[0].vval.v_blob;
7086 if (b == NULL)
7087 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007088 if (start < 0)
7089 {
7090 start = blob_len(b) + start;
7091 if (start < 0)
7092 start = 0;
7093 }
7094
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007095 for (idx = start; idx < blob_len(b); ++idx)
7096 {
7097 tv.v_type = VAR_NUMBER;
7098 tv.vval.v_number = blob_get(b, idx);
7099 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7100 {
7101 rettv->vval.v_number = idx;
7102 return;
7103 }
7104 }
7105 return;
7106 }
7107 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007108 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007109 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007110 return;
7111 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007112
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007113 l = argvars[0].vval.v_list;
7114 if (l != NULL)
7115 {
7116 item = l->lv_first;
7117 if (argvars[2].v_type != VAR_UNKNOWN)
7118 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007119 /* Start at specified item. Use the cached index that list_find()
7120 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007121 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007122 idx = l->lv_idx;
7123 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007124 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007125 if (error)
7126 item = NULL;
7127 }
7128
7129 for ( ; item != NULL; item = item->li_next, ++idx)
7130 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7131 {
7132 rettv->vval.v_number = idx;
7133 break;
7134 }
7135 }
7136}
7137
7138static int inputsecret_flag = 0;
7139
7140/*
7141 * "input()" function
7142 * Also handles inputsecret() when inputsecret is set.
7143 */
7144 static void
7145f_input(typval_T *argvars, typval_T *rettv)
7146{
7147 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7148}
7149
7150/*
7151 * "inputdialog()" function
7152 */
7153 static void
7154f_inputdialog(typval_T *argvars, typval_T *rettv)
7155{
7156#if defined(FEAT_GUI_TEXTDIALOG)
7157 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7158 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7159 {
7160 char_u *message;
7161 char_u buf[NUMBUFLEN];
7162 char_u *defstr = (char_u *)"";
7163
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007164 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007165 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007166 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007167 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7168 else
7169 IObuff[0] = NUL;
7170 if (message != NULL && defstr != NULL
7171 && do_dialog(VIM_QUESTION, NULL, message,
7172 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7173 rettv->vval.v_string = vim_strsave(IObuff);
7174 else
7175 {
7176 if (message != NULL && defstr != NULL
7177 && argvars[1].v_type != VAR_UNKNOWN
7178 && argvars[2].v_type != VAR_UNKNOWN)
7179 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007180 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007181 else
7182 rettv->vval.v_string = NULL;
7183 }
7184 rettv->v_type = VAR_STRING;
7185 }
7186 else
7187#endif
7188 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7189}
7190
7191/*
7192 * "inputlist()" function
7193 */
7194 static void
7195f_inputlist(typval_T *argvars, typval_T *rettv)
7196{
7197 listitem_T *li;
7198 int selected;
7199 int mouse_used;
7200
7201#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007202 /* While starting up, there is no place to enter text. When running tests
7203 * with --not-a-term we assume feedkeys() will be used. */
7204 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007205 return;
7206#endif
7207 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7208 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007209 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007210 return;
7211 }
7212
7213 msg_start();
7214 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7215 lines_left = Rows; /* avoid more prompt */
7216 msg_scroll = TRUE;
7217 msg_clr_eos();
7218
7219 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7220 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007221 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007222 msg_putchar('\n');
7223 }
7224
7225 /* Ask for choice. */
7226 selected = prompt_for_number(&mouse_used);
7227 if (mouse_used)
7228 selected -= lines_left;
7229
7230 rettv->vval.v_number = selected;
7231}
7232
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007233static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7234
7235/*
7236 * "inputrestore()" function
7237 */
7238 static void
7239f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7240{
7241 if (ga_userinput.ga_len > 0)
7242 {
7243 --ga_userinput.ga_len;
7244 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7245 + ga_userinput.ga_len);
7246 /* default return is zero == OK */
7247 }
7248 else if (p_verbose > 1)
7249 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007250 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007251 rettv->vval.v_number = 1; /* Failed */
7252 }
7253}
7254
7255/*
7256 * "inputsave()" function
7257 */
7258 static void
7259f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7260{
7261 /* Add an entry to the stack of typeahead storage. */
7262 if (ga_grow(&ga_userinput, 1) == OK)
7263 {
7264 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7265 + ga_userinput.ga_len);
7266 ++ga_userinput.ga_len;
7267 /* default return is zero == OK */
7268 }
7269 else
7270 rettv->vval.v_number = 1; /* Failed */
7271}
7272
7273/*
7274 * "inputsecret()" function
7275 */
7276 static void
7277f_inputsecret(typval_T *argvars, typval_T *rettv)
7278{
7279 ++cmdline_star;
7280 ++inputsecret_flag;
7281 f_input(argvars, rettv);
7282 --cmdline_star;
7283 --inputsecret_flag;
7284}
7285
7286/*
7287 * "insert()" function
7288 */
7289 static void
7290f_insert(typval_T *argvars, typval_T *rettv)
7291{
7292 long before = 0;
7293 listitem_T *item;
7294 list_T *l;
7295 int error = FALSE;
7296
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007297 if (argvars[0].v_type == VAR_BLOB)
7298 {
7299 int val, len;
7300 char_u *p;
7301
7302 len = blob_len(argvars[0].vval.v_blob);
7303 if (argvars[2].v_type != VAR_UNKNOWN)
7304 {
7305 before = (long)tv_get_number_chk(&argvars[2], &error);
7306 if (error)
7307 return; // type error; errmsg already given
7308 if (before < 0 || before > len)
7309 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007310 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007311 return;
7312 }
7313 }
7314 val = tv_get_number_chk(&argvars[1], &error);
7315 if (error)
7316 return;
7317 if (val < 0 || val > 255)
7318 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007319 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007320 return;
7321 }
7322
7323 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7324 return;
7325 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7326 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7327 *(p + before) = val;
7328 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7329
7330 copy_tv(&argvars[0], rettv);
7331 }
7332 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007333 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007334 else if ((l = argvars[0].vval.v_list) != NULL
7335 && !var_check_lock(l->lv_lock,
7336 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007337 {
7338 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007339 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007340 if (error)
7341 return; /* type error; errmsg already given */
7342
7343 if (before == l->lv_len)
7344 item = NULL;
7345 else
7346 {
7347 item = list_find(l, before);
7348 if (item == NULL)
7349 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007350 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007351 l = NULL;
7352 }
7353 }
7354 if (l != NULL)
7355 {
7356 list_insert_tv(l, &argvars[1], item);
7357 copy_tv(&argvars[0], rettv);
7358 }
7359 }
7360}
7361
7362/*
7363 * "invert(expr)" function
7364 */
7365 static void
7366f_invert(typval_T *argvars, typval_T *rettv)
7367{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007368 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007369}
7370
7371/*
7372 * "isdirectory()" function
7373 */
7374 static void
7375f_isdirectory(typval_T *argvars, typval_T *rettv)
7376{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007377 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007378}
7379
7380/*
7381 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7382 * or it refers to a List or Dictionary that is locked.
7383 */
7384 static int
7385tv_islocked(typval_T *tv)
7386{
7387 return (tv->v_lock & VAR_LOCKED)
7388 || (tv->v_type == VAR_LIST
7389 && tv->vval.v_list != NULL
7390 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7391 || (tv->v_type == VAR_DICT
7392 && tv->vval.v_dict != NULL
7393 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7394}
7395
7396/*
7397 * "islocked()" function
7398 */
7399 static void
7400f_islocked(typval_T *argvars, typval_T *rettv)
7401{
7402 lval_T lv;
7403 char_u *end;
7404 dictitem_T *di;
7405
7406 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007407 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007408 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007409 if (end != NULL && lv.ll_name != NULL)
7410 {
7411 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007412 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007413 else
7414 {
7415 if (lv.ll_tv == NULL)
7416 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007417 di = find_var(lv.ll_name, NULL, TRUE);
7418 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007419 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007420 /* Consider a variable locked when:
7421 * 1. the variable itself is locked
7422 * 2. the value of the variable is locked.
7423 * 3. the List or Dict value is locked.
7424 */
7425 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7426 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007427 }
7428 }
7429 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007430 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007431 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007432 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007433 else if (lv.ll_list != NULL)
7434 /* List item. */
7435 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7436 else
7437 /* Dictionary item. */
7438 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7439 }
7440 }
7441
7442 clear_lval(&lv);
7443}
7444
7445#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7446/*
Bram Moolenaarfda1bff2019-04-04 13:44:37 +02007447 * "isinf()" function
7448 */
7449 static void
7450f_isinf(typval_T *argvars, typval_T *rettv)
7451{
7452 if (argvars[0].v_type == VAR_FLOAT && isinf(argvars[0].vval.v_float))
7453 rettv->vval.v_number = argvars[0].vval.v_float > 0.0 ? 1 : -1;
7454}
7455
7456/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007457 * "isnan()" function
7458 */
7459 static void
7460f_isnan(typval_T *argvars, typval_T *rettv)
7461{
7462 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7463 && isnan(argvars[0].vval.v_float);
7464}
7465#endif
7466
7467/*
7468 * "items(dict)" function
7469 */
7470 static void
7471f_items(typval_T *argvars, typval_T *rettv)
7472{
7473 dict_list(argvars, rettv, 2);
7474}
7475
7476#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7477/*
7478 * Get the job from the argument.
7479 * Returns NULL if the job is invalid.
7480 */
7481 static job_T *
7482get_job_arg(typval_T *tv)
7483{
7484 job_T *job;
7485
7486 if (tv->v_type != VAR_JOB)
7487 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007488 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007489 return NULL;
7490 }
7491 job = tv->vval.v_job;
7492
7493 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007494 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007495 return job;
7496}
7497
7498/*
7499 * "job_getchannel()" function
7500 */
7501 static void
7502f_job_getchannel(typval_T *argvars, typval_T *rettv)
7503{
7504 job_T *job = get_job_arg(&argvars[0]);
7505
7506 if (job != NULL)
7507 {
7508 rettv->v_type = VAR_CHANNEL;
7509 rettv->vval.v_channel = job->jv_channel;
7510 if (job->jv_channel != NULL)
7511 ++job->jv_channel->ch_refcount;
7512 }
7513}
7514
7515/*
7516 * "job_info()" function
7517 */
7518 static void
7519f_job_info(typval_T *argvars, typval_T *rettv)
7520{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007521 if (argvars[0].v_type != VAR_UNKNOWN)
7522 {
7523 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007524
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007525 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7526 job_info(job, rettv->vval.v_dict);
7527 }
7528 else if (rettv_list_alloc(rettv) == OK)
7529 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007530}
7531
7532/*
7533 * "job_setoptions()" function
7534 */
7535 static void
7536f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7537{
7538 job_T *job = get_job_arg(&argvars[0]);
7539 jobopt_T opt;
7540
7541 if (job == NULL)
7542 return;
7543 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007544 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007545 job_set_options(job, &opt);
7546 free_job_options(&opt);
7547}
7548
7549/*
7550 * "job_start()" function
7551 */
7552 static void
7553f_job_start(typval_T *argvars, typval_T *rettv)
7554{
7555 rettv->v_type = VAR_JOB;
7556 if (check_restricted() || check_secure())
7557 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007558 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007559}
7560
7561/*
7562 * "job_status()" function
7563 */
7564 static void
7565f_job_status(typval_T *argvars, typval_T *rettv)
7566{
7567 job_T *job = get_job_arg(&argvars[0]);
7568
7569 if (job != NULL)
7570 {
7571 rettv->v_type = VAR_STRING;
7572 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7573 }
7574}
7575
7576/*
7577 * "job_stop()" function
7578 */
7579 static void
7580f_job_stop(typval_T *argvars, typval_T *rettv)
7581{
7582 job_T *job = get_job_arg(&argvars[0]);
7583
7584 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007585 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007586}
7587#endif
7588
7589/*
7590 * "join()" function
7591 */
7592 static void
7593f_join(typval_T *argvars, typval_T *rettv)
7594{
7595 garray_T ga;
7596 char_u *sep;
7597
7598 if (argvars[0].v_type != VAR_LIST)
7599 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007600 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007601 return;
7602 }
7603 if (argvars[0].vval.v_list == NULL)
7604 return;
7605 if (argvars[1].v_type == VAR_UNKNOWN)
7606 sep = (char_u *)" ";
7607 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007608 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007609
7610 rettv->v_type = VAR_STRING;
7611
7612 if (sep != NULL)
7613 {
7614 ga_init2(&ga, (int)sizeof(char), 80);
7615 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7616 ga_append(&ga, NUL);
7617 rettv->vval.v_string = (char_u *)ga.ga_data;
7618 }
7619 else
7620 rettv->vval.v_string = NULL;
7621}
7622
7623/*
7624 * "js_decode()" function
7625 */
7626 static void
7627f_js_decode(typval_T *argvars, typval_T *rettv)
7628{
7629 js_read_T reader;
7630
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007631 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007632 reader.js_fill = NULL;
7633 reader.js_used = 0;
7634 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007635 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007636}
7637
7638/*
7639 * "js_encode()" function
7640 */
7641 static void
7642f_js_encode(typval_T *argvars, typval_T *rettv)
7643{
7644 rettv->v_type = VAR_STRING;
7645 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7646}
7647
7648/*
7649 * "json_decode()" function
7650 */
7651 static void
7652f_json_decode(typval_T *argvars, typval_T *rettv)
7653{
7654 js_read_T reader;
7655
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007656 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007657 reader.js_fill = NULL;
7658 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007659 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007660}
7661
7662/*
7663 * "json_encode()" function
7664 */
7665 static void
7666f_json_encode(typval_T *argvars, typval_T *rettv)
7667{
7668 rettv->v_type = VAR_STRING;
7669 rettv->vval.v_string = json_encode(&argvars[0], 0);
7670}
7671
7672/*
7673 * "keys()" function
7674 */
7675 static void
7676f_keys(typval_T *argvars, typval_T *rettv)
7677{
7678 dict_list(argvars, rettv, 0);
7679}
7680
7681/*
7682 * "last_buffer_nr()" function.
7683 */
7684 static void
7685f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7686{
7687 int n = 0;
7688 buf_T *buf;
7689
Bram Moolenaar29323592016-07-24 22:04:11 +02007690 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007691 if (n < buf->b_fnum)
7692 n = buf->b_fnum;
7693
7694 rettv->vval.v_number = n;
7695}
7696
7697/*
7698 * "len()" function
7699 */
7700 static void
7701f_len(typval_T *argvars, typval_T *rettv)
7702{
7703 switch (argvars[0].v_type)
7704 {
7705 case VAR_STRING:
7706 case VAR_NUMBER:
7707 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007708 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007709 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007710 case VAR_BLOB:
7711 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7712 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007713 case VAR_LIST:
7714 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7715 break;
7716 case VAR_DICT:
7717 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7718 break;
7719 case VAR_UNKNOWN:
7720 case VAR_SPECIAL:
7721 case VAR_FLOAT:
7722 case VAR_FUNC:
7723 case VAR_PARTIAL:
7724 case VAR_JOB:
7725 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007726 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007727 break;
7728 }
7729}
7730
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007731 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007732libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007733{
7734#ifdef FEAT_LIBCALL
7735 char_u *string_in;
7736 char_u **string_result;
7737 int nr_result;
7738#endif
7739
7740 rettv->v_type = type;
7741 if (type != VAR_NUMBER)
7742 rettv->vval.v_string = NULL;
7743
7744 if (check_restricted() || check_secure())
7745 return;
7746
7747#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007748 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007749 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7750 {
7751 string_in = NULL;
7752 if (argvars[2].v_type == VAR_STRING)
7753 string_in = argvars[2].vval.v_string;
7754 if (type == VAR_NUMBER)
7755 string_result = NULL;
7756 else
7757 string_result = &rettv->vval.v_string;
7758 if (mch_libcall(argvars[0].vval.v_string,
7759 argvars[1].vval.v_string,
7760 string_in,
7761 argvars[2].vval.v_number,
7762 string_result,
7763 &nr_result) == OK
7764 && type == VAR_NUMBER)
7765 rettv->vval.v_number = nr_result;
7766 }
7767#endif
7768}
7769
7770/*
7771 * "libcall()" function
7772 */
7773 static void
7774f_libcall(typval_T *argvars, typval_T *rettv)
7775{
7776 libcall_common(argvars, rettv, VAR_STRING);
7777}
7778
7779/*
7780 * "libcallnr()" function
7781 */
7782 static void
7783f_libcallnr(typval_T *argvars, typval_T *rettv)
7784{
7785 libcall_common(argvars, rettv, VAR_NUMBER);
7786}
7787
7788/*
7789 * "line(string)" function
7790 */
7791 static void
7792f_line(typval_T *argvars, typval_T *rettv)
7793{
7794 linenr_T lnum = 0;
7795 pos_T *fp;
7796 int fnum;
7797
7798 fp = var2fpos(&argvars[0], TRUE, &fnum);
7799 if (fp != NULL)
7800 lnum = fp->lnum;
7801 rettv->vval.v_number = lnum;
7802}
7803
7804/*
7805 * "line2byte(lnum)" function
7806 */
7807 static void
7808f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7809{
7810#ifndef FEAT_BYTEOFF
7811 rettv->vval.v_number = -1;
7812#else
7813 linenr_T lnum;
7814
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007815 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007816 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7817 rettv->vval.v_number = -1;
7818 else
7819 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7820 if (rettv->vval.v_number >= 0)
7821 ++rettv->vval.v_number;
7822#endif
7823}
7824
7825/*
7826 * "lispindent(lnum)" function
7827 */
7828 static void
7829f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7830{
7831#ifdef FEAT_LISP
7832 pos_T pos;
7833 linenr_T lnum;
7834
7835 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007836 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007837 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7838 {
7839 curwin->w_cursor.lnum = lnum;
7840 rettv->vval.v_number = get_lisp_indent();
7841 curwin->w_cursor = pos;
7842 }
7843 else
7844#endif
7845 rettv->vval.v_number = -1;
7846}
7847
7848/*
7849 * "localtime()" function
7850 */
7851 static void
7852f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7853{
7854 rettv->vval.v_number = (varnumber_T)time(NULL);
7855}
7856
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007857 static void
7858get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7859{
7860 char_u *keys;
7861 char_u *which;
7862 char_u buf[NUMBUFLEN];
7863 char_u *keys_buf = NULL;
7864 char_u *rhs;
7865 int mode;
7866 int abbr = FALSE;
7867 int get_dict = FALSE;
7868 mapblock_T *mp;
7869 int buffer_local;
7870
7871 /* return empty string for failure */
7872 rettv->v_type = VAR_STRING;
7873 rettv->vval.v_string = NULL;
7874
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007875 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007876 if (*keys == NUL)
7877 return;
7878
7879 if (argvars[1].v_type != VAR_UNKNOWN)
7880 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007881 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007882 if (argvars[2].v_type != VAR_UNKNOWN)
7883 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007884 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007885 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007886 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007887 }
7888 }
7889 else
7890 which = (char_u *)"";
7891 if (which == NULL)
7892 return;
7893
7894 mode = get_map_mode(&which, 0);
7895
7896 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7897 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7898 vim_free(keys_buf);
7899
7900 if (!get_dict)
7901 {
7902 /* Return a string. */
7903 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007904 {
7905 if (*rhs == NUL)
7906 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7907 else
7908 rettv->vval.v_string = str2special_save(rhs, FALSE);
7909 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007910
7911 }
7912 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7913 {
7914 /* Return a dictionary. */
7915 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7916 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7917 dict_T *dict = rettv->vval.v_dict;
7918
Bram Moolenaare0be1672018-07-08 16:50:37 +02007919 dict_add_string(dict, "lhs", lhs);
7920 dict_add_string(dict, "rhs", mp->m_orig_str);
7921 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7922 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7923 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007924 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7925 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007926 dict_add_number(dict, "buffer", (long)buffer_local);
7927 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7928 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007929
7930 vim_free(lhs);
7931 vim_free(mapmode);
7932 }
7933}
7934
7935#ifdef FEAT_FLOAT
7936/*
7937 * "log()" function
7938 */
7939 static void
7940f_log(typval_T *argvars, typval_T *rettv)
7941{
7942 float_T f = 0.0;
7943
7944 rettv->v_type = VAR_FLOAT;
7945 if (get_float_arg(argvars, &f) == OK)
7946 rettv->vval.v_float = log(f);
7947 else
7948 rettv->vval.v_float = 0.0;
7949}
7950
7951/*
7952 * "log10()" function
7953 */
7954 static void
7955f_log10(typval_T *argvars, typval_T *rettv)
7956{
7957 float_T f = 0.0;
7958
7959 rettv->v_type = VAR_FLOAT;
7960 if (get_float_arg(argvars, &f) == OK)
7961 rettv->vval.v_float = log10(f);
7962 else
7963 rettv->vval.v_float = 0.0;
7964}
7965#endif
7966
7967#ifdef FEAT_LUA
7968/*
7969 * "luaeval()" function
7970 */
7971 static void
7972f_luaeval(typval_T *argvars, typval_T *rettv)
7973{
7974 char_u *str;
7975 char_u buf[NUMBUFLEN];
7976
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007977 if (check_restricted() || check_secure())
7978 return;
7979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007980 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007981 do_luaeval(str, argvars + 1, rettv);
7982}
7983#endif
7984
7985/*
7986 * "map()" function
7987 */
7988 static void
7989f_map(typval_T *argvars, typval_T *rettv)
7990{
7991 filter_map(argvars, rettv, TRUE);
7992}
7993
7994/*
7995 * "maparg()" function
7996 */
7997 static void
7998f_maparg(typval_T *argvars, typval_T *rettv)
7999{
8000 get_maparg(argvars, rettv, TRUE);
8001}
8002
8003/*
8004 * "mapcheck()" function
8005 */
8006 static void
8007f_mapcheck(typval_T *argvars, typval_T *rettv)
8008{
8009 get_maparg(argvars, rettv, FALSE);
8010}
8011
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008012typedef enum
8013{
8014 MATCH_END, /* matchend() */
8015 MATCH_MATCH, /* match() */
8016 MATCH_STR, /* matchstr() */
8017 MATCH_LIST, /* matchlist() */
8018 MATCH_POS /* matchstrpos() */
8019} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008020
8021 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008022find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008023{
8024 char_u *str = NULL;
8025 long len = 0;
8026 char_u *expr = NULL;
8027 char_u *pat;
8028 regmatch_T regmatch;
8029 char_u patbuf[NUMBUFLEN];
8030 char_u strbuf[NUMBUFLEN];
8031 char_u *save_cpo;
8032 long start = 0;
8033 long nth = 1;
8034 colnr_T startcol = 0;
8035 int match = 0;
8036 list_T *l = NULL;
8037 listitem_T *li = NULL;
8038 long idx = 0;
8039 char_u *tofree = NULL;
8040
8041 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8042 save_cpo = p_cpo;
8043 p_cpo = (char_u *)"";
8044
8045 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008046 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008047 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008048 /* type MATCH_LIST: return empty list when there are no matches.
8049 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008050 if (rettv_list_alloc(rettv) == FAIL)
8051 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008052 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008053 && (list_append_string(rettv->vval.v_list,
8054 (char_u *)"", 0) == FAIL
8055 || list_append_number(rettv->vval.v_list,
8056 (varnumber_T)-1) == FAIL
8057 || list_append_number(rettv->vval.v_list,
8058 (varnumber_T)-1) == FAIL
8059 || list_append_number(rettv->vval.v_list,
8060 (varnumber_T)-1) == FAIL))
8061 {
8062 list_free(rettv->vval.v_list);
8063 rettv->vval.v_list = NULL;
8064 goto theend;
8065 }
8066 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008067 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008068 {
8069 rettv->v_type = VAR_STRING;
8070 rettv->vval.v_string = NULL;
8071 }
8072
8073 if (argvars[0].v_type == VAR_LIST)
8074 {
8075 if ((l = argvars[0].vval.v_list) == NULL)
8076 goto theend;
8077 li = l->lv_first;
8078 }
8079 else
8080 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008081 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008082 len = (long)STRLEN(str);
8083 }
8084
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008085 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008086 if (pat == NULL)
8087 goto theend;
8088
8089 if (argvars[2].v_type != VAR_UNKNOWN)
8090 {
8091 int error = FALSE;
8092
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008093 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008094 if (error)
8095 goto theend;
8096 if (l != NULL)
8097 {
8098 li = list_find(l, start);
8099 if (li == NULL)
8100 goto theend;
8101 idx = l->lv_idx; /* use the cached index */
8102 }
8103 else
8104 {
8105 if (start < 0)
8106 start = 0;
8107 if (start > len)
8108 goto theend;
8109 /* When "count" argument is there ignore matches before "start",
8110 * otherwise skip part of the string. Differs when pattern is "^"
8111 * or "\<". */
8112 if (argvars[3].v_type != VAR_UNKNOWN)
8113 startcol = start;
8114 else
8115 {
8116 str += start;
8117 len -= start;
8118 }
8119 }
8120
8121 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008122 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008123 if (error)
8124 goto theend;
8125 }
8126
8127 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8128 if (regmatch.regprog != NULL)
8129 {
8130 regmatch.rm_ic = p_ic;
8131
8132 for (;;)
8133 {
8134 if (l != NULL)
8135 {
8136 if (li == NULL)
8137 {
8138 match = FALSE;
8139 break;
8140 }
8141 vim_free(tofree);
8142 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8143 if (str == NULL)
8144 break;
8145 }
8146
8147 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8148
8149 if (match && --nth <= 0)
8150 break;
8151 if (l == NULL && !match)
8152 break;
8153
8154 /* Advance to just after the match. */
8155 if (l != NULL)
8156 {
8157 li = li->li_next;
8158 ++idx;
8159 }
8160 else
8161 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008162 startcol = (colnr_T)(regmatch.startp[0]
8163 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008164 if (startcol > (colnr_T)len
8165 || str + startcol <= regmatch.startp[0])
8166 {
8167 match = FALSE;
8168 break;
8169 }
8170 }
8171 }
8172
8173 if (match)
8174 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008175 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008176 {
8177 listitem_T *li1 = rettv->vval.v_list->lv_first;
8178 listitem_T *li2 = li1->li_next;
8179 listitem_T *li3 = li2->li_next;
8180 listitem_T *li4 = li3->li_next;
8181
8182 vim_free(li1->li_tv.vval.v_string);
8183 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8184 (int)(regmatch.endp[0] - regmatch.startp[0]));
8185 li3->li_tv.vval.v_number =
8186 (varnumber_T)(regmatch.startp[0] - expr);
8187 li4->li_tv.vval.v_number =
8188 (varnumber_T)(regmatch.endp[0] - expr);
8189 if (l != NULL)
8190 li2->li_tv.vval.v_number = (varnumber_T)idx;
8191 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008192 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008193 {
8194 int i;
8195
8196 /* return list with matched string and submatches */
8197 for (i = 0; i < NSUBEXP; ++i)
8198 {
8199 if (regmatch.endp[i] == NULL)
8200 {
8201 if (list_append_string(rettv->vval.v_list,
8202 (char_u *)"", 0) == FAIL)
8203 break;
8204 }
8205 else if (list_append_string(rettv->vval.v_list,
8206 regmatch.startp[i],
8207 (int)(regmatch.endp[i] - regmatch.startp[i]))
8208 == FAIL)
8209 break;
8210 }
8211 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008212 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008213 {
8214 /* return matched string */
8215 if (l != NULL)
8216 copy_tv(&li->li_tv, rettv);
8217 else
8218 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8219 (int)(regmatch.endp[0] - regmatch.startp[0]));
8220 }
8221 else if (l != NULL)
8222 rettv->vval.v_number = idx;
8223 else
8224 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008225 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008226 rettv->vval.v_number =
8227 (varnumber_T)(regmatch.startp[0] - str);
8228 else
8229 rettv->vval.v_number =
8230 (varnumber_T)(regmatch.endp[0] - str);
8231 rettv->vval.v_number += (varnumber_T)(str - expr);
8232 }
8233 }
8234 vim_regfree(regmatch.regprog);
8235 }
8236
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008237theend:
8238 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008239 /* matchstrpos() without a list: drop the second item. */
8240 listitem_remove(rettv->vval.v_list,
8241 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008242 vim_free(tofree);
8243 p_cpo = save_cpo;
8244}
8245
8246/*
8247 * "match()" function
8248 */
8249 static void
8250f_match(typval_T *argvars, typval_T *rettv)
8251{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008252 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008253}
8254
Bram Moolenaar95e51472018-07-28 16:55:56 +02008255#ifdef FEAT_SEARCH_EXTRA
8256 static int
8257matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8258{
8259 dictitem_T *di;
8260
8261 if (tv->v_type != VAR_DICT)
8262 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008263 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008264 return FAIL;
8265 }
8266
8267 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008268 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008269 (char_u *)"conceal", FALSE);
8270
8271 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8272 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008273 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008274 if (*win == NULL)
8275 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01008276 emsg(_(e_invalwindow));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008277 return FAIL;
8278 }
8279 }
8280
8281 return OK;
8282}
8283#endif
8284
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008285/*
8286 * "matchadd()" function
8287 */
8288 static void
8289f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8290{
8291#ifdef FEAT_SEARCH_EXTRA
8292 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008293 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8294 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008295 int prio = 10; /* default priority */
8296 int id = -1;
8297 int error = FALSE;
8298 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008299 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008300
8301 rettv->vval.v_number = -1;
8302
8303 if (grp == NULL || pat == NULL)
8304 return;
8305 if (argvars[2].v_type != VAR_UNKNOWN)
8306 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008307 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008308 if (argvars[3].v_type != VAR_UNKNOWN)
8309 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008310 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008311 if (argvars[4].v_type != VAR_UNKNOWN
8312 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8313 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008314 }
8315 }
8316 if (error == TRUE)
8317 return;
8318 if (id >= 1 && id <= 3)
8319 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008320 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008321 return;
8322 }
8323
Bram Moolenaar95e51472018-07-28 16:55:56 +02008324 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008325 conceal_char);
8326#endif
8327}
8328
8329/*
8330 * "matchaddpos()" function
8331 */
8332 static void
8333f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8334{
8335#ifdef FEAT_SEARCH_EXTRA
8336 char_u buf[NUMBUFLEN];
8337 char_u *group;
8338 int prio = 10;
8339 int id = -1;
8340 int error = FALSE;
8341 list_T *l;
8342 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008343 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008344
8345 rettv->vval.v_number = -1;
8346
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008347 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008348 if (group == NULL)
8349 return;
8350
8351 if (argvars[1].v_type != VAR_LIST)
8352 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008353 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008354 return;
8355 }
8356 l = argvars[1].vval.v_list;
8357 if (l == NULL)
8358 return;
8359
8360 if (argvars[2].v_type != VAR_UNKNOWN)
8361 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008362 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008363 if (argvars[3].v_type != VAR_UNKNOWN)
8364 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008365 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008366
8367 if (argvars[4].v_type != VAR_UNKNOWN
8368 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8369 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008370 }
8371 }
8372 if (error == TRUE)
8373 return;
8374
8375 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8376 if (id == 1 || id == 2)
8377 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008378 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008379 return;
8380 }
8381
Bram Moolenaar95e51472018-07-28 16:55:56 +02008382 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008383 conceal_char);
8384#endif
8385}
8386
8387/*
8388 * "matcharg()" function
8389 */
8390 static void
8391f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8392{
8393 if (rettv_list_alloc(rettv) == OK)
8394 {
8395#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008396 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008397 matchitem_T *m;
8398
8399 if (id >= 1 && id <= 3)
8400 {
8401 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8402 {
8403 list_append_string(rettv->vval.v_list,
8404 syn_id2name(m->hlg_id), -1);
8405 list_append_string(rettv->vval.v_list, m->pattern, -1);
8406 }
8407 else
8408 {
8409 list_append_string(rettv->vval.v_list, NULL, -1);
8410 list_append_string(rettv->vval.v_list, NULL, -1);
8411 }
8412 }
8413#endif
8414 }
8415}
8416
8417/*
8418 * "matchdelete()" function
8419 */
8420 static void
8421f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8422{
8423#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01008424 win_T *win = get_optional_window(argvars, 1);
8425
8426 if (win == NULL)
8427 rettv->vval.v_number = -1;
8428 else
8429 rettv->vval.v_number = match_delete(win,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008430 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008431#endif
8432}
8433
8434/*
8435 * "matchend()" function
8436 */
8437 static void
8438f_matchend(typval_T *argvars, typval_T *rettv)
8439{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008440 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008441}
8442
8443/*
8444 * "matchlist()" function
8445 */
8446 static void
8447f_matchlist(typval_T *argvars, typval_T *rettv)
8448{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008449 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008450}
8451
8452/*
8453 * "matchstr()" function
8454 */
8455 static void
8456f_matchstr(typval_T *argvars, typval_T *rettv)
8457{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008458 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459}
8460
8461/*
8462 * "matchstrpos()" function
8463 */
8464 static void
8465f_matchstrpos(typval_T *argvars, typval_T *rettv)
8466{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008467 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008468}
8469
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008470 static void
8471max_min(typval_T *argvars, typval_T *rettv, int domax)
8472{
8473 varnumber_T n = 0;
8474 varnumber_T i;
8475 int error = FALSE;
8476
8477 if (argvars[0].v_type == VAR_LIST)
8478 {
8479 list_T *l;
8480 listitem_T *li;
8481
8482 l = argvars[0].vval.v_list;
8483 if (l != NULL)
8484 {
8485 li = l->lv_first;
8486 if (li != NULL)
8487 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008488 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008489 for (;;)
8490 {
8491 li = li->li_next;
8492 if (li == NULL)
8493 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008494 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008495 if (domax ? i > n : i < n)
8496 n = i;
8497 }
8498 }
8499 }
8500 }
8501 else if (argvars[0].v_type == VAR_DICT)
8502 {
8503 dict_T *d;
8504 int first = TRUE;
8505 hashitem_T *hi;
8506 int todo;
8507
8508 d = argvars[0].vval.v_dict;
8509 if (d != NULL)
8510 {
8511 todo = (int)d->dv_hashtab.ht_used;
8512 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8513 {
8514 if (!HASHITEM_EMPTY(hi))
8515 {
8516 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008517 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008518 if (first)
8519 {
8520 n = i;
8521 first = FALSE;
8522 }
8523 else if (domax ? i > n : i < n)
8524 n = i;
8525 }
8526 }
8527 }
8528 }
8529 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008530 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008531 rettv->vval.v_number = error ? 0 : n;
8532}
8533
8534/*
8535 * "max()" function
8536 */
8537 static void
8538f_max(typval_T *argvars, typval_T *rettv)
8539{
8540 max_min(argvars, rettv, TRUE);
8541}
8542
8543/*
8544 * "min()" function
8545 */
8546 static void
8547f_min(typval_T *argvars, typval_T *rettv)
8548{
8549 max_min(argvars, rettv, FALSE);
8550}
8551
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008552/*
8553 * Create the directory in which "dir" is located, and higher levels when
8554 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008555 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008556 */
8557 static int
8558mkdir_recurse(char_u *dir, int prot)
8559{
8560 char_u *p;
8561 char_u *updir;
8562 int r = FAIL;
8563
8564 /* Get end of directory name in "dir".
8565 * We're done when it's "/" or "c:/". */
8566 p = gettail_sep(dir);
8567 if (p <= get_past_head(dir))
8568 return OK;
8569
8570 /* If the directory exists we're done. Otherwise: create it.*/
8571 updir = vim_strnsave(dir, (int)(p - dir));
8572 if (updir == NULL)
8573 return FAIL;
8574 if (mch_isdir(updir))
8575 r = OK;
8576 else if (mkdir_recurse(updir, prot) == OK)
8577 r = vim_mkdir_emsg(updir, prot);
8578 vim_free(updir);
8579 return r;
8580}
8581
8582#ifdef vim_mkdir
8583/*
8584 * "mkdir()" function
8585 */
8586 static void
8587f_mkdir(typval_T *argvars, typval_T *rettv)
8588{
8589 char_u *dir;
8590 char_u buf[NUMBUFLEN];
8591 int prot = 0755;
8592
8593 rettv->vval.v_number = FAIL;
8594 if (check_restricted() || check_secure())
8595 return;
8596
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008597 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008598 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008599 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008600
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008601 if (*gettail(dir) == NUL)
8602 /* remove trailing slashes */
8603 *gettail_sep(dir) = NUL;
8604
8605 if (argvars[1].v_type != VAR_UNKNOWN)
8606 {
8607 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008608 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008609 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008610 if (prot == -1)
8611 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008612 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008613 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008614 {
8615 if (mch_isdir(dir))
8616 {
8617 /* With the "p" flag it's OK if the dir already exists. */
8618 rettv->vval.v_number = OK;
8619 return;
8620 }
8621 mkdir_recurse(dir, prot);
8622 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008623 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008624 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008625}
8626#endif
8627
8628/*
8629 * "mode()" function
8630 */
8631 static void
8632f_mode(typval_T *argvars, typval_T *rettv)
8633{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008634 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008635
Bram Moolenaar612cc382018-07-29 15:34:26 +02008636 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008637
8638 if (time_for_testing == 93784)
8639 {
8640 /* Testing the two-character code. */
8641 buf[0] = 'x';
8642 buf[1] = '!';
8643 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008644#ifdef FEAT_TERMINAL
8645 else if (term_use_loop())
8646 buf[0] = 't';
8647#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008648 else if (VIsual_active)
8649 {
8650 if (VIsual_select)
8651 buf[0] = VIsual_mode + 's' - 'v';
8652 else
8653 buf[0] = VIsual_mode;
8654 }
8655 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8656 || State == CONFIRM)
8657 {
8658 buf[0] = 'r';
8659 if (State == ASKMORE)
8660 buf[1] = 'm';
8661 else if (State == CONFIRM)
8662 buf[1] = '?';
8663 }
8664 else if (State == EXTERNCMD)
8665 buf[0] = '!';
8666 else if (State & INSERT)
8667 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008668 if (State & VREPLACE_FLAG)
8669 {
8670 buf[0] = 'R';
8671 buf[1] = 'v';
8672 }
8673 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008674 {
8675 if (State & REPLACE_FLAG)
8676 buf[0] = 'R';
8677 else
8678 buf[0] = 'i';
8679#ifdef FEAT_INS_EXPAND
8680 if (ins_compl_active())
8681 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008682 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008683 buf[1] = 'x';
8684#endif
8685 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008686 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008687 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008688 {
8689 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008690 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008691 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008692 else if (exmode_active == EXMODE_NORMAL)
8693 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008694 }
8695 else
8696 {
8697 buf[0] = 'n';
8698 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008699 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008700 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008701 // to be able to detect force-linewise/blockwise/characterwise operations
8702 buf[2] = motion_force;
8703 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008704 else if (restart_edit == 'I' || restart_edit == 'R'
8705 || restart_edit == 'V')
8706 {
8707 buf[1] = 'i';
8708 buf[2] = restart_edit;
8709 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008710 }
8711
8712 /* Clear out the minor mode when the argument is not a non-zero number or
8713 * non-empty string. */
8714 if (!non_zero_arg(&argvars[0]))
8715 buf[1] = NUL;
8716
8717 rettv->vval.v_string = vim_strsave(buf);
8718 rettv->v_type = VAR_STRING;
8719}
8720
8721#if defined(FEAT_MZSCHEME) || defined(PROTO)
8722/*
8723 * "mzeval()" function
8724 */
8725 static void
8726f_mzeval(typval_T *argvars, typval_T *rettv)
8727{
8728 char_u *str;
8729 char_u buf[NUMBUFLEN];
8730
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008731 if (check_restricted() || check_secure())
8732 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008733 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008734 do_mzeval(str, rettv);
8735}
8736
8737 void
8738mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8739{
8740 typval_T argvars[3];
8741
8742 argvars[0].v_type = VAR_STRING;
8743 argvars[0].vval.v_string = name;
8744 copy_tv(args, &argvars[1]);
8745 argvars[2].v_type = VAR_UNKNOWN;
8746 f_call(argvars, rettv);
8747 clear_tv(&argvars[1]);
8748}
8749#endif
8750
8751/*
8752 * "nextnonblank()" function
8753 */
8754 static void
8755f_nextnonblank(typval_T *argvars, typval_T *rettv)
8756{
8757 linenr_T lnum;
8758
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008759 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008760 {
8761 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8762 {
8763 lnum = 0;
8764 break;
8765 }
8766 if (*skipwhite(ml_get(lnum)) != NUL)
8767 break;
8768 }
8769 rettv->vval.v_number = lnum;
8770}
8771
8772/*
8773 * "nr2char()" function
8774 */
8775 static void
8776f_nr2char(typval_T *argvars, typval_T *rettv)
8777{
8778 char_u buf[NUMBUFLEN];
8779
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008780 if (has_mbyte)
8781 {
8782 int utf8 = 0;
8783
8784 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008785 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008786 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008787 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008788 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008789 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008790 }
8791 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008792 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008793 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008794 buf[1] = NUL;
8795 }
8796 rettv->v_type = VAR_STRING;
8797 rettv->vval.v_string = vim_strsave(buf);
8798}
8799
8800/*
8801 * "or(expr, expr)" function
8802 */
8803 static void
8804f_or(typval_T *argvars, typval_T *rettv)
8805{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008806 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8807 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008808}
8809
8810/*
8811 * "pathshorten()" function
8812 */
8813 static void
8814f_pathshorten(typval_T *argvars, typval_T *rettv)
8815{
8816 char_u *p;
8817
8818 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008819 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008820 if (p == NULL)
8821 rettv->vval.v_string = NULL;
8822 else
8823 {
8824 p = vim_strsave(p);
8825 rettv->vval.v_string = p;
8826 if (p != NULL)
8827 shorten_dir(p);
8828 }
8829}
8830
8831#ifdef FEAT_PERL
8832/*
8833 * "perleval()" function
8834 */
8835 static void
8836f_perleval(typval_T *argvars, typval_T *rettv)
8837{
8838 char_u *str;
8839 char_u buf[NUMBUFLEN];
8840
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008841 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008842 do_perleval(str, rettv);
8843}
8844#endif
8845
8846#ifdef FEAT_FLOAT
8847/*
8848 * "pow()" function
8849 */
8850 static void
8851f_pow(typval_T *argvars, typval_T *rettv)
8852{
8853 float_T fx = 0.0, fy = 0.0;
8854
8855 rettv->v_type = VAR_FLOAT;
8856 if (get_float_arg(argvars, &fx) == OK
8857 && get_float_arg(&argvars[1], &fy) == OK)
8858 rettv->vval.v_float = pow(fx, fy);
8859 else
8860 rettv->vval.v_float = 0.0;
8861}
8862#endif
8863
8864/*
8865 * "prevnonblank()" function
8866 */
8867 static void
8868f_prevnonblank(typval_T *argvars, typval_T *rettv)
8869{
8870 linenr_T lnum;
8871
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008872 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008873 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8874 lnum = 0;
8875 else
8876 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8877 --lnum;
8878 rettv->vval.v_number = lnum;
8879}
8880
8881/* This dummy va_list is here because:
8882 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8883 * - locally in the function results in a "used before set" warning
8884 * - using va_start() to initialize it gives "function with fixed args" error */
8885static va_list ap;
8886
8887/*
8888 * "printf()" function
8889 */
8890 static void
8891f_printf(typval_T *argvars, typval_T *rettv)
8892{
8893 char_u buf[NUMBUFLEN];
8894 int len;
8895 char_u *s;
8896 int saved_did_emsg = did_emsg;
8897 char *fmt;
8898
8899 rettv->v_type = VAR_STRING;
8900 rettv->vval.v_string = NULL;
8901
8902 /* Get the required length, allocate the buffer and do it for real. */
8903 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008904 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008905 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008906 if (!did_emsg)
8907 {
8908 s = alloc(len + 1);
8909 if (s != NULL)
8910 {
8911 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008912 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8913 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008914 }
8915 }
8916 did_emsg |= saved_did_emsg;
8917}
8918
Bram Moolenaarf2732452018-06-03 14:47:35 +02008919#ifdef FEAT_JOB_CHANNEL
8920/*
8921 * "prompt_setcallback({buffer}, {callback})" function
8922 */
8923 static void
8924f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8925{
8926 buf_T *buf;
8927 char_u *callback;
8928 partial_T *partial;
8929
8930 if (check_secure())
8931 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008932 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008933 if (buf == NULL)
8934 return;
8935
8936 callback = get_callback(&argvars[1], &partial);
8937 if (callback == NULL)
8938 return;
8939
8940 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8941 if (partial == NULL)
8942 buf->b_prompt_callback = vim_strsave(callback);
8943 else
8944 /* pointer into the partial */
8945 buf->b_prompt_callback = callback;
8946 buf->b_prompt_partial = partial;
8947}
8948
8949/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008950 * "prompt_setinterrupt({buffer}, {callback})" function
8951 */
8952 static void
8953f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8954{
8955 buf_T *buf;
8956 char_u *callback;
8957 partial_T *partial;
8958
8959 if (check_secure())
8960 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008961 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008962 if (buf == NULL)
8963 return;
8964
8965 callback = get_callback(&argvars[1], &partial);
8966 if (callback == NULL)
8967 return;
8968
8969 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8970 if (partial == NULL)
8971 buf->b_prompt_interrupt = vim_strsave(callback);
8972 else
8973 /* pointer into the partial */
8974 buf->b_prompt_interrupt = callback;
8975 buf->b_prompt_int_partial = partial;
8976}
8977
8978/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008979 * "prompt_setprompt({buffer}, {text})" function
8980 */
8981 static void
8982f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8983{
8984 buf_T *buf;
8985 char_u *text;
8986
8987 if (check_secure())
8988 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008989 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008990 if (buf == NULL)
8991 return;
8992
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008993 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008994 vim_free(buf->b_prompt_text);
8995 buf->b_prompt_text = vim_strsave(text);
8996}
8997#endif
8998
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008999/*
9000 * "pumvisible()" function
9001 */
9002 static void
9003f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9004{
9005#ifdef FEAT_INS_EXPAND
9006 if (pum_visible())
9007 rettv->vval.v_number = 1;
9008#endif
9009}
9010
9011#ifdef FEAT_PYTHON3
9012/*
9013 * "py3eval()" function
9014 */
9015 static void
9016f_py3eval(typval_T *argvars, typval_T *rettv)
9017{
9018 char_u *str;
9019 char_u buf[NUMBUFLEN];
9020
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009021 if (check_restricted() || check_secure())
9022 return;
9023
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009024 if (p_pyx == 0)
9025 p_pyx = 3;
9026
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009027 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009028 do_py3eval(str, rettv);
9029}
9030#endif
9031
9032#ifdef FEAT_PYTHON
9033/*
9034 * "pyeval()" function
9035 */
9036 static void
9037f_pyeval(typval_T *argvars, typval_T *rettv)
9038{
9039 char_u *str;
9040 char_u buf[NUMBUFLEN];
9041
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009042 if (check_restricted() || check_secure())
9043 return;
9044
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009045 if (p_pyx == 0)
9046 p_pyx = 2;
9047
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009048 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009049 do_pyeval(str, rettv);
9050}
9051#endif
9052
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009053#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
9054/*
9055 * "pyxeval()" function
9056 */
9057 static void
9058f_pyxeval(typval_T *argvars, typval_T *rettv)
9059{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009060 if (check_restricted() || check_secure())
9061 return;
9062
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009063# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
9064 init_pyxversion();
9065 if (p_pyx == 2)
9066 f_pyeval(argvars, rettv);
9067 else
9068 f_py3eval(argvars, rettv);
9069# elif defined(FEAT_PYTHON)
9070 f_pyeval(argvars, rettv);
9071# elif defined(FEAT_PYTHON3)
9072 f_py3eval(argvars, rettv);
9073# endif
9074}
9075#endif
9076
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009077/*
9078 * "range()" function
9079 */
9080 static void
9081f_range(typval_T *argvars, typval_T *rettv)
9082{
9083 varnumber_T start;
9084 varnumber_T end;
9085 varnumber_T stride = 1;
9086 varnumber_T i;
9087 int error = FALSE;
9088
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009089 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009090 if (argvars[1].v_type == VAR_UNKNOWN)
9091 {
9092 end = start - 1;
9093 start = 0;
9094 }
9095 else
9096 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009097 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009098 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009099 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009100 }
9101
9102 if (error)
9103 return; /* type error; errmsg already given */
9104 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009105 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009106 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009107 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009108 else
9109 {
9110 if (rettv_list_alloc(rettv) == OK)
9111 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9112 if (list_append_number(rettv->vval.v_list,
9113 (varnumber_T)i) == FAIL)
9114 break;
9115 }
9116}
9117
9118/*
9119 * "readfile()" function
9120 */
9121 static void
9122f_readfile(typval_T *argvars, typval_T *rettv)
9123{
9124 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009125 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009126 int failed = FALSE;
9127 char_u *fname;
9128 FILE *fd;
9129 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9130 int io_size = sizeof(buf);
9131 int readlen; /* size of last fread() */
9132 char_u *prev = NULL; /* previously read bytes, if any */
9133 long prevlen = 0; /* length of data in prev */
9134 long prevsize = 0; /* size of prev buffer */
9135 long maxline = MAXLNUM;
9136 long cnt = 0;
9137 char_u *p; /* position in buf */
9138 char_u *start; /* start of current line */
9139
9140 if (argvars[1].v_type != VAR_UNKNOWN)
9141 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009142 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009143 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009144 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9145 blob = TRUE;
9146
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009147 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009148 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009149 }
9150
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009151 if (blob)
9152 {
9153 if (rettv_blob_alloc(rettv) == FAIL)
9154 return;
9155 }
9156 else
9157 {
9158 if (rettv_list_alloc(rettv) == FAIL)
9159 return;
9160 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009161
9162 /* Always open the file in binary mode, library functions have a mind of
9163 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009164 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009165 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9166 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009167 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009168 return;
9169 }
9170
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009171 if (blob)
9172 {
9173 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9174 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009175 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009176 blob_free(rettv->vval.v_blob);
9177 }
9178 fclose(fd);
9179 return;
9180 }
9181
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009182 while (cnt < maxline || maxline < 0)
9183 {
9184 readlen = (int)fread(buf, 1, io_size, fd);
9185
9186 /* This for loop processes what was read, but is also entered at end
9187 * of file so that either:
9188 * - an incomplete line gets written
9189 * - a "binary" file gets an empty line at the end if it ends in a
9190 * newline. */
9191 for (p = buf, start = buf;
9192 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9193 ++p)
9194 {
9195 if (*p == '\n' || readlen <= 0)
9196 {
9197 listitem_T *li;
9198 char_u *s = NULL;
9199 long_u len = p - start;
9200
9201 /* Finished a line. Remove CRs before NL. */
9202 if (readlen > 0 && !binary)
9203 {
9204 while (len > 0 && start[len - 1] == '\r')
9205 --len;
9206 /* removal may cross back to the "prev" string */
9207 if (len == 0)
9208 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9209 --prevlen;
9210 }
9211 if (prevlen == 0)
9212 s = vim_strnsave(start, (int)len);
9213 else
9214 {
9215 /* Change "prev" buffer to be the right size. This way
9216 * the bytes are only copied once, and very long lines are
9217 * allocated only once. */
9218 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9219 {
9220 mch_memmove(s + prevlen, start, len);
9221 s[prevlen + len] = NUL;
9222 prev = NULL; /* the list will own the string */
9223 prevlen = prevsize = 0;
9224 }
9225 }
9226 if (s == NULL)
9227 {
9228 do_outofmem_msg((long_u) prevlen + len + 1);
9229 failed = TRUE;
9230 break;
9231 }
9232
9233 if ((li = listitem_alloc()) == NULL)
9234 {
9235 vim_free(s);
9236 failed = TRUE;
9237 break;
9238 }
9239 li->li_tv.v_type = VAR_STRING;
9240 li->li_tv.v_lock = 0;
9241 li->li_tv.vval.v_string = s;
9242 list_append(rettv->vval.v_list, li);
9243
9244 start = p + 1; /* step over newline */
9245 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9246 break;
9247 }
9248 else if (*p == NUL)
9249 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009250 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9251 * when finding the BF and check the previous two bytes. */
9252 else if (*p == 0xbf && enc_utf8 && !binary)
9253 {
9254 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9255 * + 1, these may be in the "prev" string. */
9256 char_u back1 = p >= buf + 1 ? p[-1]
9257 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9258 char_u back2 = p >= buf + 2 ? p[-2]
9259 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9260 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9261
9262 if (back2 == 0xef && back1 == 0xbb)
9263 {
9264 char_u *dest = p - 2;
9265
9266 /* Usually a BOM is at the beginning of a file, and so at
9267 * the beginning of a line; then we can just step over it.
9268 */
9269 if (start == dest)
9270 start = p + 1;
9271 else
9272 {
9273 /* have to shuffle buf to close gap */
9274 int adjust_prevlen = 0;
9275
9276 if (dest < buf)
9277 {
9278 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9279 dest = buf;
9280 }
9281 if (readlen > p - buf + 1)
9282 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9283 readlen -= 3 - adjust_prevlen;
9284 prevlen -= adjust_prevlen;
9285 p = dest - 1;
9286 }
9287 }
9288 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009289 } /* for */
9290
9291 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9292 break;
9293 if (start < p)
9294 {
9295 /* There's part of a line in buf, store it in "prev". */
9296 if (p - start + prevlen >= prevsize)
9297 {
9298 /* need bigger "prev" buffer */
9299 char_u *newprev;
9300
9301 /* A common use case is ordinary text files and "prev" gets a
9302 * fragment of a line, so the first allocation is made
9303 * small, to avoid repeatedly 'allocing' large and
9304 * 'reallocing' small. */
9305 if (prevsize == 0)
9306 prevsize = (long)(p - start);
9307 else
9308 {
9309 long grow50pc = (prevsize * 3) / 2;
9310 long growmin = (long)((p - start) * 2 + prevlen);
9311 prevsize = grow50pc > growmin ? grow50pc : growmin;
9312 }
9313 newprev = prev == NULL ? alloc(prevsize)
9314 : vim_realloc(prev, prevsize);
9315 if (newprev == NULL)
9316 {
9317 do_outofmem_msg((long_u)prevsize);
9318 failed = TRUE;
9319 break;
9320 }
9321 prev = newprev;
9322 }
9323 /* Add the line part to end of "prev". */
9324 mch_memmove(prev + prevlen, start, p - start);
9325 prevlen += (long)(p - start);
9326 }
9327 } /* while */
9328
9329 /*
9330 * For a negative line count use only the lines at the end of the file,
9331 * free the rest.
9332 */
9333 if (!failed && maxline < 0)
9334 while (cnt > -maxline)
9335 {
9336 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9337 --cnt;
9338 }
9339
9340 if (failed)
9341 {
9342 list_free(rettv->vval.v_list);
9343 /* readfile doc says an empty list is returned on error */
9344 rettv->vval.v_list = list_alloc();
9345 }
9346
9347 vim_free(prev);
9348 fclose(fd);
9349}
9350
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009351 static void
9352return_register(int regname, typval_T *rettv)
9353{
9354 char_u buf[2] = {0, 0};
9355
9356 buf[0] = (char_u)regname;
9357 rettv->v_type = VAR_STRING;
9358 rettv->vval.v_string = vim_strsave(buf);
9359}
9360
9361/*
9362 * "reg_executing()" function
9363 */
9364 static void
9365f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9366{
9367 return_register(reg_executing, rettv);
9368}
9369
9370/*
9371 * "reg_recording()" function
9372 */
9373 static void
9374f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9375{
9376 return_register(reg_recording, rettv);
9377}
9378
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009379#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009380/*
9381 * Convert a List to proftime_T.
9382 * Return FAIL when there is something wrong.
9383 */
9384 static int
9385list2proftime(typval_T *arg, proftime_T *tm)
9386{
9387 long n1, n2;
9388 int error = FALSE;
9389
9390 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9391 || arg->vval.v_list->lv_len != 2)
9392 return FAIL;
9393 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9394 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009395# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009396 tm->HighPart = n1;
9397 tm->LowPart = n2;
9398# else
9399 tm->tv_sec = n1;
9400 tm->tv_usec = n2;
9401# endif
9402 return error ? FAIL : OK;
9403}
9404#endif /* FEAT_RELTIME */
9405
9406/*
9407 * "reltime()" function
9408 */
9409 static void
9410f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9411{
9412#ifdef FEAT_RELTIME
9413 proftime_T res;
9414 proftime_T start;
9415
9416 if (argvars[0].v_type == VAR_UNKNOWN)
9417 {
9418 /* No arguments: get current time. */
9419 profile_start(&res);
9420 }
9421 else if (argvars[1].v_type == VAR_UNKNOWN)
9422 {
9423 if (list2proftime(&argvars[0], &res) == FAIL)
9424 return;
9425 profile_end(&res);
9426 }
9427 else
9428 {
9429 /* Two arguments: compute the difference. */
9430 if (list2proftime(&argvars[0], &start) == FAIL
9431 || list2proftime(&argvars[1], &res) == FAIL)
9432 return;
9433 profile_sub(&res, &start);
9434 }
9435
9436 if (rettv_list_alloc(rettv) == OK)
9437 {
9438 long n1, n2;
9439
Bram Moolenaar4f974752019-02-17 17:44:42 +01009440# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009441 n1 = res.HighPart;
9442 n2 = res.LowPart;
9443# else
9444 n1 = res.tv_sec;
9445 n2 = res.tv_usec;
9446# endif
9447 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9448 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9449 }
9450#endif
9451}
9452
9453#ifdef FEAT_FLOAT
9454/*
9455 * "reltimefloat()" function
9456 */
9457 static void
9458f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9459{
9460# ifdef FEAT_RELTIME
9461 proftime_T tm;
9462# endif
9463
9464 rettv->v_type = VAR_FLOAT;
9465 rettv->vval.v_float = 0;
9466# ifdef FEAT_RELTIME
9467 if (list2proftime(&argvars[0], &tm) == OK)
9468 rettv->vval.v_float = profile_float(&tm);
9469# endif
9470}
9471#endif
9472
9473/*
9474 * "reltimestr()" function
9475 */
9476 static void
9477f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9478{
9479#ifdef FEAT_RELTIME
9480 proftime_T tm;
9481#endif
9482
9483 rettv->v_type = VAR_STRING;
9484 rettv->vval.v_string = NULL;
9485#ifdef FEAT_RELTIME
9486 if (list2proftime(&argvars[0], &tm) == OK)
9487 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9488#endif
9489}
9490
9491#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009492 static void
9493make_connection(void)
9494{
9495 if (X_DISPLAY == NULL
9496# ifdef FEAT_GUI
9497 && !gui.in_use
9498# endif
9499 )
9500 {
9501 x_force_connect = TRUE;
9502 setup_term_clip();
9503 x_force_connect = FALSE;
9504 }
9505}
9506
9507 static int
9508check_connection(void)
9509{
9510 make_connection();
9511 if (X_DISPLAY == NULL)
9512 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009513 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009514 return FAIL;
9515 }
9516 return OK;
9517}
9518#endif
9519
9520#ifdef FEAT_CLIENTSERVER
9521 static void
9522remote_common(typval_T *argvars, typval_T *rettv, int expr)
9523{
9524 char_u *server_name;
9525 char_u *keys;
9526 char_u *r = NULL;
9527 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009528 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009529# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009530 HWND w;
9531# else
9532 Window w;
9533# endif
9534
9535 if (check_restricted() || check_secure())
9536 return;
9537
9538# ifdef FEAT_X11
9539 if (check_connection() == FAIL)
9540 return;
9541# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009542 if (argvars[2].v_type != VAR_UNKNOWN
9543 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009544 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009545
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009546 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009547 if (server_name == NULL)
9548 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009549 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009550# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009551 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009552# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009553 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9554 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009555# endif
9556 {
9557 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009558 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009559 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009560 vim_free(r);
9561 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009562 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009563 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009564 return;
9565 }
9566
9567 rettv->vval.v_string = r;
9568
9569 if (argvars[2].v_type != VAR_UNKNOWN)
9570 {
9571 dictitem_T v;
9572 char_u str[30];
9573 char_u *idvar;
9574
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009575 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009576 if (idvar != NULL && *idvar != NUL)
9577 {
9578 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9579 v.di_tv.v_type = VAR_STRING;
9580 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009581 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009582 vim_free(v.di_tv.vval.v_string);
9583 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009584 }
9585}
9586#endif
9587
9588/*
9589 * "remote_expr()" function
9590 */
9591 static void
9592f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9593{
9594 rettv->v_type = VAR_STRING;
9595 rettv->vval.v_string = NULL;
9596#ifdef FEAT_CLIENTSERVER
9597 remote_common(argvars, rettv, TRUE);
9598#endif
9599}
9600
9601/*
9602 * "remote_foreground()" function
9603 */
9604 static void
9605f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9606{
9607#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009608# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009609 /* On Win32 it's done in this application. */
9610 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009611 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009612
9613 if (server_name != NULL)
9614 serverForeground(server_name);
9615 }
9616# else
9617 /* Send a foreground() expression to the server. */
9618 argvars[1].v_type = VAR_STRING;
9619 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9620 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009621 rettv->v_type = VAR_STRING;
9622 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009623 remote_common(argvars, rettv, TRUE);
9624 vim_free(argvars[1].vval.v_string);
9625# endif
9626#endif
9627}
9628
9629 static void
9630f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9631{
9632#ifdef FEAT_CLIENTSERVER
9633 dictitem_T v;
9634 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009635# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009636 long_u n = 0;
9637# endif
9638 char_u *serverid;
9639
9640 if (check_restricted() || check_secure())
9641 {
9642 rettv->vval.v_number = -1;
9643 return;
9644 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009645 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009646 if (serverid == NULL)
9647 {
9648 rettv->vval.v_number = -1;
9649 return; /* type error; errmsg already given */
9650 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009651# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009652 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9653 if (n == 0)
9654 rettv->vval.v_number = -1;
9655 else
9656 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009657 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009658 rettv->vval.v_number = (s != NULL);
9659 }
9660# else
9661 if (check_connection() == FAIL)
9662 return;
9663
9664 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9665 serverStrToWin(serverid), &s);
9666# endif
9667
9668 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9669 {
9670 char_u *retvar;
9671
9672 v.di_tv.v_type = VAR_STRING;
9673 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009674 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009675 if (retvar != NULL)
9676 set_var(retvar, &v.di_tv, FALSE);
9677 vim_free(v.di_tv.vval.v_string);
9678 }
9679#else
9680 rettv->vval.v_number = -1;
9681#endif
9682}
9683
9684 static void
9685f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9686{
9687 char_u *r = NULL;
9688
9689#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009690 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009691
9692 if (serverid != NULL && !check_restricted() && !check_secure())
9693 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009694 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009695# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009696 /* The server's HWND is encoded in the 'id' parameter */
9697 long_u n = 0;
9698# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009699
9700 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009701 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009702
Bram Moolenaar4f974752019-02-17 17:44:42 +01009703# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009704 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9705 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009706 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009707 if (r == NULL)
9708# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009709 if (check_connection() == FAIL
9710 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9711 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009712# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009713 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009714 }
9715#endif
9716 rettv->v_type = VAR_STRING;
9717 rettv->vval.v_string = r;
9718}
9719
9720/*
9721 * "remote_send()" function
9722 */
9723 static void
9724f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9725{
9726 rettv->v_type = VAR_STRING;
9727 rettv->vval.v_string = NULL;
9728#ifdef FEAT_CLIENTSERVER
9729 remote_common(argvars, rettv, FALSE);
9730#endif
9731}
9732
9733/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009734 * "remote_startserver()" function
9735 */
9736 static void
9737f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9738{
9739#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009740 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009741
9742 if (server == NULL)
9743 return; /* type error; errmsg already given */
9744 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009745 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009746 else
9747 {
9748# ifdef FEAT_X11
9749 if (check_connection() == OK)
9750 serverRegisterName(X_DISPLAY, server);
9751# else
9752 serverSetName(server);
9753# endif
9754 }
9755#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009756 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009757#endif
9758}
9759
9760/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009761 * "remove()" function
9762 */
9763 static void
9764f_remove(typval_T *argvars, typval_T *rettv)
9765{
9766 list_T *l;
9767 listitem_T *item, *item2;
9768 listitem_T *li;
9769 long idx;
9770 long end;
9771 char_u *key;
9772 dict_T *d;
9773 dictitem_T *di;
9774 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009775 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009776
9777 if (argvars[0].v_type == VAR_DICT)
9778 {
9779 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009780 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009781 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009782 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009783 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009784 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009785 if (key != NULL)
9786 {
9787 di = dict_find(d, key, -1);
9788 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009789 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009790 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9791 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9792 {
9793 *rettv = di->di_tv;
9794 init_tv(&di->di_tv);
9795 dictitem_remove(d, di);
9796 }
9797 }
9798 }
9799 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009800 else if (argvars[0].v_type == VAR_BLOB)
9801 {
9802 idx = (long)tv_get_number_chk(&argvars[1], &error);
9803 if (!error)
9804 {
9805 blob_T *b = argvars[0].vval.v_blob;
9806 int len = blob_len(b);
9807 char_u *p;
9808
9809 if (idx < 0)
9810 // count from the end
9811 idx = len + idx;
9812 if (idx < 0 || idx >= len)
9813 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009814 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009815 return;
9816 }
9817 if (argvars[2].v_type == VAR_UNKNOWN)
9818 {
9819 // Remove one item, return its value.
9820 p = (char_u *)b->bv_ga.ga_data;
9821 rettv->vval.v_number = (varnumber_T) *(p + idx);
9822 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9823 --b->bv_ga.ga_len;
9824 }
9825 else
9826 {
9827 blob_T *blob;
9828
9829 // Remove range of items, return list with values.
9830 end = (long)tv_get_number_chk(&argvars[2], &error);
9831 if (error)
9832 return;
9833 if (end < 0)
9834 // count from the end
9835 end = len + end;
9836 if (end >= len || idx > end)
9837 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009838 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009839 return;
9840 }
9841 blob = blob_alloc();
9842 if (blob == NULL)
9843 return;
9844 blob->bv_ga.ga_len = end - idx + 1;
9845 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9846 {
9847 vim_free(blob);
9848 return;
9849 }
9850 p = (char_u *)b->bv_ga.ga_data;
9851 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9852 (size_t)(end - idx + 1));
9853 ++blob->bv_refcount;
9854 rettv->v_type = VAR_BLOB;
9855 rettv->vval.v_blob = blob;
9856
9857 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9858 b->bv_ga.ga_len -= end - idx + 1;
9859 }
9860 }
9861 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009862 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009863 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009864 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009865 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009866 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009867 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009868 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009869 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009870 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009871 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009872 else
9873 {
9874 if (argvars[2].v_type == VAR_UNKNOWN)
9875 {
9876 /* Remove one item, return its value. */
9877 vimlist_remove(l, item, item);
9878 *rettv = item->li_tv;
9879 vim_free(item);
9880 }
9881 else
9882 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009883 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009884 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009885 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009886 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009887 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009888 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009889 else
9890 {
9891 int cnt = 0;
9892
9893 for (li = item; li != NULL; li = li->li_next)
9894 {
9895 ++cnt;
9896 if (li == item2)
9897 break;
9898 }
9899 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009900 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009901 else
9902 {
9903 vimlist_remove(l, item, item2);
9904 if (rettv_list_alloc(rettv) == OK)
9905 {
9906 l = rettv->vval.v_list;
9907 l->lv_first = item;
9908 l->lv_last = item2;
9909 item->li_prev = NULL;
9910 item2->li_next = NULL;
9911 l->lv_len = cnt;
9912 }
9913 }
9914 }
9915 }
9916 }
9917 }
9918}
9919
9920/*
9921 * "rename({from}, {to})" function
9922 */
9923 static void
9924f_rename(typval_T *argvars, typval_T *rettv)
9925{
9926 char_u buf[NUMBUFLEN];
9927
9928 if (check_restricted() || check_secure())
9929 rettv->vval.v_number = -1;
9930 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009931 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9932 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009933}
9934
9935/*
9936 * "repeat()" function
9937 */
9938 static void
9939f_repeat(typval_T *argvars, typval_T *rettv)
9940{
9941 char_u *p;
9942 int n;
9943 int slen;
9944 int len;
9945 char_u *r;
9946 int i;
9947
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009948 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009949 if (argvars[0].v_type == VAR_LIST)
9950 {
9951 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9952 while (n-- > 0)
9953 if (list_extend(rettv->vval.v_list,
9954 argvars[0].vval.v_list, NULL) == FAIL)
9955 break;
9956 }
9957 else
9958 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009959 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009960 rettv->v_type = VAR_STRING;
9961 rettv->vval.v_string = NULL;
9962
9963 slen = (int)STRLEN(p);
9964 len = slen * n;
9965 if (len <= 0)
9966 return;
9967
9968 r = alloc(len + 1);
9969 if (r != NULL)
9970 {
9971 for (i = 0; i < n; i++)
9972 mch_memmove(r + i * slen, p, (size_t)slen);
9973 r[len] = NUL;
9974 }
9975
9976 rettv->vval.v_string = r;
9977 }
9978}
9979
9980/*
9981 * "resolve()" function
9982 */
9983 static void
9984f_resolve(typval_T *argvars, typval_T *rettv)
9985{
9986 char_u *p;
9987#ifdef HAVE_READLINK
9988 char_u *buf = NULL;
9989#endif
9990
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009991 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009992#ifdef FEAT_SHORTCUT
9993 {
9994 char_u *v = NULL;
9995
Bram Moolenaardce1e892019-02-10 23:18:53 +01009996 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009997 if (v != NULL)
9998 rettv->vval.v_string = v;
9999 else
10000 rettv->vval.v_string = vim_strsave(p);
10001 }
10002#else
10003# ifdef HAVE_READLINK
10004 {
10005 char_u *cpy;
10006 int len;
10007 char_u *remain = NULL;
10008 char_u *q;
10009 int is_relative_to_current = FALSE;
10010 int has_trailing_pathsep = FALSE;
10011 int limit = 100;
10012
10013 p = vim_strsave(p);
10014
10015 if (p[0] == '.' && (vim_ispathsep(p[1])
10016 || (p[1] == '.' && (vim_ispathsep(p[2])))))
10017 is_relative_to_current = TRUE;
10018
10019 len = STRLEN(p);
10020 if (len > 0 && after_pathsep(p, p + len))
10021 {
10022 has_trailing_pathsep = TRUE;
10023 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
10024 }
10025
10026 q = getnextcomp(p);
10027 if (*q != NUL)
10028 {
10029 /* Separate the first path component in "p", and keep the
10030 * remainder (beginning with the path separator). */
10031 remain = vim_strsave(q - 1);
10032 q[-1] = NUL;
10033 }
10034
10035 buf = alloc(MAXPATHL + 1);
10036 if (buf == NULL)
10037 goto fail;
10038
10039 for (;;)
10040 {
10041 for (;;)
10042 {
10043 len = readlink((char *)p, (char *)buf, MAXPATHL);
10044 if (len <= 0)
10045 break;
10046 buf[len] = NUL;
10047
10048 if (limit-- == 0)
10049 {
10050 vim_free(p);
10051 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010052 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010053 rettv->vval.v_string = NULL;
10054 goto fail;
10055 }
10056
10057 /* Ensure that the result will have a trailing path separator
10058 * if the argument has one. */
10059 if (remain == NULL && has_trailing_pathsep)
10060 add_pathsep(buf);
10061
10062 /* Separate the first path component in the link value and
10063 * concatenate the remainders. */
10064 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10065 if (*q != NUL)
10066 {
10067 if (remain == NULL)
10068 remain = vim_strsave(q - 1);
10069 else
10070 {
10071 cpy = concat_str(q - 1, remain);
10072 if (cpy != NULL)
10073 {
10074 vim_free(remain);
10075 remain = cpy;
10076 }
10077 }
10078 q[-1] = NUL;
10079 }
10080
10081 q = gettail(p);
10082 if (q > p && *q == NUL)
10083 {
10084 /* Ignore trailing path separator. */
10085 q[-1] = NUL;
10086 q = gettail(p);
10087 }
10088 if (q > p && !mch_isFullName(buf))
10089 {
10090 /* symlink is relative to directory of argument */
10091 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10092 if (cpy != NULL)
10093 {
10094 STRCPY(cpy, p);
10095 STRCPY(gettail(cpy), buf);
10096 vim_free(p);
10097 p = cpy;
10098 }
10099 }
10100 else
10101 {
10102 vim_free(p);
10103 p = vim_strsave(buf);
10104 }
10105 }
10106
10107 if (remain == NULL)
10108 break;
10109
10110 /* Append the first path component of "remain" to "p". */
10111 q = getnextcomp(remain + 1);
10112 len = q - remain - (*q != NUL);
10113 cpy = vim_strnsave(p, STRLEN(p) + len);
10114 if (cpy != NULL)
10115 {
10116 STRNCAT(cpy, remain, len);
10117 vim_free(p);
10118 p = cpy;
10119 }
10120 /* Shorten "remain". */
10121 if (*q != NUL)
10122 STRMOVE(remain, q - 1);
10123 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010124 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010125 }
10126
10127 /* If the result is a relative path name, make it explicitly relative to
10128 * the current directory if and only if the argument had this form. */
10129 if (!vim_ispathsep(*p))
10130 {
10131 if (is_relative_to_current
10132 && *p != NUL
10133 && !(p[0] == '.'
10134 && (p[1] == NUL
10135 || vim_ispathsep(p[1])
10136 || (p[1] == '.'
10137 && (p[2] == NUL
10138 || vim_ispathsep(p[2]))))))
10139 {
10140 /* Prepend "./". */
10141 cpy = concat_str((char_u *)"./", p);
10142 if (cpy != NULL)
10143 {
10144 vim_free(p);
10145 p = cpy;
10146 }
10147 }
10148 else if (!is_relative_to_current)
10149 {
10150 /* Strip leading "./". */
10151 q = p;
10152 while (q[0] == '.' && vim_ispathsep(q[1]))
10153 q += 2;
10154 if (q > p)
10155 STRMOVE(p, p + 2);
10156 }
10157 }
10158
10159 /* Ensure that the result will have no trailing path separator
10160 * if the argument had none. But keep "/" or "//". */
10161 if (!has_trailing_pathsep)
10162 {
10163 q = p + STRLEN(p);
10164 if (after_pathsep(p, q))
10165 *gettail_sep(p) = NUL;
10166 }
10167
10168 rettv->vval.v_string = p;
10169 }
10170# else
10171 rettv->vval.v_string = vim_strsave(p);
10172# endif
10173#endif
10174
10175 simplify_filename(rettv->vval.v_string);
10176
10177#ifdef HAVE_READLINK
10178fail:
10179 vim_free(buf);
10180#endif
10181 rettv->v_type = VAR_STRING;
10182}
10183
10184/*
10185 * "reverse({list})" function
10186 */
10187 static void
10188f_reverse(typval_T *argvars, typval_T *rettv)
10189{
10190 list_T *l;
10191 listitem_T *li, *ni;
10192
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010193 if (argvars[0].v_type == VAR_BLOB)
10194 {
10195 blob_T *b = argvars[0].vval.v_blob;
10196 int i, len = blob_len(b);
10197
10198 for (i = 0; i < len / 2; i++)
10199 {
10200 int tmp = blob_get(b, i);
10201
10202 blob_set(b, i, blob_get(b, len - i - 1));
10203 blob_set(b, len - i - 1, tmp);
10204 }
10205 rettv_blob_set(rettv, b);
10206 return;
10207 }
10208
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010209 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010210 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010211 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010212 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010213 (char_u *)N_("reverse() argument"), TRUE))
10214 {
10215 li = l->lv_last;
10216 l->lv_first = l->lv_last = NULL;
10217 l->lv_len = 0;
10218 while (li != NULL)
10219 {
10220 ni = li->li_prev;
10221 list_append(l, li);
10222 li = ni;
10223 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010224 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010225 l->lv_idx = l->lv_len - l->lv_idx - 1;
10226 }
10227}
10228
10229#define SP_NOMOVE 0x01 /* don't move cursor */
10230#define SP_REPEAT 0x02 /* repeat to find outer pair */
10231#define SP_RETCOUNT 0x04 /* return matchcount */
10232#define SP_SETPCMARK 0x08 /* set previous context mark */
10233#define SP_START 0x10 /* accept match at start position */
10234#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10235#define SP_END 0x40 /* leave cursor at end of match */
10236#define SP_COLUMN 0x80 /* start at cursor column */
10237
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010238/*
10239 * Get flags for a search function.
10240 * Possibly sets "p_ws".
10241 * Returns BACKWARD, FORWARD or zero (for an error).
10242 */
10243 static int
10244get_search_arg(typval_T *varp, int *flagsp)
10245{
10246 int dir = FORWARD;
10247 char_u *flags;
10248 char_u nbuf[NUMBUFLEN];
10249 int mask;
10250
10251 if (varp->v_type != VAR_UNKNOWN)
10252 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010253 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010254 if (flags == NULL)
10255 return 0; /* type error; errmsg already given */
10256 while (*flags != NUL)
10257 {
10258 switch (*flags)
10259 {
10260 case 'b': dir = BACKWARD; break;
10261 case 'w': p_ws = TRUE; break;
10262 case 'W': p_ws = FALSE; break;
10263 default: mask = 0;
10264 if (flagsp != NULL)
10265 switch (*flags)
10266 {
10267 case 'c': mask = SP_START; break;
10268 case 'e': mask = SP_END; break;
10269 case 'm': mask = SP_RETCOUNT; break;
10270 case 'n': mask = SP_NOMOVE; break;
10271 case 'p': mask = SP_SUBPAT; break;
10272 case 'r': mask = SP_REPEAT; break;
10273 case 's': mask = SP_SETPCMARK; break;
10274 case 'z': mask = SP_COLUMN; break;
10275 }
10276 if (mask == 0)
10277 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010278 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010279 dir = 0;
10280 }
10281 else
10282 *flagsp |= mask;
10283 }
10284 if (dir == 0)
10285 break;
10286 ++flags;
10287 }
10288 }
10289 return dir;
10290}
10291
10292/*
10293 * Shared by search() and searchpos() functions.
10294 */
10295 static int
10296search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10297{
10298 int flags;
10299 char_u *pat;
10300 pos_T pos;
10301 pos_T save_cursor;
10302 int save_p_ws = p_ws;
10303 int dir;
10304 int retval = 0; /* default: FAIL */
10305 long lnum_stop = 0;
10306 proftime_T tm;
10307#ifdef FEAT_RELTIME
10308 long time_limit = 0;
10309#endif
10310 int options = SEARCH_KEEP;
10311 int subpatnum;
10312
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010313 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010314 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10315 if (dir == 0)
10316 goto theend;
10317 flags = *flagsp;
10318 if (flags & SP_START)
10319 options |= SEARCH_START;
10320 if (flags & SP_END)
10321 options |= SEARCH_END;
10322 if (flags & SP_COLUMN)
10323 options |= SEARCH_COL;
10324
10325 /* Optional arguments: line number to stop searching and timeout. */
10326 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10327 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010328 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010329 if (lnum_stop < 0)
10330 goto theend;
10331#ifdef FEAT_RELTIME
10332 if (argvars[3].v_type != VAR_UNKNOWN)
10333 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010334 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010335 if (time_limit < 0)
10336 goto theend;
10337 }
10338#endif
10339 }
10340
10341#ifdef FEAT_RELTIME
10342 /* Set the time limit, if there is one. */
10343 profile_setlimit(time_limit, &tm);
10344#endif
10345
10346 /*
10347 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10348 * Check to make sure only those flags are set.
10349 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10350 * flags cannot be set. Check for that condition also.
10351 */
10352 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10353 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10354 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010355 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010356 goto theend;
10357 }
10358
10359 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010360 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010361 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010362 if (subpatnum != FAIL)
10363 {
10364 if (flags & SP_SUBPAT)
10365 retval = subpatnum;
10366 else
10367 retval = pos.lnum;
10368 if (flags & SP_SETPCMARK)
10369 setpcmark();
10370 curwin->w_cursor = pos;
10371 if (match_pos != NULL)
10372 {
10373 /* Store the match cursor position */
10374 match_pos->lnum = pos.lnum;
10375 match_pos->col = pos.col + 1;
10376 }
10377 /* "/$" will put the cursor after the end of the line, may need to
10378 * correct that here */
10379 check_cursor();
10380 }
10381
10382 /* If 'n' flag is used: restore cursor position. */
10383 if (flags & SP_NOMOVE)
10384 curwin->w_cursor = save_cursor;
10385 else
10386 curwin->w_set_curswant = TRUE;
10387theend:
10388 p_ws = save_p_ws;
10389
10390 return retval;
10391}
10392
10393#ifdef FEAT_FLOAT
10394
10395/*
10396 * round() is not in C90, use ceil() or floor() instead.
10397 */
10398 float_T
10399vim_round(float_T f)
10400{
10401 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10402}
10403
10404/*
10405 * "round({float})" function
10406 */
10407 static void
10408f_round(typval_T *argvars, typval_T *rettv)
10409{
10410 float_T f = 0.0;
10411
10412 rettv->v_type = VAR_FLOAT;
10413 if (get_float_arg(argvars, &f) == OK)
10414 rettv->vval.v_float = vim_round(f);
10415 else
10416 rettv->vval.v_float = 0.0;
10417}
10418#endif
10419
Bram Moolenaare99be0e2019-03-26 22:51:09 +010010420#ifdef FEAT_RUBY
10421/*
10422 * "rubyeval()" function
10423 */
10424 static void
10425f_rubyeval(typval_T *argvars, typval_T *rettv)
10426{
10427 char_u *str;
10428 char_u buf[NUMBUFLEN];
10429
10430 str = tv_get_string_buf(&argvars[0], buf);
10431 do_rubyeval(str, rettv);
10432}
10433#endif
10434
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010435/*
10436 * "screenattr()" function
10437 */
10438 static void
10439f_screenattr(typval_T *argvars, typval_T *rettv)
10440{
10441 int row;
10442 int col;
10443 int c;
10444
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010445 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10446 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010447 if (row < 0 || row >= screen_Rows
10448 || col < 0 || col >= screen_Columns)
10449 c = -1;
10450 else
10451 c = ScreenAttrs[LineOffset[row] + col];
10452 rettv->vval.v_number = c;
10453}
10454
10455/*
10456 * "screenchar()" function
10457 */
10458 static void
10459f_screenchar(typval_T *argvars, typval_T *rettv)
10460{
10461 int row;
10462 int col;
10463 int off;
10464 int c;
10465
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010466 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10467 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010468 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010469 c = -1;
10470 else
10471 {
10472 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010473 if (enc_utf8 && ScreenLinesUC[off] != 0)
10474 c = ScreenLinesUC[off];
10475 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010476 c = ScreenLines[off];
10477 }
10478 rettv->vval.v_number = c;
10479}
10480
10481/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010482 * "screenchars()" function
10483 */
10484 static void
10485f_screenchars(typval_T *argvars, typval_T *rettv)
10486{
10487 int row;
10488 int col;
10489 int off;
10490 int c;
10491 int i;
10492
10493 if (rettv_list_alloc(rettv) == FAIL)
10494 return;
10495 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10496 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10497 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10498 return;
10499
10500 off = LineOffset[row] + col;
10501 if (enc_utf8 && ScreenLinesUC[off] != 0)
10502 c = ScreenLinesUC[off];
10503 else
10504 c = ScreenLines[off];
10505 list_append_number(rettv->vval.v_list, (varnumber_T)c);
10506
10507 if (enc_utf8)
10508
10509 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10510 list_append_number(rettv->vval.v_list,
10511 (varnumber_T)ScreenLinesC[i][off]);
10512}
10513
10514/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010515 * "screencol()" function
10516 *
10517 * First column is 1 to be consistent with virtcol().
10518 */
10519 static void
10520f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10521{
10522 rettv->vval.v_number = screen_screencol() + 1;
10523}
10524
10525/*
10526 * "screenrow()" function
10527 */
10528 static void
10529f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10530{
10531 rettv->vval.v_number = screen_screenrow() + 1;
10532}
10533
10534/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010535 * "screenstring()" function
10536 */
10537 static void
10538f_screenstring(typval_T *argvars, typval_T *rettv)
10539{
10540 int row;
10541 int col;
10542 int off;
10543 int c;
10544 int i;
10545 char_u buf[MB_MAXBYTES + 1];
10546 int buflen = 0;
10547
10548 rettv->vval.v_string = NULL;
10549 rettv->v_type = VAR_STRING;
10550
10551 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10552 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10553 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10554 return;
10555
10556 off = LineOffset[row] + col;
10557 if (enc_utf8 && ScreenLinesUC[off] != 0)
10558 c = ScreenLinesUC[off];
10559 else
10560 c = ScreenLines[off];
10561 buflen += mb_char2bytes(c, buf);
10562
10563 if (enc_utf8)
10564 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10565 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
10566
10567 buf[buflen] = NUL;
10568 rettv->vval.v_string = vim_strsave(buf);
10569}
10570
10571/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010572 * "search()" function
10573 */
10574 static void
10575f_search(typval_T *argvars, typval_T *rettv)
10576{
10577 int flags = 0;
10578
10579 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10580}
10581
10582/*
10583 * "searchdecl()" function
10584 */
10585 static void
10586f_searchdecl(typval_T *argvars, typval_T *rettv)
10587{
10588 int locally = 1;
10589 int thisblock = 0;
10590 int error = FALSE;
10591 char_u *name;
10592
10593 rettv->vval.v_number = 1; /* default: FAIL */
10594
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010595 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010596 if (argvars[1].v_type != VAR_UNKNOWN)
10597 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010598 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010599 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010600 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010601 }
10602 if (!error && name != NULL)
10603 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10604 locally, thisblock, SEARCH_KEEP) == FAIL;
10605}
10606
10607/*
10608 * Used by searchpair() and searchpairpos()
10609 */
10610 static int
10611searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10612{
10613 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010614 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010615 int save_p_ws = p_ws;
10616 int dir;
10617 int flags = 0;
10618 char_u nbuf1[NUMBUFLEN];
10619 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010620 int retval = 0; /* default: FAIL */
10621 long lnum_stop = 0;
10622 long time_limit = 0;
10623
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010624 /* Get the three pattern arguments: start, middle, end. Will result in an
10625 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010626 spat = tv_get_string_chk(&argvars[0]);
10627 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10628 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010629 if (spat == NULL || mpat == NULL || epat == NULL)
10630 goto theend; /* type error */
10631
10632 /* Handle the optional fourth argument: flags */
10633 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10634 if (dir == 0)
10635 goto theend;
10636
10637 /* Don't accept SP_END or SP_SUBPAT.
10638 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10639 */
10640 if ((flags & (SP_END | SP_SUBPAT)) != 0
10641 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10642 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010643 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 goto theend;
10645 }
10646
10647 /* Using 'r' implies 'W', otherwise it doesn't work. */
10648 if (flags & SP_REPEAT)
10649 p_ws = FALSE;
10650
10651 /* Optional fifth argument: skip expression */
10652 if (argvars[3].v_type == VAR_UNKNOWN
10653 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010654 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010655 else
10656 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010657 skip = &argvars[4];
10658 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10659 && skip->v_type != VAR_STRING)
10660 {
10661 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010662 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010663 goto theend;
10664 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010665 if (argvars[5].v_type != VAR_UNKNOWN)
10666 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010667 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010668 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010669 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010670 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010671 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010672 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010673#ifdef FEAT_RELTIME
10674 if (argvars[6].v_type != VAR_UNKNOWN)
10675 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010676 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010677 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010678 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010679 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010680 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010681 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010682 }
10683#endif
10684 }
10685 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010686
10687 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10688 match_pos, lnum_stop, time_limit);
10689
10690theend:
10691 p_ws = save_p_ws;
10692
10693 return retval;
10694}
10695
10696/*
10697 * "searchpair()" function
10698 */
10699 static void
10700f_searchpair(typval_T *argvars, typval_T *rettv)
10701{
10702 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10703}
10704
10705/*
10706 * "searchpairpos()" function
10707 */
10708 static void
10709f_searchpairpos(typval_T *argvars, typval_T *rettv)
10710{
10711 pos_T match_pos;
10712 int lnum = 0;
10713 int col = 0;
10714
10715 if (rettv_list_alloc(rettv) == FAIL)
10716 return;
10717
10718 if (searchpair_cmn(argvars, &match_pos) > 0)
10719 {
10720 lnum = match_pos.lnum;
10721 col = match_pos.col;
10722 }
10723
10724 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10725 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10726}
10727
10728/*
10729 * Search for a start/middle/end thing.
10730 * Used by searchpair(), see its documentation for the details.
10731 * Returns 0 or -1 for no match,
10732 */
10733 long
10734do_searchpair(
10735 char_u *spat, /* start pattern */
10736 char_u *mpat, /* middle pattern */
10737 char_u *epat, /* end pattern */
10738 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010739 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010740 int flags, /* SP_SETPCMARK and other SP_ values */
10741 pos_T *match_pos,
10742 linenr_T lnum_stop, /* stop at this line if not zero */
10743 long time_limit UNUSED) /* stop after this many msec */
10744{
10745 char_u *save_cpo;
10746 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10747 long retval = 0;
10748 pos_T pos;
10749 pos_T firstpos;
10750 pos_T foundpos;
10751 pos_T save_cursor;
10752 pos_T save_pos;
10753 int n;
10754 int r;
10755 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010756 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010757 int err;
10758 int options = SEARCH_KEEP;
10759 proftime_T tm;
10760
10761 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10762 save_cpo = p_cpo;
10763 p_cpo = empty_option;
10764
10765#ifdef FEAT_RELTIME
10766 /* Set the time limit, if there is one. */
10767 profile_setlimit(time_limit, &tm);
10768#endif
10769
10770 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10771 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010772 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10773 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010774 if (pat2 == NULL || pat3 == NULL)
10775 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010776 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010777 if (*mpat == NUL)
10778 STRCPY(pat3, pat2);
10779 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010780 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010781 spat, epat, mpat);
10782 if (flags & SP_START)
10783 options |= SEARCH_START;
10784
Bram Moolenaar48570482017-10-30 21:48:41 +010010785 if (skip != NULL)
10786 {
10787 /* Empty string means to not use the skip expression. */
10788 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10789 use_skip = skip->vval.v_string != NULL
10790 && *skip->vval.v_string != NUL;
10791 }
10792
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010793 save_cursor = curwin->w_cursor;
10794 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010795 CLEAR_POS(&firstpos);
10796 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010797 pat = pat3;
10798 for (;;)
10799 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010800 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010801 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010802 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010803 /* didn't find it or found the first match again: FAIL */
10804 break;
10805
10806 if (firstpos.lnum == 0)
10807 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010808 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010809 {
10810 /* Found the same position again. Can happen with a pattern that
10811 * has "\zs" at the end and searching backwards. Advance one
10812 * character and try again. */
10813 if (dir == BACKWARD)
10814 decl(&pos);
10815 else
10816 incl(&pos);
10817 }
10818 foundpos = pos;
10819
10820 /* clear the start flag to avoid getting stuck here */
10821 options &= ~SEARCH_START;
10822
10823 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010824 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010825 {
10826 save_pos = curwin->w_cursor;
10827 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010828 err = FALSE;
10829 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010830 curwin->w_cursor = save_pos;
10831 if (err)
10832 {
10833 /* Evaluating {skip} caused an error, break here. */
10834 curwin->w_cursor = save_cursor;
10835 retval = -1;
10836 break;
10837 }
10838 if (r)
10839 continue;
10840 }
10841
10842 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10843 {
10844 /* Found end when searching backwards or start when searching
10845 * forward: nested pair. */
10846 ++nest;
10847 pat = pat2; /* nested, don't search for middle */
10848 }
10849 else
10850 {
10851 /* Found end when searching forward or start when searching
10852 * backward: end of (nested) pair; or found middle in outer pair. */
10853 if (--nest == 1)
10854 pat = pat3; /* outer level, search for middle */
10855 }
10856
10857 if (nest == 0)
10858 {
10859 /* Found the match: return matchcount or line number. */
10860 if (flags & SP_RETCOUNT)
10861 ++retval;
10862 else
10863 retval = pos.lnum;
10864 if (flags & SP_SETPCMARK)
10865 setpcmark();
10866 curwin->w_cursor = pos;
10867 if (!(flags & SP_REPEAT))
10868 break;
10869 nest = 1; /* search for next unmatched */
10870 }
10871 }
10872
10873 if (match_pos != NULL)
10874 {
10875 /* Store the match cursor position */
10876 match_pos->lnum = curwin->w_cursor.lnum;
10877 match_pos->col = curwin->w_cursor.col + 1;
10878 }
10879
10880 /* If 'n' flag is used or search failed: restore cursor position. */
10881 if ((flags & SP_NOMOVE) || retval == 0)
10882 curwin->w_cursor = save_cursor;
10883
10884theend:
10885 vim_free(pat2);
10886 vim_free(pat3);
10887 if (p_cpo == empty_option)
10888 p_cpo = save_cpo;
10889 else
10890 /* Darn, evaluating the {skip} expression changed the value. */
10891 free_string_option(save_cpo);
10892
10893 return retval;
10894}
10895
10896/*
10897 * "searchpos()" function
10898 */
10899 static void
10900f_searchpos(typval_T *argvars, typval_T *rettv)
10901{
10902 pos_T match_pos;
10903 int lnum = 0;
10904 int col = 0;
10905 int n;
10906 int flags = 0;
10907
10908 if (rettv_list_alloc(rettv) == FAIL)
10909 return;
10910
10911 n = search_cmn(argvars, &match_pos, &flags);
10912 if (n > 0)
10913 {
10914 lnum = match_pos.lnum;
10915 col = match_pos.col;
10916 }
10917
10918 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10919 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10920 if (flags & SP_SUBPAT)
10921 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10922}
10923
10924 static void
10925f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10926{
10927#ifdef FEAT_CLIENTSERVER
10928 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010929 char_u *server = tv_get_string_chk(&argvars[0]);
10930 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010931
10932 rettv->vval.v_number = -1;
10933 if (server == NULL || reply == NULL)
10934 return;
10935 if (check_restricted() || check_secure())
10936 return;
10937# ifdef FEAT_X11
10938 if (check_connection() == FAIL)
10939 return;
10940# endif
10941
10942 if (serverSendReply(server, reply) < 0)
10943 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010944 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010945 return;
10946 }
10947 rettv->vval.v_number = 0;
10948#else
10949 rettv->vval.v_number = -1;
10950#endif
10951}
10952
10953 static void
10954f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10955{
10956 char_u *r = NULL;
10957
10958#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010959# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010960 r = serverGetVimNames();
10961# else
10962 make_connection();
10963 if (X_DISPLAY != NULL)
10964 r = serverGetVimNames(X_DISPLAY);
10965# endif
10966#endif
10967 rettv->v_type = VAR_STRING;
10968 rettv->vval.v_string = r;
10969}
10970
10971/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010972 * "setbufline()" function
10973 */
10974 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010975f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010976{
10977 linenr_T lnum;
10978 buf_T *buf;
10979
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010980 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010981 if (buf == NULL)
10982 rettv->vval.v_number = 1; /* FAIL */
10983 else
10984 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010985 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010986 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010987 }
10988}
10989
10990/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010991 * "setbufvar()" function
10992 */
10993 static void
10994f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10995{
10996 buf_T *buf;
10997 char_u *varname, *bufvarname;
10998 typval_T *varp;
10999 char_u nbuf[NUMBUFLEN];
11000
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011001 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011002 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011003 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
11004 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010011005 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011006 varp = &argvars[2];
11007
11008 if (buf != NULL && varname != NULL && varp != NULL)
11009 {
11010 if (*varname == '&')
11011 {
11012 long numval;
11013 char_u *strval;
11014 int error = FALSE;
11015 aco_save_T aco;
11016
11017 /* set curbuf to be our buf, temporarily */
11018 aucmd_prepbuf(&aco, buf);
11019
11020 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011021 numval = (long)tv_get_number_chk(varp, &error);
11022 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011023 if (!error && strval != NULL)
11024 set_option_value(varname, numval, strval, OPT_LOCAL);
11025
11026 /* reset notion of buffer */
11027 aucmd_restbuf(&aco);
11028 }
11029 else
11030 {
11031 buf_T *save_curbuf = curbuf;
11032
11033 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
11034 if (bufvarname != NULL)
11035 {
11036 curbuf = buf;
11037 STRCPY(bufvarname, "b:");
11038 STRCPY(bufvarname + 2, varname);
11039 set_var(bufvarname, varp, TRUE);
11040 vim_free(bufvarname);
11041 curbuf = save_curbuf;
11042 }
11043 }
11044 }
11045}
11046
11047 static void
11048f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
11049{
11050 dict_T *d;
11051 dictitem_T *di;
11052 char_u *csearch;
11053
11054 if (argvars[0].v_type != VAR_DICT)
11055 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011056 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011057 return;
11058 }
11059
11060 if ((d = argvars[0].vval.v_dict) != NULL)
11061 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010011062 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011063 if (csearch != NULL)
11064 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011065 if (enc_utf8)
11066 {
11067 int pcc[MAX_MCO];
11068 int c = utfc_ptr2char(csearch, pcc);
11069
11070 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
11071 }
11072 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011073 set_last_csearch(PTR2CHAR(csearch),
11074 csearch, MB_PTR2LEN(csearch));
11075 }
11076
11077 di = dict_find(d, (char_u *)"forward", -1);
11078 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011079 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011080 ? FORWARD : BACKWARD);
11081
11082 di = dict_find(d, (char_u *)"until", -1);
11083 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011084 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011085 }
11086}
11087
11088/*
11089 * "setcmdpos()" function
11090 */
11091 static void
11092f_setcmdpos(typval_T *argvars, typval_T *rettv)
11093{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011094 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011095
11096 if (pos >= 0)
11097 rettv->vval.v_number = set_cmdline_pos(pos);
11098}
11099
11100/*
11101 * "setfperm({fname}, {mode})" function
11102 */
11103 static void
11104f_setfperm(typval_T *argvars, typval_T *rettv)
11105{
11106 char_u *fname;
11107 char_u modebuf[NUMBUFLEN];
11108 char_u *mode_str;
11109 int i;
11110 int mask;
11111 int mode = 0;
11112
11113 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011114 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011115 if (fname == NULL)
11116 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011117 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011118 if (mode_str == NULL)
11119 return;
11120 if (STRLEN(mode_str) != 9)
11121 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011122 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011123 return;
11124 }
11125
11126 mask = 1;
11127 for (i = 8; i >= 0; --i)
11128 {
11129 if (mode_str[i] != '-')
11130 mode |= mask;
11131 mask = mask << 1;
11132 }
11133 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11134}
11135
11136/*
11137 * "setline()" function
11138 */
11139 static void
11140f_setline(typval_T *argvars, typval_T *rettv)
11141{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011142 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011143
Bram Moolenaarca851592018-06-06 21:04:07 +020011144 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011145}
11146
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011147/*
11148 * Used by "setqflist()" and "setloclist()" functions
11149 */
11150 static void
11151set_qf_ll_list(
11152 win_T *wp UNUSED,
11153 typval_T *list_arg UNUSED,
11154 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011155 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011156 typval_T *rettv)
11157{
11158#ifdef FEAT_QUICKFIX
11159 static char *e_invact = N_("E927: Invalid action: '%s'");
11160 char_u *act;
11161 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011162 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011163#endif
11164
11165 rettv->vval.v_number = -1;
11166
11167#ifdef FEAT_QUICKFIX
11168 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011169 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011170 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011171 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011172 else
11173 {
11174 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011175 dict_T *d = NULL;
11176 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011177
11178 if (action_arg->v_type == VAR_STRING)
11179 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011180 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011181 if (act == NULL)
11182 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011183 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11184 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011185 action = *act;
11186 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011187 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011188 }
11189 else if (action_arg->v_type == VAR_UNKNOWN)
11190 action = ' ';
11191 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011192 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011193
Bram Moolenaard823fa92016-08-12 16:29:27 +020011194 if (action_arg->v_type != VAR_UNKNOWN
11195 && what_arg->v_type != VAR_UNKNOWN)
11196 {
11197 if (what_arg->v_type == VAR_DICT)
11198 d = what_arg->vval.v_dict;
11199 else
11200 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011201 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011202 valid_dict = FALSE;
11203 }
11204 }
11205
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011206 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011207 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011208 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11209 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011210 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011211 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011212 }
11213#endif
11214}
11215
11216/*
11217 * "setloclist()" function
11218 */
11219 static void
11220f_setloclist(typval_T *argvars, typval_T *rettv)
11221{
11222 win_T *win;
11223
11224 rettv->vval.v_number = -1;
11225
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011226 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011227 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011228 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011229}
11230
11231/*
11232 * "setmatches()" function
11233 */
11234 static void
11235f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11236{
11237#ifdef FEAT_SEARCH_EXTRA
11238 list_T *l;
11239 listitem_T *li;
11240 dict_T *d;
11241 list_T *s = NULL;
Bram Moolenaaraff74912019-03-30 18:11:49 +010011242 win_T *win = get_optional_window(argvars, 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011243
11244 rettv->vval.v_number = -1;
11245 if (argvars[0].v_type != VAR_LIST)
11246 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011247 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011248 return;
11249 }
Bram Moolenaaraff74912019-03-30 18:11:49 +010011250 if (win == NULL)
11251 return;
11252
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011253 if ((l = argvars[0].vval.v_list) != NULL)
11254 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011255 /* To some extent make sure that we are dealing with a list from
11256 * "getmatches()". */
11257 li = l->lv_first;
11258 while (li != NULL)
11259 {
11260 if (li->li_tv.v_type != VAR_DICT
11261 || (d = li->li_tv.vval.v_dict) == NULL)
11262 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011263 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011264 return;
11265 }
11266 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11267 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11268 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11269 && dict_find(d, (char_u *)"priority", -1) != NULL
11270 && dict_find(d, (char_u *)"id", -1) != NULL))
11271 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011272 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011273 return;
11274 }
11275 li = li->li_next;
11276 }
11277
Bram Moolenaaraff74912019-03-30 18:11:49 +010011278 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011279 li = l->lv_first;
11280 while (li != NULL)
11281 {
11282 int i = 0;
11283 char_u buf[5];
11284 dictitem_T *di;
11285 char_u *group;
11286 int priority;
11287 int id;
11288 char_u *conceal;
11289
11290 d = li->li_tv.vval.v_dict;
11291 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11292 {
11293 if (s == NULL)
11294 {
11295 s = list_alloc();
11296 if (s == NULL)
11297 return;
11298 }
11299
11300 /* match from matchaddpos() */
11301 for (i = 1; i < 9; i++)
11302 {
11303 sprintf((char *)buf, (char *)"pos%d", i);
11304 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11305 {
11306 if (di->di_tv.v_type != VAR_LIST)
11307 return;
11308
11309 list_append_tv(s, &di->di_tv);
11310 s->lv_refcount++;
11311 }
11312 else
11313 break;
11314 }
11315 }
11316
Bram Moolenaar8f667172018-12-14 15:38:31 +010011317 group = dict_get_string(d, (char_u *)"group", TRUE);
11318 priority = (int)dict_get_number(d, (char_u *)"priority");
11319 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011320 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011321 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011322 : NULL;
11323 if (i == 0)
11324 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011325 match_add(win, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011326 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011327 priority, id, NULL, conceal);
11328 }
11329 else
11330 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011331 match_add(win, group, NULL, priority, id, s, conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011332 list_unref(s);
11333 s = NULL;
11334 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011335 vim_free(group);
11336 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011337
11338 li = li->li_next;
11339 }
11340 rettv->vval.v_number = 0;
11341 }
11342#endif
11343}
11344
11345/*
11346 * "setpos()" function
11347 */
11348 static void
11349f_setpos(typval_T *argvars, typval_T *rettv)
11350{
11351 pos_T pos;
11352 int fnum;
11353 char_u *name;
11354 colnr_T curswant = -1;
11355
11356 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011357 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011358 if (name != NULL)
11359 {
11360 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11361 {
11362 if (--pos.col < 0)
11363 pos.col = 0;
11364 if (name[0] == '.' && name[1] == NUL)
11365 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011366 /* set cursor; "fnum" is ignored */
11367 curwin->w_cursor = pos;
11368 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011369 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011370 curwin->w_curswant = curswant - 1;
11371 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011372 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011373 check_cursor();
11374 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011375 }
11376 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11377 {
11378 /* set mark */
11379 if (setmark_pos(name[1], &pos, fnum) == OK)
11380 rettv->vval.v_number = 0;
11381 }
11382 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011383 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011384 }
11385 }
11386}
11387
11388/*
11389 * "setqflist()" function
11390 */
11391 static void
11392f_setqflist(typval_T *argvars, typval_T *rettv)
11393{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011394 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011395}
11396
11397/*
11398 * "setreg()" function
11399 */
11400 static void
11401f_setreg(typval_T *argvars, typval_T *rettv)
11402{
11403 int regname;
11404 char_u *strregname;
11405 char_u *stropt;
11406 char_u *strval;
11407 int append;
11408 char_u yank_type;
11409 long block_len;
11410
11411 block_len = -1;
11412 yank_type = MAUTO;
11413 append = FALSE;
11414
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011415 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011416 rettv->vval.v_number = 1; /* FAIL is default */
11417
11418 if (strregname == NULL)
11419 return; /* type error; errmsg already given */
11420 regname = *strregname;
11421 if (regname == 0 || regname == '@')
11422 regname = '"';
11423
11424 if (argvars[2].v_type != VAR_UNKNOWN)
11425 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011426 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011427 if (stropt == NULL)
11428 return; /* type error */
11429 for (; *stropt != NUL; ++stropt)
11430 switch (*stropt)
11431 {
11432 case 'a': case 'A': /* append */
11433 append = TRUE;
11434 break;
11435 case 'v': case 'c': /* character-wise selection */
11436 yank_type = MCHAR;
11437 break;
11438 case 'V': case 'l': /* line-wise selection */
11439 yank_type = MLINE;
11440 break;
11441 case 'b': case Ctrl_V: /* block-wise selection */
11442 yank_type = MBLOCK;
11443 if (VIM_ISDIGIT(stropt[1]))
11444 {
11445 ++stropt;
11446 block_len = getdigits(&stropt) - 1;
11447 --stropt;
11448 }
11449 break;
11450 }
11451 }
11452
11453 if (argvars[1].v_type == VAR_LIST)
11454 {
11455 char_u **lstval;
11456 char_u **allocval;
11457 char_u buf[NUMBUFLEN];
11458 char_u **curval;
11459 char_u **curallocval;
11460 list_T *ll = argvars[1].vval.v_list;
11461 listitem_T *li;
11462 int len;
11463
11464 /* If the list is NULL handle like an empty list. */
11465 len = ll == NULL ? 0 : ll->lv_len;
11466
11467 /* First half: use for pointers to result lines; second half: use for
11468 * pointers to allocated copies. */
11469 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11470 if (lstval == NULL)
11471 return;
11472 curval = lstval;
11473 allocval = lstval + len + 2;
11474 curallocval = allocval;
11475
11476 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11477 li = li->li_next)
11478 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011479 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011480 if (strval == NULL)
11481 goto free_lstval;
11482 if (strval == buf)
11483 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011484 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011485 * overwrite the string. */
11486 strval = vim_strsave(buf);
11487 if (strval == NULL)
11488 goto free_lstval;
11489 *curallocval++ = strval;
11490 }
11491 *curval++ = strval;
11492 }
11493 *curval++ = NULL;
11494
11495 write_reg_contents_lst(regname, lstval, -1,
11496 append, yank_type, block_len);
11497free_lstval:
11498 while (curallocval > allocval)
11499 vim_free(*--curallocval);
11500 vim_free(lstval);
11501 }
11502 else
11503 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011504 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011505 if (strval == NULL)
11506 return;
11507 write_reg_contents_ex(regname, strval, -1,
11508 append, yank_type, block_len);
11509 }
11510 rettv->vval.v_number = 0;
11511}
11512
11513/*
11514 * "settabvar()" function
11515 */
11516 static void
11517f_settabvar(typval_T *argvars, typval_T *rettv)
11518{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011519 tabpage_T *save_curtab;
11520 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011521 char_u *varname, *tabvarname;
11522 typval_T *varp;
11523
11524 rettv->vval.v_number = 0;
11525
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011526 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011527 return;
11528
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011529 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11530 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011531 varp = &argvars[2];
11532
Bram Moolenaar4033c552017-09-16 20:54:51 +020011533 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011534 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011535 save_curtab = curtab;
11536 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011537
11538 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11539 if (tabvarname != NULL)
11540 {
11541 STRCPY(tabvarname, "t:");
11542 STRCPY(tabvarname + 2, varname);
11543 set_var(tabvarname, varp, TRUE);
11544 vim_free(tabvarname);
11545 }
11546
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011547 /* Restore current tabpage */
11548 if (valid_tabpage(save_curtab))
11549 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011550 }
11551}
11552
11553/*
11554 * "settabwinvar()" function
11555 */
11556 static void
11557f_settabwinvar(typval_T *argvars, typval_T *rettv)
11558{
11559 setwinvar(argvars, rettv, 1);
11560}
11561
11562/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011563 * "settagstack()" function
11564 */
11565 static void
11566f_settagstack(typval_T *argvars, typval_T *rettv)
11567{
11568 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11569 win_T *wp;
11570 dict_T *d;
11571 int action = 'r';
11572
11573 rettv->vval.v_number = -1;
11574
11575 // first argument: window number or id
11576 wp = find_win_by_nr_or_id(&argvars[0]);
11577 if (wp == NULL)
11578 return;
11579
11580 // second argument: dict with items to set in the tag stack
11581 if (argvars[1].v_type != VAR_DICT)
11582 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011583 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011584 return;
11585 }
11586 d = argvars[1].vval.v_dict;
11587 if (d == NULL)
11588 return;
11589
11590 // third argument: action - 'a' for append and 'r' for replace.
11591 // default is to replace the stack.
11592 if (argvars[2].v_type == VAR_UNKNOWN)
11593 action = 'r';
11594 else if (argvars[2].v_type == VAR_STRING)
11595 {
11596 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011597 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011598 if (actstr == NULL)
11599 return;
11600 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11601 action = *actstr;
11602 else
11603 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011604 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011605 return;
11606 }
11607 }
11608 else
11609 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011610 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011611 return;
11612 }
11613
11614 if (set_tagstack(wp, d, action) == OK)
11615 rettv->vval.v_number = 0;
11616}
11617
11618/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011619 * "setwinvar()" function
11620 */
11621 static void
11622f_setwinvar(typval_T *argvars, typval_T *rettv)
11623{
11624 setwinvar(argvars, rettv, 0);
11625}
11626
11627#ifdef FEAT_CRYPT
11628/*
11629 * "sha256({string})" function
11630 */
11631 static void
11632f_sha256(typval_T *argvars, typval_T *rettv)
11633{
11634 char_u *p;
11635
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011636 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011637 rettv->vval.v_string = vim_strsave(
11638 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11639 rettv->v_type = VAR_STRING;
11640}
11641#endif /* FEAT_CRYPT */
11642
11643/*
11644 * "shellescape({string})" function
11645 */
11646 static void
11647f_shellescape(typval_T *argvars, typval_T *rettv)
11648{
Bram Moolenaar20615522017-06-05 18:46:26 +020011649 int do_special = non_zero_arg(&argvars[1]);
11650
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011651 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011652 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011653 rettv->v_type = VAR_STRING;
11654}
11655
11656/*
11657 * shiftwidth() function
11658 */
11659 static void
11660f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11661{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011662 rettv->vval.v_number = 0;
11663
11664 if (argvars[0].v_type != VAR_UNKNOWN)
11665 {
11666 long col;
11667
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011668 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011669 if (col < 0)
11670 return; // type error; errmsg already given
11671#ifdef FEAT_VARTABS
11672 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11673 return;
11674#endif
11675 }
11676
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011677 rettv->vval.v_number = get_sw_value(curbuf);
11678}
11679
Bram Moolenaar162b7142018-12-21 15:17:36 +010011680#ifdef FEAT_SIGNS
11681/*
11682 * "sign_define()" function
11683 */
11684 static void
11685f_sign_define(typval_T *argvars, typval_T *rettv)
11686{
11687 char_u *name;
11688 dict_T *dict;
11689 char_u *icon = NULL;
11690 char_u *linehl = NULL;
11691 char_u *text = NULL;
11692 char_u *texthl = NULL;
11693
11694 rettv->vval.v_number = -1;
11695
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011696 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011697 if (name == NULL)
11698 return;
11699
11700 if (argvars[1].v_type != VAR_UNKNOWN)
11701 {
11702 if (argvars[1].v_type != VAR_DICT)
11703 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011704 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011705 return;
11706 }
11707
11708 // sign attributes
11709 dict = argvars[1].vval.v_dict;
11710 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11711 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11712 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11713 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11714 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11715 text = dict_get_string(dict, (char_u *)"text", TRUE);
11716 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11717 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11718 }
11719
11720 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11721 rettv->vval.v_number = 0;
11722
11723 vim_free(icon);
11724 vim_free(linehl);
11725 vim_free(text);
11726 vim_free(texthl);
11727}
11728
11729/*
11730 * "sign_getdefined()" function
11731 */
11732 static void
11733f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11734{
11735 char_u *name = NULL;
11736
11737 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11738 return;
11739
11740 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011741 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011742
11743 sign_getlist(name, rettv->vval.v_list);
11744}
11745
11746/*
11747 * "sign_getplaced()" function
11748 */
11749 static void
11750f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11751{
11752 buf_T *buf = NULL;
11753 dict_T *dict;
11754 dictitem_T *di;
11755 linenr_T lnum = 0;
11756 int sign_id = 0;
11757 char_u *group = NULL;
11758 int notanum = FALSE;
11759
11760 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11761 return;
11762
11763 if (argvars[0].v_type != VAR_UNKNOWN)
11764 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011765 // get signs placed in the specified buffer
11766 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011767 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011768 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011769
11770 if (argvars[1].v_type != VAR_UNKNOWN)
11771 {
11772 if (argvars[1].v_type != VAR_DICT ||
11773 ((dict = argvars[1].vval.v_dict) == NULL))
11774 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011775 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011776 return;
11777 }
11778 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11779 {
11780 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011781 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011782 if (notanum)
11783 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011784 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011785 }
11786 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11787 {
11788 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011789 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011790 if (notanum)
11791 return;
11792 }
11793 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11794 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011795 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011796 if (group == NULL)
11797 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011798 if (*group == '\0') // empty string means global group
11799 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011800 }
11801 }
11802 }
11803
11804 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11805}
11806
11807/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011808 * "sign_jump()" function
11809 */
11810 static void
11811f_sign_jump(typval_T *argvars, typval_T *rettv)
11812{
11813 int sign_id;
11814 char_u *sign_group = NULL;
11815 buf_T *buf;
11816 int notanum = FALSE;
11817
11818 rettv->vval.v_number = -1;
11819
Bram Moolenaarbdace832019-03-02 10:13:42 +010011820 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011821 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11822 if (notanum)
11823 return;
11824 if (sign_id <= 0)
11825 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011826 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011827 return;
11828 }
11829
11830 // Sign group
11831 sign_group = tv_get_string_chk(&argvars[1]);
11832 if (sign_group == NULL)
11833 return;
11834 if (sign_group[0] == '\0')
11835 sign_group = NULL; // global sign group
11836 else
11837 {
11838 sign_group = vim_strsave(sign_group);
11839 if (sign_group == NULL)
11840 return;
11841 }
11842
11843 // Buffer to place the sign
11844 buf = get_buf_arg(&argvars[2]);
11845 if (buf == NULL)
11846 goto cleanup;
11847
11848 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11849
11850cleanup:
11851 vim_free(sign_group);
11852}
11853
11854/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011855 * "sign_place()" function
11856 */
11857 static void
11858f_sign_place(typval_T *argvars, typval_T *rettv)
11859{
11860 int sign_id;
11861 char_u *group = NULL;
11862 char_u *sign_name;
11863 buf_T *buf;
11864 dict_T *dict;
11865 dictitem_T *di;
11866 linenr_T lnum = 0;
11867 int prio = SIGN_DEF_PRIO;
11868 int notanum = FALSE;
11869
11870 rettv->vval.v_number = -1;
11871
Bram Moolenaarbdace832019-03-02 10:13:42 +010011872 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011873 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011874 if (notanum)
11875 return;
11876 if (sign_id < 0)
11877 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011878 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011879 return;
11880 }
11881
11882 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011883 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011884 if (group == NULL)
11885 return;
11886 if (group[0] == '\0')
11887 group = NULL; // global sign group
11888 else
11889 {
11890 group = vim_strsave(group);
11891 if (group == NULL)
11892 return;
11893 }
11894
11895 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011896 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011897 if (sign_name == NULL)
11898 goto cleanup;
11899
11900 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011901 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011902 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011903 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011904
11905 if (argvars[4].v_type != VAR_UNKNOWN)
11906 {
11907 if (argvars[4].v_type != VAR_DICT ||
11908 ((dict = argvars[4].vval.v_dict) == NULL))
11909 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011910 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011911 goto cleanup;
11912 }
11913
11914 // Line number where the sign is to be placed
11915 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11916 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011917 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011918 if (notanum)
11919 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011920 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011921 }
11922 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11923 {
11924 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011925 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011926 if (notanum)
11927 goto cleanup;
11928 }
11929 }
11930
11931 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11932 rettv->vval.v_number = sign_id;
11933
11934cleanup:
11935 vim_free(group);
11936}
11937
11938/*
11939 * "sign_undefine()" function
11940 */
11941 static void
11942f_sign_undefine(typval_T *argvars, typval_T *rettv)
11943{
11944 char_u *name;
11945
11946 rettv->vval.v_number = -1;
11947
11948 if (argvars[0].v_type == VAR_UNKNOWN)
11949 {
11950 // Free all the signs
11951 free_signs();
11952 rettv->vval.v_number = 0;
11953 }
11954 else
11955 {
11956 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011957 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011958 if (name == NULL)
11959 return;
11960
11961 if (sign_undefine_by_name(name) == OK)
11962 rettv->vval.v_number = 0;
11963 }
11964}
11965
11966/*
11967 * "sign_unplace()" function
11968 */
11969 static void
11970f_sign_unplace(typval_T *argvars, typval_T *rettv)
11971{
11972 dict_T *dict;
11973 dictitem_T *di;
11974 int sign_id = 0;
11975 buf_T *buf = NULL;
11976 char_u *group = NULL;
11977
11978 rettv->vval.v_number = -1;
11979
11980 if (argvars[0].v_type != VAR_STRING)
11981 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011982 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011983 return;
11984 }
11985
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011986 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011987 if (group[0] == '\0')
11988 group = NULL; // global sign group
11989 else
11990 {
11991 group = vim_strsave(group);
11992 if (group == NULL)
11993 return;
11994 }
11995
11996 if (argvars[1].v_type != VAR_UNKNOWN)
11997 {
11998 if (argvars[1].v_type != VAR_DICT)
11999 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012000 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012001 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012002 }
12003 dict = argvars[1].vval.v_dict;
12004
12005 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
12006 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010012007 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010012008 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012009 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010012010 }
12011 if (dict_find(dict, (char_u *)"id", -1) != NULL)
12012 sign_id = dict_get_number(dict, (char_u *)"id");
12013 }
12014
12015 if (buf == NULL)
12016 {
12017 // Delete the sign in all the buffers
12018 FOR_ALL_BUFFERS(buf)
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 }
12022 else
12023 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012024 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012025 rettv->vval.v_number = 0;
12026 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012027
12028cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010012029 vim_free(group);
12030}
12031#endif
12032
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012033/*
12034 * "simplify()" function
12035 */
12036 static void
12037f_simplify(typval_T *argvars, typval_T *rettv)
12038{
12039 char_u *p;
12040
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012041 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012042 rettv->vval.v_string = vim_strsave(p);
12043 simplify_filename(rettv->vval.v_string); /* simplify in place */
12044 rettv->v_type = VAR_STRING;
12045}
12046
12047#ifdef FEAT_FLOAT
12048/*
12049 * "sin()" function
12050 */
12051 static void
12052f_sin(typval_T *argvars, typval_T *rettv)
12053{
12054 float_T f = 0.0;
12055
12056 rettv->v_type = VAR_FLOAT;
12057 if (get_float_arg(argvars, &f) == OK)
12058 rettv->vval.v_float = sin(f);
12059 else
12060 rettv->vval.v_float = 0.0;
12061}
12062
12063/*
12064 * "sinh()" function
12065 */
12066 static void
12067f_sinh(typval_T *argvars, typval_T *rettv)
12068{
12069 float_T f = 0.0;
12070
12071 rettv->v_type = VAR_FLOAT;
12072 if (get_float_arg(argvars, &f) == OK)
12073 rettv->vval.v_float = sinh(f);
12074 else
12075 rettv->vval.v_float = 0.0;
12076}
12077#endif
12078
12079static int
12080#ifdef __BORLANDC__
12081 _RTLENTRYF
12082#endif
12083 item_compare(const void *s1, const void *s2);
12084static int
12085#ifdef __BORLANDC__
12086 _RTLENTRYF
12087#endif
12088 item_compare2(const void *s1, const void *s2);
12089
12090/* struct used in the array that's given to qsort() */
12091typedef struct
12092{
12093 listitem_T *item;
12094 int idx;
12095} sortItem_T;
12096
12097/* struct storing information about current sort */
12098typedef struct
12099{
12100 int item_compare_ic;
12101 int item_compare_numeric;
12102 int item_compare_numbers;
12103#ifdef FEAT_FLOAT
12104 int item_compare_float;
12105#endif
12106 char_u *item_compare_func;
12107 partial_T *item_compare_partial;
12108 dict_T *item_compare_selfdict;
12109 int item_compare_func_err;
12110 int item_compare_keep_zero;
12111} sortinfo_T;
12112static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012113#define ITEM_COMPARE_FAIL 999
12114
12115/*
12116 * Compare functions for f_sort() and f_uniq() below.
12117 */
12118 static int
12119#ifdef __BORLANDC__
12120_RTLENTRYF
12121#endif
12122item_compare(const void *s1, const void *s2)
12123{
12124 sortItem_T *si1, *si2;
12125 typval_T *tv1, *tv2;
12126 char_u *p1, *p2;
12127 char_u *tofree1 = NULL, *tofree2 = NULL;
12128 int res;
12129 char_u numbuf1[NUMBUFLEN];
12130 char_u numbuf2[NUMBUFLEN];
12131
12132 si1 = (sortItem_T *)s1;
12133 si2 = (sortItem_T *)s2;
12134 tv1 = &si1->item->li_tv;
12135 tv2 = &si2->item->li_tv;
12136
12137 if (sortinfo->item_compare_numbers)
12138 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012139 varnumber_T v1 = tv_get_number(tv1);
12140 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012141
12142 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12143 }
12144
12145#ifdef FEAT_FLOAT
12146 if (sortinfo->item_compare_float)
12147 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012148 float_T v1 = tv_get_float(tv1);
12149 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012150
12151 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12152 }
12153#endif
12154
12155 /* tv2string() puts quotes around a string and allocates memory. Don't do
12156 * that for string variables. Use a single quote when comparing with a
12157 * non-string to do what the docs promise. */
12158 if (tv1->v_type == VAR_STRING)
12159 {
12160 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12161 p1 = (char_u *)"'";
12162 else
12163 p1 = tv1->vval.v_string;
12164 }
12165 else
12166 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12167 if (tv2->v_type == VAR_STRING)
12168 {
12169 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12170 p2 = (char_u *)"'";
12171 else
12172 p2 = tv2->vval.v_string;
12173 }
12174 else
12175 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12176 if (p1 == NULL)
12177 p1 = (char_u *)"";
12178 if (p2 == NULL)
12179 p2 = (char_u *)"";
12180 if (!sortinfo->item_compare_numeric)
12181 {
12182 if (sortinfo->item_compare_ic)
12183 res = STRICMP(p1, p2);
12184 else
12185 res = STRCMP(p1, p2);
12186 }
12187 else
12188 {
12189 double n1, n2;
12190 n1 = strtod((char *)p1, (char **)&p1);
12191 n2 = strtod((char *)p2, (char **)&p2);
12192 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12193 }
12194
12195 /* When the result would be zero, compare the item indexes. Makes the
12196 * sort stable. */
12197 if (res == 0 && !sortinfo->item_compare_keep_zero)
12198 res = si1->idx > si2->idx ? 1 : -1;
12199
12200 vim_free(tofree1);
12201 vim_free(tofree2);
12202 return res;
12203}
12204
12205 static int
12206#ifdef __BORLANDC__
12207_RTLENTRYF
12208#endif
12209item_compare2(const void *s1, const void *s2)
12210{
12211 sortItem_T *si1, *si2;
12212 int res;
12213 typval_T rettv;
12214 typval_T argv[3];
12215 int dummy;
12216 char_u *func_name;
12217 partial_T *partial = sortinfo->item_compare_partial;
12218
12219 /* shortcut after failure in previous call; compare all items equal */
12220 if (sortinfo->item_compare_func_err)
12221 return 0;
12222
12223 si1 = (sortItem_T *)s1;
12224 si2 = (sortItem_T *)s2;
12225
12226 if (partial == NULL)
12227 func_name = sortinfo->item_compare_func;
12228 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012229 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012230
12231 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12232 * in the copy without changing the original list items. */
12233 copy_tv(&si1->item->li_tv, &argv[0]);
12234 copy_tv(&si2->item->li_tv, &argv[1]);
12235
12236 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
12237 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020012238 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012239 partial, sortinfo->item_compare_selfdict);
12240 clear_tv(&argv[0]);
12241 clear_tv(&argv[1]);
12242
12243 if (res == FAIL)
12244 res = ITEM_COMPARE_FAIL;
12245 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012246 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012247 if (sortinfo->item_compare_func_err)
12248 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12249 clear_tv(&rettv);
12250
12251 /* When the result would be zero, compare the pointers themselves. Makes
12252 * the sort stable. */
12253 if (res == 0 && !sortinfo->item_compare_keep_zero)
12254 res = si1->idx > si2->idx ? 1 : -1;
12255
12256 return res;
12257}
12258
12259/*
12260 * "sort({list})" function
12261 */
12262 static void
12263do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12264{
12265 list_T *l;
12266 listitem_T *li;
12267 sortItem_T *ptrs;
12268 sortinfo_T *old_sortinfo;
12269 sortinfo_T info;
12270 long len;
12271 long i;
12272
12273 /* Pointer to current info struct used in compare function. Save and
12274 * restore the current one for nested calls. */
12275 old_sortinfo = sortinfo;
12276 sortinfo = &info;
12277
12278 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012279 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012280 else
12281 {
12282 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012283 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012284 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12285 TRUE))
12286 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012287 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012288
12289 len = list_len(l);
12290 if (len <= 1)
12291 goto theend; /* short list sorts pretty quickly */
12292
12293 info.item_compare_ic = FALSE;
12294 info.item_compare_numeric = FALSE;
12295 info.item_compare_numbers = FALSE;
12296#ifdef FEAT_FLOAT
12297 info.item_compare_float = FALSE;
12298#endif
12299 info.item_compare_func = NULL;
12300 info.item_compare_partial = NULL;
12301 info.item_compare_selfdict = NULL;
12302 if (argvars[1].v_type != VAR_UNKNOWN)
12303 {
12304 /* optional second argument: {func} */
12305 if (argvars[1].v_type == VAR_FUNC)
12306 info.item_compare_func = argvars[1].vval.v_string;
12307 else if (argvars[1].v_type == VAR_PARTIAL)
12308 info.item_compare_partial = argvars[1].vval.v_partial;
12309 else
12310 {
12311 int error = FALSE;
12312
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012313 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012314 if (error)
12315 goto theend; /* type error; errmsg already given */
12316 if (i == 1)
12317 info.item_compare_ic = TRUE;
12318 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012319 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012320 else if (i != 0)
12321 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012322 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012323 goto theend;
12324 }
12325 if (info.item_compare_func != NULL)
12326 {
12327 if (*info.item_compare_func == NUL)
12328 {
12329 /* empty string means default sort */
12330 info.item_compare_func = NULL;
12331 }
12332 else if (STRCMP(info.item_compare_func, "n") == 0)
12333 {
12334 info.item_compare_func = NULL;
12335 info.item_compare_numeric = TRUE;
12336 }
12337 else if (STRCMP(info.item_compare_func, "N") == 0)
12338 {
12339 info.item_compare_func = NULL;
12340 info.item_compare_numbers = TRUE;
12341 }
12342#ifdef FEAT_FLOAT
12343 else if (STRCMP(info.item_compare_func, "f") == 0)
12344 {
12345 info.item_compare_func = NULL;
12346 info.item_compare_float = TRUE;
12347 }
12348#endif
12349 else if (STRCMP(info.item_compare_func, "i") == 0)
12350 {
12351 info.item_compare_func = NULL;
12352 info.item_compare_ic = TRUE;
12353 }
12354 }
12355 }
12356
12357 if (argvars[2].v_type != VAR_UNKNOWN)
12358 {
12359 /* optional third argument: {dict} */
12360 if (argvars[2].v_type != VAR_DICT)
12361 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012362 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012363 goto theend;
12364 }
12365 info.item_compare_selfdict = argvars[2].vval.v_dict;
12366 }
12367 }
12368
12369 /* Make an array with each entry pointing to an item in the List. */
12370 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12371 if (ptrs == NULL)
12372 goto theend;
12373
12374 i = 0;
12375 if (sort)
12376 {
12377 /* sort(): ptrs will be the list to sort */
12378 for (li = l->lv_first; li != NULL; li = li->li_next)
12379 {
12380 ptrs[i].item = li;
12381 ptrs[i].idx = i;
12382 ++i;
12383 }
12384
12385 info.item_compare_func_err = FALSE;
12386 info.item_compare_keep_zero = FALSE;
12387 /* test the compare function */
12388 if ((info.item_compare_func != NULL
12389 || info.item_compare_partial != NULL)
12390 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12391 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012392 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012393 else
12394 {
12395 /* Sort the array with item pointers. */
12396 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12397 info.item_compare_func == NULL
12398 && info.item_compare_partial == NULL
12399 ? item_compare : item_compare2);
12400
12401 if (!info.item_compare_func_err)
12402 {
12403 /* Clear the List and append the items in sorted order. */
12404 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12405 l->lv_len = 0;
12406 for (i = 0; i < len; ++i)
12407 list_append(l, ptrs[i].item);
12408 }
12409 }
12410 }
12411 else
12412 {
12413 int (*item_compare_func_ptr)(const void *, const void *);
12414
12415 /* f_uniq(): ptrs will be a stack of items to remove */
12416 info.item_compare_func_err = FALSE;
12417 info.item_compare_keep_zero = TRUE;
12418 item_compare_func_ptr = info.item_compare_func != NULL
12419 || info.item_compare_partial != NULL
12420 ? item_compare2 : item_compare;
12421
12422 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12423 li = li->li_next)
12424 {
12425 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12426 == 0)
12427 ptrs[i++].item = li;
12428 if (info.item_compare_func_err)
12429 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012430 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012431 break;
12432 }
12433 }
12434
12435 if (!info.item_compare_func_err)
12436 {
12437 while (--i >= 0)
12438 {
12439 li = ptrs[i].item->li_next;
12440 ptrs[i].item->li_next = li->li_next;
12441 if (li->li_next != NULL)
12442 li->li_next->li_prev = ptrs[i].item;
12443 else
12444 l->lv_last = ptrs[i].item;
12445 list_fix_watch(l, li);
12446 listitem_free(li);
12447 l->lv_len--;
12448 }
12449 }
12450 }
12451
12452 vim_free(ptrs);
12453 }
12454theend:
12455 sortinfo = old_sortinfo;
12456}
12457
12458/*
12459 * "sort({list})" function
12460 */
12461 static void
12462f_sort(typval_T *argvars, typval_T *rettv)
12463{
12464 do_sort_uniq(argvars, rettv, TRUE);
12465}
12466
12467/*
12468 * "uniq({list})" function
12469 */
12470 static void
12471f_uniq(typval_T *argvars, typval_T *rettv)
12472{
12473 do_sort_uniq(argvars, rettv, FALSE);
12474}
12475
12476/*
12477 * "soundfold({word})" function
12478 */
12479 static void
12480f_soundfold(typval_T *argvars, typval_T *rettv)
12481{
12482 char_u *s;
12483
12484 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012485 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012486#ifdef FEAT_SPELL
12487 rettv->vval.v_string = eval_soundfold(s);
12488#else
12489 rettv->vval.v_string = vim_strsave(s);
12490#endif
12491}
12492
12493/*
12494 * "spellbadword()" function
12495 */
12496 static void
12497f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12498{
12499 char_u *word = (char_u *)"";
12500 hlf_T attr = HLF_COUNT;
12501 int len = 0;
12502
12503 if (rettv_list_alloc(rettv) == FAIL)
12504 return;
12505
12506#ifdef FEAT_SPELL
12507 if (argvars[0].v_type == VAR_UNKNOWN)
12508 {
12509 /* Find the start and length of the badly spelled word. */
12510 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12511 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012512 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012513 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012514 curwin->w_set_curswant = TRUE;
12515 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012516 }
12517 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12518 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012519 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012520 int capcol = -1;
12521
12522 if (str != NULL)
12523 {
12524 /* Check the argument for spelling. */
12525 while (*str != NUL)
12526 {
12527 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12528 if (attr != HLF_COUNT)
12529 {
12530 word = str;
12531 break;
12532 }
12533 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012534 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012535 }
12536 }
12537 }
12538#endif
12539
12540 list_append_string(rettv->vval.v_list, word, len);
12541 list_append_string(rettv->vval.v_list, (char_u *)(
12542 attr == HLF_SPB ? "bad" :
12543 attr == HLF_SPR ? "rare" :
12544 attr == HLF_SPL ? "local" :
12545 attr == HLF_SPC ? "caps" :
12546 ""), -1);
12547}
12548
12549/*
12550 * "spellsuggest()" function
12551 */
12552 static void
12553f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12554{
12555#ifdef FEAT_SPELL
12556 char_u *str;
12557 int typeerr = FALSE;
12558 int maxcount;
12559 garray_T ga;
12560 int i;
12561 listitem_T *li;
12562 int need_capital = FALSE;
12563#endif
12564
12565 if (rettv_list_alloc(rettv) == FAIL)
12566 return;
12567
12568#ifdef FEAT_SPELL
12569 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12570 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012571 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012572 if (argvars[1].v_type != VAR_UNKNOWN)
12573 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012574 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012575 if (maxcount <= 0)
12576 return;
12577 if (argvars[2].v_type != VAR_UNKNOWN)
12578 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012579 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012580 if (typeerr)
12581 return;
12582 }
12583 }
12584 else
12585 maxcount = 25;
12586
12587 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12588
12589 for (i = 0; i < ga.ga_len; ++i)
12590 {
12591 str = ((char_u **)ga.ga_data)[i];
12592
12593 li = listitem_alloc();
12594 if (li == NULL)
12595 vim_free(str);
12596 else
12597 {
12598 li->li_tv.v_type = VAR_STRING;
12599 li->li_tv.v_lock = 0;
12600 li->li_tv.vval.v_string = str;
12601 list_append(rettv->vval.v_list, li);
12602 }
12603 }
12604 ga_clear(&ga);
12605 }
12606#endif
12607}
12608
12609 static void
12610f_split(typval_T *argvars, typval_T *rettv)
12611{
12612 char_u *str;
12613 char_u *end;
12614 char_u *pat = NULL;
12615 regmatch_T regmatch;
12616 char_u patbuf[NUMBUFLEN];
12617 char_u *save_cpo;
12618 int match;
12619 colnr_T col = 0;
12620 int keepempty = FALSE;
12621 int typeerr = FALSE;
12622
12623 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12624 save_cpo = p_cpo;
12625 p_cpo = (char_u *)"";
12626
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012627 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012628 if (argvars[1].v_type != VAR_UNKNOWN)
12629 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012630 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012631 if (pat == NULL)
12632 typeerr = TRUE;
12633 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012634 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012635 }
12636 if (pat == NULL || *pat == NUL)
12637 pat = (char_u *)"[\\x01- ]\\+";
12638
12639 if (rettv_list_alloc(rettv) == FAIL)
12640 return;
12641 if (typeerr)
12642 return;
12643
12644 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12645 if (regmatch.regprog != NULL)
12646 {
12647 regmatch.rm_ic = FALSE;
12648 while (*str != NUL || keepempty)
12649 {
12650 if (*str == NUL)
12651 match = FALSE; /* empty item at the end */
12652 else
12653 match = vim_regexec_nl(&regmatch, str, col);
12654 if (match)
12655 end = regmatch.startp[0];
12656 else
12657 end = str + STRLEN(str);
12658 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12659 && *str != NUL && match && end < regmatch.endp[0]))
12660 {
12661 if (list_append_string(rettv->vval.v_list, str,
12662 (int)(end - str)) == FAIL)
12663 break;
12664 }
12665 if (!match)
12666 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010012667 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012668 if (regmatch.endp[0] > str)
12669 col = 0;
12670 else
Bram Moolenaar13505972019-01-24 15:04:48 +010012671 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012672 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012673 str = regmatch.endp[0];
12674 }
12675
12676 vim_regfree(regmatch.regprog);
12677 }
12678
12679 p_cpo = save_cpo;
12680}
12681
12682#ifdef FEAT_FLOAT
12683/*
12684 * "sqrt()" function
12685 */
12686 static void
12687f_sqrt(typval_T *argvars, typval_T *rettv)
12688{
12689 float_T f = 0.0;
12690
12691 rettv->v_type = VAR_FLOAT;
12692 if (get_float_arg(argvars, &f) == OK)
12693 rettv->vval.v_float = sqrt(f);
12694 else
12695 rettv->vval.v_float = 0.0;
12696}
12697
12698/*
12699 * "str2float()" function
12700 */
12701 static void
12702f_str2float(typval_T *argvars, typval_T *rettv)
12703{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012704 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012705 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012706
Bram Moolenaar08243d22017-01-10 16:12:29 +010012707 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012708 p = skipwhite(p + 1);
12709 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012710 if (isneg)
12711 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012712 rettv->v_type = VAR_FLOAT;
12713}
12714#endif
12715
12716/*
12717 * "str2nr()" function
12718 */
12719 static void
12720f_str2nr(typval_T *argvars, typval_T *rettv)
12721{
12722 int base = 10;
12723 char_u *p;
12724 varnumber_T n;
12725 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012726 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012727
12728 if (argvars[1].v_type != VAR_UNKNOWN)
12729 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012730 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012731 if (base != 2 && base != 8 && base != 10 && base != 16)
12732 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012733 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012734 return;
12735 }
12736 }
12737
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012738 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012739 isneg = (*p == '-');
12740 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012741 p = skipwhite(p + 1);
12742 switch (base)
12743 {
12744 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12745 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12746 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12747 default: what = 0;
12748 }
12749 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012750 if (isneg)
12751 rettv->vval.v_number = -n;
12752 else
12753 rettv->vval.v_number = n;
12754
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012755}
12756
12757#ifdef HAVE_STRFTIME
12758/*
12759 * "strftime({format}[, {time}])" function
12760 */
12761 static void
12762f_strftime(typval_T *argvars, typval_T *rettv)
12763{
12764 char_u result_buf[256];
12765 struct tm *curtime;
12766 time_t seconds;
12767 char_u *p;
12768
12769 rettv->v_type = VAR_STRING;
12770
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012771 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012772 if (argvars[1].v_type == VAR_UNKNOWN)
12773 seconds = time(NULL);
12774 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012775 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012776 curtime = localtime(&seconds);
12777 /* MSVC returns NULL for an invalid value of seconds. */
12778 if (curtime == NULL)
12779 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12780 else
12781 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012782 vimconv_T conv;
12783 char_u *enc;
12784
12785 conv.vc_type = CONV_NONE;
12786 enc = enc_locale();
12787 convert_setup(&conv, p_enc, enc);
12788 if (conv.vc_type != CONV_NONE)
12789 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012790 if (p != NULL)
12791 (void)strftime((char *)result_buf, sizeof(result_buf),
12792 (char *)p, curtime);
12793 else
12794 result_buf[0] = NUL;
12795
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012796 if (conv.vc_type != CONV_NONE)
12797 vim_free(p);
12798 convert_setup(&conv, enc, p_enc);
12799 if (conv.vc_type != CONV_NONE)
12800 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12801 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012802 rettv->vval.v_string = vim_strsave(result_buf);
12803
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012804 /* Release conversion descriptors */
12805 convert_setup(&conv, NULL, NULL);
12806 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012807 }
12808}
12809#endif
12810
12811/*
12812 * "strgetchar()" function
12813 */
12814 static void
12815f_strgetchar(typval_T *argvars, typval_T *rettv)
12816{
12817 char_u *str;
12818 int len;
12819 int error = FALSE;
12820 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012821 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012822
12823 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012824 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012825 if (str == NULL)
12826 return;
12827 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012828 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012829 if (error)
12830 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012831
Bram Moolenaar13505972019-01-24 15:04:48 +010012832 while (charidx >= 0 && byteidx < len)
12833 {
12834 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012835 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012836 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12837 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012838 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012839 --charidx;
12840 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012841 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012842}
12843
12844/*
12845 * "stridx()" function
12846 */
12847 static void
12848f_stridx(typval_T *argvars, typval_T *rettv)
12849{
12850 char_u buf[NUMBUFLEN];
12851 char_u *needle;
12852 char_u *haystack;
12853 char_u *save_haystack;
12854 char_u *pos;
12855 int start_idx;
12856
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012857 needle = tv_get_string_chk(&argvars[1]);
12858 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012859 rettv->vval.v_number = -1;
12860 if (needle == NULL || haystack == NULL)
12861 return; /* type error; errmsg already given */
12862
12863 if (argvars[2].v_type != VAR_UNKNOWN)
12864 {
12865 int error = FALSE;
12866
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012867 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012868 if (error || start_idx >= (int)STRLEN(haystack))
12869 return;
12870 if (start_idx >= 0)
12871 haystack += start_idx;
12872 }
12873
12874 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12875 if (pos != NULL)
12876 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12877}
12878
12879/*
12880 * "string()" function
12881 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012882 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012883f_string(typval_T *argvars, typval_T *rettv)
12884{
12885 char_u *tofree;
12886 char_u numbuf[NUMBUFLEN];
12887
12888 rettv->v_type = VAR_STRING;
12889 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12890 get_copyID());
12891 /* Make a copy if we have a value but it's not in allocated memory. */
12892 if (rettv->vval.v_string != NULL && tofree == NULL)
12893 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12894}
12895
12896/*
12897 * "strlen()" function
12898 */
12899 static void
12900f_strlen(typval_T *argvars, typval_T *rettv)
12901{
12902 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012903 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012904}
12905
12906/*
12907 * "strchars()" function
12908 */
12909 static void
12910f_strchars(typval_T *argvars, typval_T *rettv)
12911{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012912 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012913 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012914 varnumber_T len = 0;
12915 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012916
12917 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012918 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012919 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012920 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012921 else
12922 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012923 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12924 while (*s != NUL)
12925 {
12926 func_mb_ptr2char_adv(&s);
12927 ++len;
12928 }
12929 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012930 }
12931}
12932
12933/*
12934 * "strdisplaywidth()" function
12935 */
12936 static void
12937f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12938{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012939 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012940 int col = 0;
12941
12942 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012943 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012944
12945 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12946}
12947
12948/*
12949 * "strwidth()" function
12950 */
12951 static void
12952f_strwidth(typval_T *argvars, typval_T *rettv)
12953{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012954 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012955
Bram Moolenaar13505972019-01-24 15:04:48 +010012956 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012957}
12958
12959/*
12960 * "strcharpart()" function
12961 */
12962 static void
12963f_strcharpart(typval_T *argvars, typval_T *rettv)
12964{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012965 char_u *p;
12966 int nchar;
12967 int nbyte = 0;
12968 int charlen;
12969 int len = 0;
12970 int slen;
12971 int error = FALSE;
12972
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012973 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012974 slen = (int)STRLEN(p);
12975
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012976 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012977 if (!error)
12978 {
12979 if (nchar > 0)
12980 while (nchar > 0 && nbyte < slen)
12981 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012982 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012983 --nchar;
12984 }
12985 else
12986 nbyte = nchar;
12987 if (argvars[2].v_type != VAR_UNKNOWN)
12988 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012989 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012990 while (charlen > 0 && nbyte + len < slen)
12991 {
12992 int off = nbyte + len;
12993
12994 if (off < 0)
12995 len += 1;
12996 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012997 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012998 --charlen;
12999 }
13000 }
13001 else
13002 len = slen - nbyte; /* default: all bytes that are available. */
13003 }
13004
13005 /*
13006 * Only return the overlap between the specified part and the actual
13007 * string.
13008 */
13009 if (nbyte < 0)
13010 {
13011 len += nbyte;
13012 nbyte = 0;
13013 }
13014 else if (nbyte > slen)
13015 nbyte = slen;
13016 if (len < 0)
13017 len = 0;
13018 else if (nbyte + len > slen)
13019 len = slen - nbyte;
13020
13021 rettv->v_type = VAR_STRING;
13022 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013023}
13024
13025/*
13026 * "strpart()" function
13027 */
13028 static void
13029f_strpart(typval_T *argvars, typval_T *rettv)
13030{
13031 char_u *p;
13032 int n;
13033 int len;
13034 int slen;
13035 int error = FALSE;
13036
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013037 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013038 slen = (int)STRLEN(p);
13039
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013040 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013041 if (error)
13042 len = 0;
13043 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013044 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013045 else
13046 len = slen - n; /* default len: all bytes that are available. */
13047
13048 /*
13049 * Only return the overlap between the specified part and the actual
13050 * string.
13051 */
13052 if (n < 0)
13053 {
13054 len += n;
13055 n = 0;
13056 }
13057 else if (n > slen)
13058 n = slen;
13059 if (len < 0)
13060 len = 0;
13061 else if (n + len > slen)
13062 len = slen - n;
13063
13064 rettv->v_type = VAR_STRING;
13065 rettv->vval.v_string = vim_strnsave(p + n, len);
13066}
13067
13068/*
13069 * "strridx()" function
13070 */
13071 static void
13072f_strridx(typval_T *argvars, typval_T *rettv)
13073{
13074 char_u buf[NUMBUFLEN];
13075 char_u *needle;
13076 char_u *haystack;
13077 char_u *rest;
13078 char_u *lastmatch = NULL;
13079 int haystack_len, end_idx;
13080
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013081 needle = tv_get_string_chk(&argvars[1]);
13082 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013083
13084 rettv->vval.v_number = -1;
13085 if (needle == NULL || haystack == NULL)
13086 return; /* type error; errmsg already given */
13087
13088 haystack_len = (int)STRLEN(haystack);
13089 if (argvars[2].v_type != VAR_UNKNOWN)
13090 {
13091 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013092 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013093 if (end_idx < 0)
13094 return; /* can never find a match */
13095 }
13096 else
13097 end_idx = haystack_len;
13098
13099 if (*needle == NUL)
13100 {
13101 /* Empty string matches past the end. */
13102 lastmatch = haystack + end_idx;
13103 }
13104 else
13105 {
13106 for (rest = haystack; *rest != '\0'; ++rest)
13107 {
13108 rest = (char_u *)strstr((char *)rest, (char *)needle);
13109 if (rest == NULL || rest > haystack + end_idx)
13110 break;
13111 lastmatch = rest;
13112 }
13113 }
13114
13115 if (lastmatch == NULL)
13116 rettv->vval.v_number = -1;
13117 else
13118 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
13119}
13120
13121/*
13122 * "strtrans()" function
13123 */
13124 static void
13125f_strtrans(typval_T *argvars, typval_T *rettv)
13126{
13127 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013128 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013129}
13130
13131/*
13132 * "submatch()" function
13133 */
13134 static void
13135f_submatch(typval_T *argvars, typval_T *rettv)
13136{
13137 int error = FALSE;
13138 int no;
13139 int retList = 0;
13140
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013141 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013142 if (error)
13143 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013144 if (no < 0 || no >= NSUBEXP)
13145 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013146 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010013147 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013148 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013149 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013150 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013151 if (error)
13152 return;
13153
13154 if (retList == 0)
13155 {
13156 rettv->v_type = VAR_STRING;
13157 rettv->vval.v_string = reg_submatch(no);
13158 }
13159 else
13160 {
13161 rettv->v_type = VAR_LIST;
13162 rettv->vval.v_list = reg_submatch_list(no);
13163 }
13164}
13165
13166/*
13167 * "substitute()" function
13168 */
13169 static void
13170f_substitute(typval_T *argvars, typval_T *rettv)
13171{
13172 char_u patbuf[NUMBUFLEN];
13173 char_u subbuf[NUMBUFLEN];
13174 char_u flagsbuf[NUMBUFLEN];
13175
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013176 char_u *str = tv_get_string_chk(&argvars[0]);
13177 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013178 char_u *sub = NULL;
13179 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013180 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013181
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013182 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13183 expr = &argvars[2];
13184 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013185 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013186
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013187 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013188 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13189 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013190 rettv->vval.v_string = NULL;
13191 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013192 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013193}
13194
13195/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013196 * "swapinfo(swap_filename)" function
13197 */
13198 static void
13199f_swapinfo(typval_T *argvars, typval_T *rettv)
13200{
13201 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013202 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013203}
13204
13205/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013206 * "swapname(expr)" function
13207 */
13208 static void
13209f_swapname(typval_T *argvars, typval_T *rettv)
13210{
13211 buf_T *buf;
13212
13213 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013214 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013215 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13216 || buf->b_ml.ml_mfp->mf_fname == NULL)
13217 rettv->vval.v_string = NULL;
13218 else
13219 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13220}
13221
13222/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013223 * "synID(lnum, col, trans)" function
13224 */
13225 static void
13226f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13227{
13228 int id = 0;
13229#ifdef FEAT_SYN_HL
13230 linenr_T lnum;
13231 colnr_T col;
13232 int trans;
13233 int transerr = FALSE;
13234
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013235 lnum = tv_get_lnum(argvars); /* -1 on type error */
13236 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13237 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013238
13239 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13240 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13241 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13242#endif
13243
13244 rettv->vval.v_number = id;
13245}
13246
13247/*
13248 * "synIDattr(id, what [, mode])" function
13249 */
13250 static void
13251f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13252{
13253 char_u *p = NULL;
13254#ifdef FEAT_SYN_HL
13255 int id;
13256 char_u *what;
13257 char_u *mode;
13258 char_u modebuf[NUMBUFLEN];
13259 int modec;
13260
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013261 id = (int)tv_get_number(&argvars[0]);
13262 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013263 if (argvars[2].v_type != VAR_UNKNOWN)
13264 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013265 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013266 modec = TOLOWER_ASC(mode[0]);
13267 if (modec != 't' && modec != 'c' && modec != 'g')
13268 modec = 0; /* replace invalid with current */
13269 }
13270 else
13271 {
13272#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13273 if (USE_24BIT)
13274 modec = 'g';
13275 else
13276#endif
13277 if (t_colors > 1)
13278 modec = 'c';
13279 else
13280 modec = 't';
13281 }
13282
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013283 switch (TOLOWER_ASC(what[0]))
13284 {
13285 case 'b':
13286 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13287 p = highlight_color(id, what, modec);
13288 else /* bold */
13289 p = highlight_has_attr(id, HL_BOLD, modec);
13290 break;
13291
13292 case 'f': /* fg[#] or font */
13293 p = highlight_color(id, what, modec);
13294 break;
13295
13296 case 'i':
13297 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13298 p = highlight_has_attr(id, HL_INVERSE, modec);
13299 else /* italic */
13300 p = highlight_has_attr(id, HL_ITALIC, modec);
13301 break;
13302
13303 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013304 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013305 break;
13306
13307 case 'r': /* reverse */
13308 p = highlight_has_attr(id, HL_INVERSE, modec);
13309 break;
13310
13311 case 's':
13312 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13313 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013314 /* strikeout */
13315 else if (TOLOWER_ASC(what[1]) == 't' &&
13316 TOLOWER_ASC(what[2]) == 'r')
13317 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013318 else /* standout */
13319 p = highlight_has_attr(id, HL_STANDOUT, modec);
13320 break;
13321
13322 case 'u':
13323 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13324 /* underline */
13325 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13326 else
13327 /* undercurl */
13328 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13329 break;
13330 }
13331
13332 if (p != NULL)
13333 p = vim_strsave(p);
13334#endif
13335 rettv->v_type = VAR_STRING;
13336 rettv->vval.v_string = p;
13337}
13338
13339/*
13340 * "synIDtrans(id)" function
13341 */
13342 static void
13343f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13344{
13345 int id;
13346
13347#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013348 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013349
13350 if (id > 0)
13351 id = syn_get_final_id(id);
13352 else
13353#endif
13354 id = 0;
13355
13356 rettv->vval.v_number = id;
13357}
13358
13359/*
13360 * "synconcealed(lnum, col)" function
13361 */
13362 static void
13363f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13364{
13365#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13366 linenr_T lnum;
13367 colnr_T col;
13368 int syntax_flags = 0;
13369 int cchar;
13370 int matchid = 0;
13371 char_u str[NUMBUFLEN];
13372#endif
13373
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013374 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013375
13376#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013377 lnum = tv_get_lnum(argvars); /* -1 on type error */
13378 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013379
13380 vim_memset(str, NUL, sizeof(str));
13381
13382 if (rettv_list_alloc(rettv) != FAIL)
13383 {
13384 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13385 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13386 && curwin->w_p_cole > 0)
13387 {
13388 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13389 syntax_flags = get_syntax_info(&matchid);
13390
13391 /* get the conceal character */
13392 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13393 {
13394 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013395 if (cchar == NUL && curwin->w_p_cole == 1)
13396 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013397 if (cchar != NUL)
13398 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013399 if (has_mbyte)
13400 (*mb_char2bytes)(cchar, str);
13401 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013402 str[0] = cchar;
13403 }
13404 }
13405 }
13406
13407 list_append_number(rettv->vval.v_list,
13408 (syntax_flags & HL_CONCEAL) != 0);
13409 /* -1 to auto-determine strlen */
13410 list_append_string(rettv->vval.v_list, str, -1);
13411 list_append_number(rettv->vval.v_list, matchid);
13412 }
13413#endif
13414}
13415
13416/*
13417 * "synstack(lnum, col)" function
13418 */
13419 static void
13420f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13421{
13422#ifdef FEAT_SYN_HL
13423 linenr_T lnum;
13424 colnr_T col;
13425 int i;
13426 int id;
13427#endif
13428
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013429 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013430
13431#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013432 lnum = tv_get_lnum(argvars); /* -1 on type error */
13433 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013434
13435 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13436 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13437 && rettv_list_alloc(rettv) != FAIL)
13438 {
13439 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13440 for (i = 0; ; ++i)
13441 {
13442 id = syn_get_stack_item(i);
13443 if (id < 0)
13444 break;
13445 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13446 break;
13447 }
13448 }
13449#endif
13450}
13451
13452 static void
13453get_cmd_output_as_rettv(
13454 typval_T *argvars,
13455 typval_T *rettv,
13456 int retlist)
13457{
13458 char_u *res = NULL;
13459 char_u *p;
13460 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013461 int err = FALSE;
13462 FILE *fd;
13463 list_T *list = NULL;
13464 int flags = SHELL_SILENT;
13465
13466 rettv->v_type = VAR_STRING;
13467 rettv->vval.v_string = NULL;
13468 if (check_restricted() || check_secure())
13469 goto errret;
13470
13471 if (argvars[1].v_type != VAR_UNKNOWN)
13472 {
13473 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013474 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013475 * command.
13476 */
13477 if ((infile = vim_tempname('i', TRUE)) == NULL)
13478 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013479 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013480 goto errret;
13481 }
13482
13483 fd = mch_fopen((char *)infile, WRITEBIN);
13484 if (fd == NULL)
13485 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013486 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013487 goto errret;
13488 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013489 if (argvars[1].v_type == VAR_NUMBER)
13490 {
13491 linenr_T lnum;
13492 buf_T *buf;
13493
13494 buf = buflist_findnr(argvars[1].vval.v_number);
13495 if (buf == NULL)
13496 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013497 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013498 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013499 goto errret;
13500 }
13501
13502 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13503 {
13504 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13505 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13506 {
13507 err = TRUE;
13508 break;
13509 }
13510 if (putc(NL, fd) == EOF)
13511 {
13512 err = TRUE;
13513 break;
13514 }
13515 }
13516 }
13517 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013518 {
13519 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13520 err = TRUE;
13521 }
13522 else
13523 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013524 size_t len;
13525 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013526
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013527 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013528 if (p == NULL)
13529 {
13530 fclose(fd);
13531 goto errret; /* type error; errmsg already given */
13532 }
13533 len = STRLEN(p);
13534 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13535 err = TRUE;
13536 }
13537 if (fclose(fd) != 0)
13538 err = TRUE;
13539 if (err)
13540 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013541 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013542 goto errret;
13543 }
13544 }
13545
13546 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13547 * echoes typeahead, that messes up the display. */
13548 if (!msg_silent)
13549 flags += SHELL_COOKED;
13550
13551 if (retlist)
13552 {
13553 int len;
13554 listitem_T *li;
13555 char_u *s = NULL;
13556 char_u *start;
13557 char_u *end;
13558 int i;
13559
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013560 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013561 if (res == NULL)
13562 goto errret;
13563
13564 list = list_alloc();
13565 if (list == NULL)
13566 goto errret;
13567
13568 for (i = 0; i < len; ++i)
13569 {
13570 start = res + i;
13571 while (i < len && res[i] != NL)
13572 ++i;
13573 end = res + i;
13574
13575 s = alloc((unsigned)(end - start + 1));
13576 if (s == NULL)
13577 goto errret;
13578
13579 for (p = s; start < end; ++p, ++start)
13580 *p = *start == NUL ? NL : *start;
13581 *p = NUL;
13582
13583 li = listitem_alloc();
13584 if (li == NULL)
13585 {
13586 vim_free(s);
13587 goto errret;
13588 }
13589 li->li_tv.v_type = VAR_STRING;
13590 li->li_tv.v_lock = 0;
13591 li->li_tv.vval.v_string = s;
13592 list_append(list, li);
13593 }
13594
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013595 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013596 list = NULL;
13597 }
13598 else
13599 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013600 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010013601#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013602 /* translate <CR><NL> into <NL> */
13603 if (res != NULL)
13604 {
13605 char_u *s, *d;
13606
13607 d = res;
13608 for (s = res; *s; ++s)
13609 {
13610 if (s[0] == CAR && s[1] == NL)
13611 ++s;
13612 *d++ = *s;
13613 }
13614 *d = NUL;
13615 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013616#endif
13617 rettv->vval.v_string = res;
13618 res = NULL;
13619 }
13620
13621errret:
13622 if (infile != NULL)
13623 {
13624 mch_remove(infile);
13625 vim_free(infile);
13626 }
13627 if (res != NULL)
13628 vim_free(res);
13629 if (list != NULL)
13630 list_free(list);
13631}
13632
13633/*
13634 * "system()" function
13635 */
13636 static void
13637f_system(typval_T *argvars, typval_T *rettv)
13638{
13639 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13640}
13641
13642/*
13643 * "systemlist()" function
13644 */
13645 static void
13646f_systemlist(typval_T *argvars, typval_T *rettv)
13647{
13648 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13649}
13650
13651/*
13652 * "tabpagebuflist()" function
13653 */
13654 static void
13655f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13656{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013657 tabpage_T *tp;
13658 win_T *wp = NULL;
13659
13660 if (argvars[0].v_type == VAR_UNKNOWN)
13661 wp = firstwin;
13662 else
13663 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013664 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013665 if (tp != NULL)
13666 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13667 }
13668 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13669 {
13670 for (; wp != NULL; wp = wp->w_next)
13671 if (list_append_number(rettv->vval.v_list,
13672 wp->w_buffer->b_fnum) == FAIL)
13673 break;
13674 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013675}
13676
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013677/*
13678 * "tabpagenr()" function
13679 */
13680 static void
13681f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13682{
13683 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013684 char_u *arg;
13685
13686 if (argvars[0].v_type != VAR_UNKNOWN)
13687 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013688 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013689 nr = 0;
13690 if (arg != NULL)
13691 {
13692 if (STRCMP(arg, "$") == 0)
13693 nr = tabpage_index(NULL) - 1;
13694 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013695 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013696 }
13697 }
13698 else
13699 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013700 rettv->vval.v_number = nr;
13701}
13702
13703
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013704/*
13705 * Common code for tabpagewinnr() and winnr().
13706 */
13707 static int
13708get_winnr(tabpage_T *tp, typval_T *argvar)
13709{
13710 win_T *twin;
13711 int nr = 1;
13712 win_T *wp;
13713 char_u *arg;
13714
13715 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13716 if (argvar->v_type != VAR_UNKNOWN)
13717 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013718 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013719 if (arg == NULL)
13720 nr = 0; /* type error; errmsg already given */
13721 else if (STRCMP(arg, "$") == 0)
13722 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13723 else if (STRCMP(arg, "#") == 0)
13724 {
13725 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13726 if (twin == NULL)
13727 nr = 0;
13728 }
13729 else
13730 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013731 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013732 nr = 0;
13733 }
13734 }
13735
13736 if (nr > 0)
13737 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13738 wp != twin; wp = wp->w_next)
13739 {
13740 if (wp == NULL)
13741 {
13742 /* didn't find it in this tabpage */
13743 nr = 0;
13744 break;
13745 }
13746 ++nr;
13747 }
13748 return nr;
13749}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013750
13751/*
13752 * "tabpagewinnr()" function
13753 */
13754 static void
13755f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13756{
13757 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013758 tabpage_T *tp;
13759
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013760 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013761 if (tp == NULL)
13762 nr = 0;
13763 else
13764 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013765 rettv->vval.v_number = nr;
13766}
13767
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013768/*
13769 * "tagfiles()" function
13770 */
13771 static void
13772f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13773{
13774 char_u *fname;
13775 tagname_T tn;
13776 int first;
13777
13778 if (rettv_list_alloc(rettv) == FAIL)
13779 return;
13780 fname = alloc(MAXPATHL);
13781 if (fname == NULL)
13782 return;
13783
13784 for (first = TRUE; ; first = FALSE)
13785 if (get_tagfname(&tn, first, fname) == FAIL
13786 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13787 break;
13788 tagname_free(&tn);
13789 vim_free(fname);
13790}
13791
13792/*
13793 * "taglist()" function
13794 */
13795 static void
13796f_taglist(typval_T *argvars, typval_T *rettv)
13797{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013798 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013799 char_u *tag_pattern;
13800
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013801 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013802
13803 rettv->vval.v_number = FALSE;
13804 if (*tag_pattern == NUL)
13805 return;
13806
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013807 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013808 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013809 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013810 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013811}
13812
13813/*
13814 * "tempname()" function
13815 */
13816 static void
13817f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13818{
13819 static int x = 'A';
13820
13821 rettv->v_type = VAR_STRING;
13822 rettv->vval.v_string = vim_tempname(x, FALSE);
13823
13824 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13825 * names. Skip 'I' and 'O', they are used for shell redirection. */
13826 do
13827 {
13828 if (x == 'Z')
13829 x = '0';
13830 else if (x == '9')
13831 x = 'A';
13832 else
13833 {
13834#ifdef EBCDIC
13835 if (x == 'I')
13836 x = 'J';
13837 else if (x == 'R')
13838 x = 'S';
13839 else
13840#endif
13841 ++x;
13842 }
13843 } while (x == 'I' || x == 'O');
13844}
13845
13846#ifdef FEAT_FLOAT
13847/*
13848 * "tan()" function
13849 */
13850 static void
13851f_tan(typval_T *argvars, typval_T *rettv)
13852{
13853 float_T f = 0.0;
13854
13855 rettv->v_type = VAR_FLOAT;
13856 if (get_float_arg(argvars, &f) == OK)
13857 rettv->vval.v_float = tan(f);
13858 else
13859 rettv->vval.v_float = 0.0;
13860}
13861
13862/*
13863 * "tanh()" function
13864 */
13865 static void
13866f_tanh(typval_T *argvars, typval_T *rettv)
13867{
13868 float_T f = 0.0;
13869
13870 rettv->v_type = VAR_FLOAT;
13871 if (get_float_arg(argvars, &f) == OK)
13872 rettv->vval.v_float = tanh(f);
13873 else
13874 rettv->vval.v_float = 0.0;
13875}
13876#endif
13877
13878/*
13879 * "test_alloc_fail(id, countdown, repeat)" function
13880 */
13881 static void
13882f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13883{
13884 if (argvars[0].v_type != VAR_NUMBER
13885 || argvars[0].vval.v_number <= 0
13886 || argvars[1].v_type != VAR_NUMBER
13887 || argvars[1].vval.v_number < 0
13888 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013889 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013890 else
13891 {
13892 alloc_fail_id = argvars[0].vval.v_number;
13893 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013894 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013895 alloc_fail_countdown = argvars[1].vval.v_number;
13896 alloc_fail_repeat = argvars[2].vval.v_number;
13897 did_outofmem_msg = FALSE;
13898 }
13899}
13900
13901/*
13902 * "test_autochdir()"
13903 */
13904 static void
13905f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13906{
13907#if defined(FEAT_AUTOCHDIR)
13908 test_autochdir = TRUE;
13909#endif
13910}
13911
13912/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013913 * "test_feedinput()"
13914 */
13915 static void
13916f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13917{
13918#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013919 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013920
13921 if (val != NULL)
13922 {
13923 trash_input_buf();
13924 add_to_input_buf_csi(val, (int)STRLEN(val));
13925 }
13926#endif
13927}
13928
13929/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013930 * "test_option_not_set({name})" function
13931 */
13932 static void
13933f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13934{
13935 char_u *name = (char_u *)"";
13936
13937 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013938 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013939 else
13940 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013941 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013942 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013943 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013944 }
13945}
13946
13947/*
13948 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013949 */
13950 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013951f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013952{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013953 char_u *name = (char_u *)"";
13954 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013955 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013956
13957 if (argvars[0].v_type != VAR_STRING
13958 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013959 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013960 else
13961 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013962 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013963 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013964
13965 if (STRCMP(name, (char_u *)"redraw") == 0)
13966 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013967 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13968 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013969 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13970 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013971 else if (STRCMP(name, (char_u *)"starting") == 0)
13972 {
13973 if (val)
13974 {
13975 if (save_starting < 0)
13976 save_starting = starting;
13977 starting = 0;
13978 }
13979 else
13980 {
13981 starting = save_starting;
13982 save_starting = -1;
13983 }
13984 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013985 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13986 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013987 else if (STRCMP(name, (char_u *)"ALL") == 0)
13988 {
13989 disable_char_avail_for_testing = FALSE;
13990 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013991 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013992 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013993 if (save_starting >= 0)
13994 {
13995 starting = save_starting;
13996 save_starting = -1;
13997 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013998 }
13999 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014000 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010014001 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014002}
14003
14004/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010014005 * "test_refcount({expr})" function
14006 */
14007 static void
14008f_test_refcount(typval_T *argvars, typval_T *rettv)
14009{
14010 int retval = -1;
14011
14012 switch (argvars[0].v_type)
14013 {
14014 case VAR_UNKNOWN:
14015 case VAR_NUMBER:
14016 case VAR_FLOAT:
14017 case VAR_SPECIAL:
14018 case VAR_STRING:
14019 break;
14020 case VAR_JOB:
14021#ifdef FEAT_JOB_CHANNEL
14022 if (argvars[0].vval.v_job != NULL)
14023 retval = argvars[0].vval.v_job->jv_refcount - 1;
14024#endif
14025 break;
14026 case VAR_CHANNEL:
14027#ifdef FEAT_JOB_CHANNEL
14028 if (argvars[0].vval.v_channel != NULL)
14029 retval = argvars[0].vval.v_channel->ch_refcount - 1;
14030#endif
14031 break;
14032 case VAR_FUNC:
14033 if (argvars[0].vval.v_string != NULL)
14034 {
14035 ufunc_T *fp;
14036
14037 fp = find_func(argvars[0].vval.v_string);
14038 if (fp != NULL)
14039 retval = fp->uf_refcount;
14040 }
14041 break;
14042 case VAR_PARTIAL:
14043 if (argvars[0].vval.v_partial != NULL)
14044 retval = argvars[0].vval.v_partial->pt_refcount - 1;
14045 break;
14046 case VAR_BLOB:
14047 if (argvars[0].vval.v_blob != NULL)
14048 retval = argvars[0].vval.v_blob->bv_refcount - 1;
14049 break;
14050 case VAR_LIST:
14051 if (argvars[0].vval.v_list != NULL)
14052 retval = argvars[0].vval.v_list->lv_refcount - 1;
14053 break;
14054 case VAR_DICT:
14055 if (argvars[0].vval.v_dict != NULL)
14056 retval = argvars[0].vval.v_dict->dv_refcount - 1;
14057 break;
14058 }
14059
14060 rettv->v_type = VAR_NUMBER;
14061 rettv->vval.v_number = retval;
14062
14063}
14064
14065/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014066 * "test_garbagecollect_now()" function
14067 */
14068 static void
14069f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14070{
14071 /* This is dangerous, any Lists and Dicts used internally may be freed
14072 * while still in use. */
14073 garbage_collect(TRUE);
14074}
14075
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014076/*
14077 * "test_ignore_error()" function
14078 */
14079 static void
14080f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
14081{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014082 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014083}
14084
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010014085 static void
14086f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
14087{
14088 rettv->v_type = VAR_BLOB;
14089 rettv->vval.v_blob = NULL;
14090}
14091
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014092#ifdef FEAT_JOB_CHANNEL
14093 static void
14094f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
14095{
14096 rettv->v_type = VAR_CHANNEL;
14097 rettv->vval.v_channel = NULL;
14098}
14099#endif
14100
14101 static void
14102f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
14103{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014104 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014105}
14106
14107#ifdef FEAT_JOB_CHANNEL
14108 static void
14109f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
14110{
14111 rettv->v_type = VAR_JOB;
14112 rettv->vval.v_job = NULL;
14113}
14114#endif
14115
14116 static void
14117f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
14118{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014119 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014120}
14121
14122 static void
14123f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
14124{
14125 rettv->v_type = VAR_PARTIAL;
14126 rettv->vval.v_partial = NULL;
14127}
14128
14129 static void
14130f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
14131{
14132 rettv->v_type = VAR_STRING;
14133 rettv->vval.v_string = NULL;
14134}
14135
Bram Moolenaarab186732018-09-14 21:27:06 +020014136#ifdef FEAT_GUI
14137 static void
14138f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
14139{
14140 char_u *which;
14141 long value;
14142 int dragging;
14143 scrollbar_T *sb = NULL;
14144
14145 if (argvars[0].v_type != VAR_STRING
14146 || (argvars[1].v_type) != VAR_NUMBER
14147 || (argvars[2].v_type) != VAR_NUMBER)
14148 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014149 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020014150 return;
14151 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014152 which = tv_get_string(&argvars[0]);
14153 value = tv_get_number(&argvars[1]);
14154 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020014155
14156 if (STRCMP(which, "left") == 0)
14157 sb = &curwin->w_scrollbars[SBAR_LEFT];
14158 else if (STRCMP(which, "right") == 0)
14159 sb = &curwin->w_scrollbars[SBAR_RIGHT];
14160 else if (STRCMP(which, "hor") == 0)
14161 sb = &gui.bottom_sbar;
14162 if (sb == NULL)
14163 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014164 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020014165 return;
14166 }
14167 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020014168# ifndef USE_ON_FLY_SCROLL
14169 // need to loop through normal_cmd() to handle the scroll events
14170 exec_normal(FALSE, TRUE, FALSE);
14171# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020014172}
14173#endif
14174
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014175 static void
14176f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14177{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014178 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014179}
14180
14181#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14182/*
14183 * Get a callback from "arg". It can be a Funcref or a function name.
14184 * When "arg" is zero return an empty string.
14185 * Return NULL for an invalid argument.
14186 */
14187 char_u *
14188get_callback(typval_T *arg, partial_T **pp)
14189{
14190 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14191 {
14192 *pp = arg->vval.v_partial;
14193 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014194 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014195 }
14196 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014197 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014198 {
14199 func_ref(arg->vval.v_string);
14200 return arg->vval.v_string;
14201 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014202 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14203 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014204 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014205 return NULL;
14206}
14207
14208/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020014209 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014210 */
14211 void
14212free_callback(char_u *callback, partial_T *partial)
14213{
14214 if (partial != NULL)
14215 partial_unref(partial);
14216 else if (callback != NULL)
14217 {
14218 func_unref(callback);
14219 vim_free(callback);
14220 }
14221}
14222#endif
14223
14224#ifdef FEAT_TIMERS
14225/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014226 * "timer_info([timer])" function
14227 */
14228 static void
14229f_timer_info(typval_T *argvars, typval_T *rettv)
14230{
14231 timer_T *timer = NULL;
14232
14233 if (rettv_list_alloc(rettv) != OK)
14234 return;
14235 if (argvars[0].v_type != VAR_UNKNOWN)
14236 {
14237 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014238 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014239 else
14240 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014241 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014242 if (timer != NULL)
14243 add_timer_info(rettv, timer);
14244 }
14245 }
14246 else
14247 add_timer_info_all(rettv);
14248}
14249
14250/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014251 * "timer_pause(timer, paused)" function
14252 */
14253 static void
14254f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14255{
14256 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014257 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014258
14259 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014260 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014261 else
14262 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014263 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014264 if (timer != NULL)
14265 timer->tr_paused = paused;
14266 }
14267}
14268
14269/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014270 * "timer_start(time, callback [, options])" function
14271 */
14272 static void
14273f_timer_start(typval_T *argvars, typval_T *rettv)
14274{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014275 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014276 timer_T *timer;
14277 int repeat = 0;
14278 char_u *callback;
14279 dict_T *dict;
14280 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014281
Bram Moolenaar75537a92016-09-05 22:45:28 +020014282 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014283 if (check_secure())
14284 return;
14285 if (argvars[2].v_type != VAR_UNKNOWN)
14286 {
14287 if (argvars[2].v_type != VAR_DICT
14288 || (dict = argvars[2].vval.v_dict) == NULL)
14289 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014290 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014291 return;
14292 }
14293 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014294 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014295 }
14296
Bram Moolenaar75537a92016-09-05 22:45:28 +020014297 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014298 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014299 return;
14300
14301 timer = create_timer(msec, repeat);
14302 if (timer == NULL)
14303 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014304 else
14305 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014306 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014307 timer->tr_callback = vim_strsave(callback);
14308 else
14309 /* pointer into the partial */
14310 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014311 timer->tr_partial = partial;
14312 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014313 }
14314}
14315
14316/*
14317 * "timer_stop(timer)" function
14318 */
14319 static void
14320f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14321{
14322 timer_T *timer;
14323
14324 if (argvars[0].v_type != VAR_NUMBER)
14325 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014326 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014327 return;
14328 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014329 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014330 if (timer != NULL)
14331 stop_timer(timer);
14332}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014333
14334/*
14335 * "timer_stopall()" function
14336 */
14337 static void
14338f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14339{
14340 stop_all_timers();
14341}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014342#endif
14343
14344/*
14345 * "tolower(string)" function
14346 */
14347 static void
14348f_tolower(typval_T *argvars, typval_T *rettv)
14349{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014350 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014351 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014352}
14353
14354/*
14355 * "toupper(string)" function
14356 */
14357 static void
14358f_toupper(typval_T *argvars, typval_T *rettv)
14359{
14360 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014361 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014362}
14363
14364/*
14365 * "tr(string, fromstr, tostr)" function
14366 */
14367 static void
14368f_tr(typval_T *argvars, typval_T *rettv)
14369{
14370 char_u *in_str;
14371 char_u *fromstr;
14372 char_u *tostr;
14373 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014374 int inlen;
14375 int fromlen;
14376 int tolen;
14377 int idx;
14378 char_u *cpstr;
14379 int cplen;
14380 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014381 char_u buf[NUMBUFLEN];
14382 char_u buf2[NUMBUFLEN];
14383 garray_T ga;
14384
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014385 in_str = tv_get_string(&argvars[0]);
14386 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14387 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014388
14389 /* Default return value: empty string. */
14390 rettv->v_type = VAR_STRING;
14391 rettv->vval.v_string = NULL;
14392 if (fromstr == NULL || tostr == NULL)
14393 return; /* type error; errmsg already given */
14394 ga_init2(&ga, (int)sizeof(char), 80);
14395
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014396 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014397 /* not multi-byte: fromstr and tostr must be the same length */
14398 if (STRLEN(fromstr) != STRLEN(tostr))
14399 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014400error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014401 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014402 ga_clear(&ga);
14403 return;
14404 }
14405
14406 /* fromstr and tostr have to contain the same number of chars */
14407 while (*in_str != NUL)
14408 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014409 if (has_mbyte)
14410 {
14411 inlen = (*mb_ptr2len)(in_str);
14412 cpstr = in_str;
14413 cplen = inlen;
14414 idx = 0;
14415 for (p = fromstr; *p != NUL; p += fromlen)
14416 {
14417 fromlen = (*mb_ptr2len)(p);
14418 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14419 {
14420 for (p = tostr; *p != NUL; p += tolen)
14421 {
14422 tolen = (*mb_ptr2len)(p);
14423 if (idx-- == 0)
14424 {
14425 cplen = tolen;
14426 cpstr = p;
14427 break;
14428 }
14429 }
14430 if (*p == NUL) /* tostr is shorter than fromstr */
14431 goto error;
14432 break;
14433 }
14434 ++idx;
14435 }
14436
14437 if (first && cpstr == in_str)
14438 {
14439 /* Check that fromstr and tostr have the same number of
14440 * (multi-byte) characters. Done only once when a character
14441 * of in_str doesn't appear in fromstr. */
14442 first = FALSE;
14443 for (p = tostr; *p != NUL; p += tolen)
14444 {
14445 tolen = (*mb_ptr2len)(p);
14446 --idx;
14447 }
14448 if (idx != 0)
14449 goto error;
14450 }
14451
14452 (void)ga_grow(&ga, cplen);
14453 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14454 ga.ga_len += cplen;
14455
14456 in_str += inlen;
14457 }
14458 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014459 {
14460 /* When not using multi-byte chars we can do it faster. */
14461 p = vim_strchr(fromstr, *in_str);
14462 if (p != NULL)
14463 ga_append(&ga, tostr[p - fromstr]);
14464 else
14465 ga_append(&ga, *in_str);
14466 ++in_str;
14467 }
14468 }
14469
14470 /* add a terminating NUL */
14471 (void)ga_grow(&ga, 1);
14472 ga_append(&ga, NUL);
14473
14474 rettv->vval.v_string = ga.ga_data;
14475}
14476
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014477/*
14478 * "trim({expr})" function
14479 */
14480 static void
14481f_trim(typval_T *argvars, typval_T *rettv)
14482{
14483 char_u buf1[NUMBUFLEN];
14484 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014485 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014486 char_u *mask = NULL;
14487 char_u *tail;
14488 char_u *prev;
14489 char_u *p;
14490 int c1;
14491
14492 rettv->v_type = VAR_STRING;
14493 if (head == NULL)
14494 {
14495 rettv->vval.v_string = NULL;
14496 return;
14497 }
14498
14499 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014500 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014501
14502 while (*head != NUL)
14503 {
14504 c1 = PTR2CHAR(head);
14505 if (mask == NULL)
14506 {
14507 if (c1 > ' ' && c1 != 0xa0)
14508 break;
14509 }
14510 else
14511 {
14512 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14513 if (c1 == PTR2CHAR(p))
14514 break;
14515 if (*p == NUL)
14516 break;
14517 }
14518 MB_PTR_ADV(head);
14519 }
14520
14521 for (tail = head + STRLEN(head); tail > head; tail = prev)
14522 {
14523 prev = tail;
14524 MB_PTR_BACK(head, prev);
14525 c1 = PTR2CHAR(prev);
14526 if (mask == NULL)
14527 {
14528 if (c1 > ' ' && c1 != 0xa0)
14529 break;
14530 }
14531 else
14532 {
14533 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14534 if (c1 == PTR2CHAR(p))
14535 break;
14536 if (*p == NUL)
14537 break;
14538 }
14539 }
14540 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14541}
14542
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014543#ifdef FEAT_FLOAT
14544/*
14545 * "trunc({float})" function
14546 */
14547 static void
14548f_trunc(typval_T *argvars, typval_T *rettv)
14549{
14550 float_T f = 0.0;
14551
14552 rettv->v_type = VAR_FLOAT;
14553 if (get_float_arg(argvars, &f) == OK)
14554 /* trunc() is not in C90, use floor() or ceil() instead. */
14555 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14556 else
14557 rettv->vval.v_float = 0.0;
14558}
14559#endif
14560
14561/*
14562 * "type(expr)" function
14563 */
14564 static void
14565f_type(typval_T *argvars, typval_T *rettv)
14566{
14567 int n = -1;
14568
14569 switch (argvars[0].v_type)
14570 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014571 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14572 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014573 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014574 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14575 case VAR_LIST: n = VAR_TYPE_LIST; break;
14576 case VAR_DICT: n = VAR_TYPE_DICT; break;
14577 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014578 case VAR_SPECIAL:
14579 if (argvars[0].vval.v_number == VVAL_FALSE
14580 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014581 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014582 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014583 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014584 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014585 case VAR_JOB: n = VAR_TYPE_JOB; break;
14586 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014587 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014588 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014589 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014590 n = -1;
14591 break;
14592 }
14593 rettv->vval.v_number = n;
14594}
14595
14596/*
14597 * "undofile(name)" function
14598 */
14599 static void
14600f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14601{
14602 rettv->v_type = VAR_STRING;
14603#ifdef FEAT_PERSISTENT_UNDO
14604 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014605 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014606
14607 if (*fname == NUL)
14608 {
14609 /* If there is no file name there will be no undo file. */
14610 rettv->vval.v_string = NULL;
14611 }
14612 else
14613 {
14614 char_u *ffname = FullName_save(fname, FALSE);
14615
14616 if (ffname != NULL)
14617 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14618 vim_free(ffname);
14619 }
14620 }
14621#else
14622 rettv->vval.v_string = NULL;
14623#endif
14624}
14625
14626/*
14627 * "undotree()" function
14628 */
14629 static void
14630f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14631{
14632 if (rettv_dict_alloc(rettv) == OK)
14633 {
14634 dict_T *dict = rettv->vval.v_dict;
14635 list_T *list;
14636
Bram Moolenaare0be1672018-07-08 16:50:37 +020014637 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14638 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14639 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14640 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14641 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14642 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014643
14644 list = list_alloc();
14645 if (list != NULL)
14646 {
14647 u_eval_tree(curbuf->b_u_oldhead, list);
14648 dict_add_list(dict, "entries", list);
14649 }
14650 }
14651}
14652
14653/*
14654 * "values(dict)" function
14655 */
14656 static void
14657f_values(typval_T *argvars, typval_T *rettv)
14658{
14659 dict_list(argvars, rettv, 1);
14660}
14661
14662/*
14663 * "virtcol(string)" function
14664 */
14665 static void
14666f_virtcol(typval_T *argvars, typval_T *rettv)
14667{
14668 colnr_T vcol = 0;
14669 pos_T *fp;
14670 int fnum = curbuf->b_fnum;
14671
14672 fp = var2fpos(&argvars[0], FALSE, &fnum);
14673 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14674 && fnum == curbuf->b_fnum)
14675 {
14676 getvvcol(curwin, fp, NULL, NULL, &vcol);
14677 ++vcol;
14678 }
14679
14680 rettv->vval.v_number = vcol;
14681}
14682
14683/*
14684 * "visualmode()" function
14685 */
14686 static void
14687f_visualmode(typval_T *argvars, typval_T *rettv)
14688{
14689 char_u str[2];
14690
14691 rettv->v_type = VAR_STRING;
14692 str[0] = curbuf->b_visual_mode_eval;
14693 str[1] = NUL;
14694 rettv->vval.v_string = vim_strsave(str);
14695
14696 /* A non-zero number or non-empty string argument: reset mode. */
14697 if (non_zero_arg(&argvars[0]))
14698 curbuf->b_visual_mode_eval = NUL;
14699}
14700
14701/*
14702 * "wildmenumode()" function
14703 */
14704 static void
14705f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14706{
14707#ifdef FEAT_WILDMENU
14708 if (wild_menu_showing)
14709 rettv->vval.v_number = 1;
14710#endif
14711}
14712
14713/*
14714 * "winbufnr(nr)" function
14715 */
14716 static void
14717f_winbufnr(typval_T *argvars, typval_T *rettv)
14718{
14719 win_T *wp;
14720
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014721 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014722 if (wp == NULL)
14723 rettv->vval.v_number = -1;
14724 else
14725 rettv->vval.v_number = wp->w_buffer->b_fnum;
14726}
14727
14728/*
14729 * "wincol()" function
14730 */
14731 static void
14732f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14733{
14734 validate_cursor();
14735 rettv->vval.v_number = curwin->w_wcol + 1;
14736}
14737
14738/*
14739 * "winheight(nr)" function
14740 */
14741 static void
14742f_winheight(typval_T *argvars, typval_T *rettv)
14743{
14744 win_T *wp;
14745
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014746 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014747 if (wp == NULL)
14748 rettv->vval.v_number = -1;
14749 else
14750 rettv->vval.v_number = wp->w_height;
14751}
14752
14753/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014754 * "winlayout()" function
14755 */
14756 static void
14757f_winlayout(typval_T *argvars, typval_T *rettv)
14758{
14759 tabpage_T *tp;
14760
14761 if (rettv_list_alloc(rettv) != OK)
14762 return;
14763
14764 if (argvars[0].v_type == VAR_UNKNOWN)
14765 tp = curtab;
14766 else
14767 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014768 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014769 if (tp == NULL)
14770 return;
14771 }
14772
14773 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14774}
14775
14776/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014777 * "winline()" function
14778 */
14779 static void
14780f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14781{
14782 validate_cursor();
14783 rettv->vval.v_number = curwin->w_wrow + 1;
14784}
14785
14786/*
14787 * "winnr()" function
14788 */
14789 static void
14790f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14791{
14792 int nr = 1;
14793
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014794 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014795 rettv->vval.v_number = nr;
14796}
14797
14798/*
14799 * "winrestcmd()" function
14800 */
14801 static void
14802f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14803{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014804 win_T *wp;
14805 int winnr = 1;
14806 garray_T ga;
14807 char_u buf[50];
14808
14809 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014810 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014811 {
14812 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14813 ga_concat(&ga, buf);
14814 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14815 ga_concat(&ga, buf);
14816 ++winnr;
14817 }
14818 ga_append(&ga, NUL);
14819
14820 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014821 rettv->v_type = VAR_STRING;
14822}
14823
14824/*
14825 * "winrestview()" function
14826 */
14827 static void
14828f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14829{
14830 dict_T *dict;
14831
14832 if (argvars[0].v_type != VAR_DICT
14833 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014834 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014835 else
14836 {
14837 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014838 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014839 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014840 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014841 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014842 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014843 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14844 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014845 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014846 curwin->w_set_curswant = FALSE;
14847 }
14848
14849 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014850 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014851#ifdef FEAT_DIFF
14852 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014853 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014854#endif
14855 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014856 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014857 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014858 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014859
14860 check_cursor();
14861 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014862 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014863 changed_window_setting();
14864
14865 if (curwin->w_topline <= 0)
14866 curwin->w_topline = 1;
14867 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14868 curwin->w_topline = curbuf->b_ml.ml_line_count;
14869#ifdef FEAT_DIFF
14870 check_topfill(curwin, TRUE);
14871#endif
14872 }
14873}
14874
14875/*
14876 * "winsaveview()" function
14877 */
14878 static void
14879f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14880{
14881 dict_T *dict;
14882
14883 if (rettv_dict_alloc(rettv) == FAIL)
14884 return;
14885 dict = rettv->vval.v_dict;
14886
Bram Moolenaare0be1672018-07-08 16:50:37 +020014887 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14888 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020014889 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014890 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014891 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014892
Bram Moolenaare0be1672018-07-08 16:50:37 +020014893 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014894#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014895 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014896#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014897 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14898 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014899}
14900
14901/*
14902 * "winwidth(nr)" function
14903 */
14904 static void
14905f_winwidth(typval_T *argvars, typval_T *rettv)
14906{
14907 win_T *wp;
14908
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014909 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014910 if (wp == NULL)
14911 rettv->vval.v_number = -1;
14912 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014913 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014914}
14915
14916/*
14917 * "wordcount()" function
14918 */
14919 static void
14920f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14921{
14922 if (rettv_dict_alloc(rettv) == FAIL)
14923 return;
14924 cursor_pos_info(rettv->vval.v_dict);
14925}
14926
14927/*
14928 * "writefile()" function
14929 */
14930 static void
14931f_writefile(typval_T *argvars, typval_T *rettv)
14932{
14933 int binary = FALSE;
14934 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014935#ifdef HAVE_FSYNC
14936 int do_fsync = p_fs;
14937#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014938 char_u *fname;
14939 FILE *fd;
14940 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014941 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014942 list_T *list = NULL;
14943 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014944
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014945 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010014946 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014947 return;
14948
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014949 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014950 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014951 list = argvars[0].vval.v_list;
14952 if (list == NULL)
14953 return;
14954 for (li = list->lv_first; li != NULL; li = li->li_next)
14955 if (tv_get_string_chk(&li->li_tv) == NULL)
14956 return;
14957 }
14958 else if (argvars[0].v_type == VAR_BLOB)
14959 {
14960 blob = argvars[0].vval.v_blob;
14961 if (blob == NULL)
14962 return;
14963 }
14964 else
14965 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014966 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014967 return;
14968 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014969
14970 if (argvars[2].v_type != VAR_UNKNOWN)
14971 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014972 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014973
14974 if (arg2 == NULL)
14975 return;
14976 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014977 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014978 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014979 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014980#ifdef HAVE_FSYNC
14981 if (vim_strchr(arg2, 's') != NULL)
14982 do_fsync = TRUE;
14983 else if (vim_strchr(arg2, 'S') != NULL)
14984 do_fsync = FALSE;
14985#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014986 }
14987
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014988 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014989 if (fname == NULL)
14990 return;
14991
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014992 /* Always open the file in binary mode, library functions have a mind of
14993 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014994 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14995 append ? APPENDBIN : WRITEBIN)) == NULL)
14996 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014997 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014998 ret = -1;
14999 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015000 else if (blob)
15001 {
15002 if (write_blob(fd, blob) == FAIL)
15003 ret = -1;
15004#ifdef HAVE_FSYNC
15005 else if (do_fsync)
15006 // Ignore the error, the user wouldn't know what to do about it.
15007 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010015008 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010015009#endif
15010 fclose(fd);
15011 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015012 else
15013 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015014 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015015 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015016#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010015017 else if (do_fsync)
15018 /* Ignore the error, the user wouldn't know what to do about it.
15019 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010015020 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015021#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015022 fclose(fd);
15023 }
15024
15025 rettv->vval.v_number = ret;
15026}
15027
15028/*
15029 * "xor(expr, expr)" function
15030 */
15031 static void
15032f_xor(typval_T *argvars, typval_T *rettv)
15033{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015034 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
15035 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015036}
15037
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015038#endif /* FEAT_EVAL */