blob: 2eafe140ce310e423393cf21dc5b1e2e1a7ae537 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * evalfunc.c: Builtin functions
12 */
13#define USING_FLOAT_STUFF
14
15#include "vim.h"
16
17#if defined(FEAT_EVAL) || defined(PROTO)
18
19#ifdef AMIGA
20# include <time.h> /* for strftime() */
21#endif
22
23#ifdef VMS
24# include <float.h>
25#endif
26
Bram Moolenaard0573012017-10-28 21:11:06 +020027#ifdef MACOS_X
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020028# include <time.h> /* for time_t */
29#endif
30
31static char *e_listarg = N_("E686: Argument of %s must be a List");
Bram Moolenaarbf821bc2019-01-23 21:15:02 +010032static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020033static char *e_stringreq = N_("E928: String required");
Bram Moolenaaraff74912019-03-30 18:11:49 +010034static char *e_invalwindow = N_("E957: Invalid window number");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020035
36#ifdef FEAT_FLOAT
37static void f_abs(typval_T *argvars, typval_T *rettv);
38static void f_acos(typval_T *argvars, typval_T *rettv);
39#endif
40static void f_add(typval_T *argvars, typval_T *rettv);
41static void f_and(typval_T *argvars, typval_T *rettv);
42static void f_append(typval_T *argvars, typval_T *rettv);
Bram Moolenaarca851592018-06-06 21:04:07 +020043static void f_appendbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020044static void f_argc(typval_T *argvars, typval_T *rettv);
45static void f_argidx(typval_T *argvars, typval_T *rettv);
46static void f_arglistid(typval_T *argvars, typval_T *rettv);
47static void f_argv(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +010048static void f_assert_beeps(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020049static void f_assert_equal(typval_T *argvars, typval_T *rettv);
Bram Moolenaard96ff162018-02-18 22:13:29 +010050static void f_assert_equalfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020051static void f_assert_exception(typval_T *argvars, typval_T *rettv);
52static void f_assert_fails(typval_T *argvars, typval_T *rettv);
53static void f_assert_false(typval_T *argvars, typval_T *rettv);
Bram Moolenaar61c04492016-07-23 15:35:35 +020054static void f_assert_inrange(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020055static void f_assert_match(typval_T *argvars, typval_T *rettv);
56static void f_assert_notequal(typval_T *argvars, typval_T *rettv);
57static void f_assert_notmatch(typval_T *argvars, typval_T *rettv);
Bram Moolenaar42205552017-03-18 19:42:22 +010058static void f_assert_report(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020059static void f_assert_true(typval_T *argvars, typval_T *rettv);
60#ifdef FEAT_FLOAT
61static void f_asin(typval_T *argvars, typval_T *rettv);
62static void f_atan(typval_T *argvars, typval_T *rettv);
63static void f_atan2(typval_T *argvars, typval_T *rettv);
64#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010065#ifdef FEAT_BEVAL
66static void f_balloon_show(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010067# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +010068static void f_balloon_split(typval_T *argvars, typval_T *rettv);
Bram Moolenaar669a8282017-11-19 20:13:05 +010069# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +010070#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020071static void f_browse(typval_T *argvars, typval_T *rettv);
72static void f_browsedir(typval_T *argvars, typval_T *rettv);
73static void f_bufexists(typval_T *argvars, typval_T *rettv);
74static void f_buflisted(typval_T *argvars, typval_T *rettv);
75static void f_bufloaded(typval_T *argvars, typval_T *rettv);
76static void f_bufname(typval_T *argvars, typval_T *rettv);
77static void f_bufnr(typval_T *argvars, typval_T *rettv);
78static void f_bufwinid(typval_T *argvars, typval_T *rettv);
79static void f_bufwinnr(typval_T *argvars, typval_T *rettv);
80static void f_byte2line(typval_T *argvars, typval_T *rettv);
81static void byteidx(typval_T *argvars, typval_T *rettv, int comp);
82static void f_byteidx(typval_T *argvars, typval_T *rettv);
83static void f_byteidxcomp(typval_T *argvars, typval_T *rettv);
84static void f_call(typval_T *argvars, typval_T *rettv);
85#ifdef FEAT_FLOAT
86static void f_ceil(typval_T *argvars, typval_T *rettv);
87#endif
88#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +010089static void f_ch_canread(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020090static void f_ch_close(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0874a832016-09-01 15:11:51 +020091static void f_ch_close_in(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020092static void f_ch_evalexpr(typval_T *argvars, typval_T *rettv);
93static void f_ch_evalraw(typval_T *argvars, typval_T *rettv);
94static void f_ch_getbufnr(typval_T *argvars, typval_T *rettv);
95static void f_ch_getjob(typval_T *argvars, typval_T *rettv);
96static void f_ch_info(typval_T *argvars, typval_T *rettv);
97static void f_ch_log(typval_T *argvars, typval_T *rettv);
98static void f_ch_logfile(typval_T *argvars, typval_T *rettv);
99static void f_ch_open(typval_T *argvars, typval_T *rettv);
100static void f_ch_read(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100101static void f_ch_readblob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200102static void f_ch_readraw(typval_T *argvars, typval_T *rettv);
103static void f_ch_sendexpr(typval_T *argvars, typval_T *rettv);
104static void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
105static void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
106static void f_ch_status(typval_T *argvars, typval_T *rettv);
107#endif
108static void f_changenr(typval_T *argvars, typval_T *rettv);
109static void f_char2nr(typval_T *argvars, typval_T *rettv);
110static void f_cindent(typval_T *argvars, typval_T *rettv);
111static void f_clearmatches(typval_T *argvars, typval_T *rettv);
112static void f_col(typval_T *argvars, typval_T *rettv);
113#if defined(FEAT_INS_EXPAND)
114static void f_complete(typval_T *argvars, typval_T *rettv);
115static void f_complete_add(typval_T *argvars, typval_T *rettv);
116static void f_complete_check(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfd133322019-03-29 12:20:27 +0100117static void f_complete_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200118#endif
119static void f_confirm(typval_T *argvars, typval_T *rettv);
120static void f_copy(typval_T *argvars, typval_T *rettv);
121#ifdef FEAT_FLOAT
122static void f_cos(typval_T *argvars, typval_T *rettv);
123static void f_cosh(typval_T *argvars, typval_T *rettv);
124#endif
125static void f_count(typval_T *argvars, typval_T *rettv);
126static void f_cscope_connection(typval_T *argvars, typval_T *rettv);
127static void f_cursor(typval_T *argsvars, typval_T *rettv);
Bram Moolenaar4f974752019-02-17 17:44:42 +0100128#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200129static void f_debugbreak(typval_T *argvars, typval_T *rettv);
130#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200131static void f_deepcopy(typval_T *argvars, typval_T *rettv);
132static void f_delete(typval_T *argvars, typval_T *rettv);
Bram Moolenaard79a2622018-06-07 18:17:46 +0200133static void f_deletebufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200134static void f_did_filetype(typval_T *argvars, typval_T *rettv);
135static void f_diff_filler(typval_T *argvars, typval_T *rettv);
136static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
137static void f_empty(typval_T *argvars, typval_T *rettv);
138static void f_escape(typval_T *argvars, typval_T *rettv);
139static void f_eval(typval_T *argvars, typval_T *rettv);
140static void f_eventhandler(typval_T *argvars, typval_T *rettv);
141static void f_executable(typval_T *argvars, typval_T *rettv);
142static void f_execute(typval_T *argvars, typval_T *rettv);
143static void f_exepath(typval_T *argvars, typval_T *rettv);
144static void f_exists(typval_T *argvars, typval_T *rettv);
145#ifdef FEAT_FLOAT
146static void f_exp(typval_T *argvars, typval_T *rettv);
147#endif
148static void f_expand(typval_T *argvars, typval_T *rettv);
149static void f_extend(typval_T *argvars, typval_T *rettv);
150static void f_feedkeys(typval_T *argvars, typval_T *rettv);
151static void f_filereadable(typval_T *argvars, typval_T *rettv);
152static void f_filewritable(typval_T *argvars, typval_T *rettv);
153static void f_filter(typval_T *argvars, typval_T *rettv);
154static void f_finddir(typval_T *argvars, typval_T *rettv);
155static void f_findfile(typval_T *argvars, typval_T *rettv);
156#ifdef FEAT_FLOAT
157static void f_float2nr(typval_T *argvars, typval_T *rettv);
158static void f_floor(typval_T *argvars, typval_T *rettv);
159static void f_fmod(typval_T *argvars, typval_T *rettv);
160#endif
161static void f_fnameescape(typval_T *argvars, typval_T *rettv);
162static void f_fnamemodify(typval_T *argvars, typval_T *rettv);
163static void f_foldclosed(typval_T *argvars, typval_T *rettv);
164static void f_foldclosedend(typval_T *argvars, typval_T *rettv);
165static void f_foldlevel(typval_T *argvars, typval_T *rettv);
166static void f_foldtext(typval_T *argvars, typval_T *rettv);
167static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
168static void f_foreground(typval_T *argvars, typval_T *rettv);
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200169static void f_funcref(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200170static void f_function(typval_T *argvars, typval_T *rettv);
171static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
172static void f_get(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200173static void f_getbufinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200174static void f_getbufline(typval_T *argvars, typval_T *rettv);
175static void f_getbufvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100176static void f_getchangelist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200177static void f_getchar(typval_T *argvars, typval_T *rettv);
178static void f_getcharmod(typval_T *argvars, typval_T *rettv);
179static void f_getcharsearch(typval_T *argvars, typval_T *rettv);
180static void f_getcmdline(typval_T *argvars, typval_T *rettv);
181#if defined(FEAT_CMDL_COMPL)
182static void f_getcompletion(typval_T *argvars, typval_T *rettv);
183#endif
184static void f_getcmdpos(typval_T *argvars, typval_T *rettv);
185static void f_getcmdtype(typval_T *argvars, typval_T *rettv);
186static void f_getcmdwintype(typval_T *argvars, typval_T *rettv);
187static void f_getcwd(typval_T *argvars, typval_T *rettv);
188static void f_getfontname(typval_T *argvars, typval_T *rettv);
189static void f_getfperm(typval_T *argvars, typval_T *rettv);
190static void f_getfsize(typval_T *argvars, typval_T *rettv);
191static void f_getftime(typval_T *argvars, typval_T *rettv);
192static void f_getftype(typval_T *argvars, typval_T *rettv);
Bram Moolenaar4f505882018-02-10 21:06:32 +0100193static void f_getjumplist(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200194static void f_getline(typval_T *argvars, typval_T *rettv);
Bram Moolenaard823fa92016-08-12 16:29:27 +0200195static void f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200196static void f_getmatches(typval_T *argvars, typval_T *rettv);
197static void f_getpid(typval_T *argvars, typval_T *rettv);
198static void f_getcurpos(typval_T *argvars, typval_T *rettv);
199static void f_getpos(typval_T *argvars, typval_T *rettv);
200static void f_getqflist(typval_T *argvars, typval_T *rettv);
201static void f_getreg(typval_T *argvars, typval_T *rettv);
202static void f_getregtype(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200203static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200204static void f_gettabvar(typval_T *argvars, typval_T *rettv);
205static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100206static void f_gettagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200207static void f_getwininfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100208static void f_getwinpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200209static void f_getwinposx(typval_T *argvars, typval_T *rettv);
210static void f_getwinposy(typval_T *argvars, typval_T *rettv);
211static void f_getwinvar(typval_T *argvars, typval_T *rettv);
212static void f_glob(typval_T *argvars, typval_T *rettv);
213static void f_globpath(typval_T *argvars, typval_T *rettv);
214static void f_glob2regpat(typval_T *argvars, typval_T *rettv);
215static void f_has(typval_T *argvars, typval_T *rettv);
216static void f_has_key(typval_T *argvars, typval_T *rettv);
217static void f_haslocaldir(typval_T *argvars, typval_T *rettv);
218static void f_hasmapto(typval_T *argvars, typval_T *rettv);
219static void f_histadd(typval_T *argvars, typval_T *rettv);
220static void f_histdel(typval_T *argvars, typval_T *rettv);
221static void f_histget(typval_T *argvars, typval_T *rettv);
222static void f_histnr(typval_T *argvars, typval_T *rettv);
223static void f_hlID(typval_T *argvars, typval_T *rettv);
224static void f_hlexists(typval_T *argvars, typval_T *rettv);
225static void f_hostname(typval_T *argvars, typval_T *rettv);
226static void f_iconv(typval_T *argvars, typval_T *rettv);
227static void f_indent(typval_T *argvars, typval_T *rettv);
228static void f_index(typval_T *argvars, typval_T *rettv);
229static void f_input(typval_T *argvars, typval_T *rettv);
230static void f_inputdialog(typval_T *argvars, typval_T *rettv);
231static void f_inputlist(typval_T *argvars, typval_T *rettv);
232static void f_inputrestore(typval_T *argvars, typval_T *rettv);
233static void f_inputsave(typval_T *argvars, typval_T *rettv);
234static void f_inputsecret(typval_T *argvars, typval_T *rettv);
235static void f_insert(typval_T *argvars, typval_T *rettv);
236static void f_invert(typval_T *argvars, typval_T *rettv);
237static void f_isdirectory(typval_T *argvars, typval_T *rettv);
238static void f_islocked(typval_T *argvars, typval_T *rettv);
239#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
240static void f_isnan(typval_T *argvars, typval_T *rettv);
241#endif
242static void f_items(typval_T *argvars, typval_T *rettv);
243#ifdef FEAT_JOB_CHANNEL
244static void f_job_getchannel(typval_T *argvars, typval_T *rettv);
245static void f_job_info(typval_T *argvars, typval_T *rettv);
246static void f_job_setoptions(typval_T *argvars, typval_T *rettv);
247static void f_job_start(typval_T *argvars, typval_T *rettv);
248static void f_job_stop(typval_T *argvars, typval_T *rettv);
249static void f_job_status(typval_T *argvars, typval_T *rettv);
250#endif
251static void f_join(typval_T *argvars, typval_T *rettv);
252static void f_js_decode(typval_T *argvars, typval_T *rettv);
253static void f_js_encode(typval_T *argvars, typval_T *rettv);
254static void f_json_decode(typval_T *argvars, typval_T *rettv);
255static void f_json_encode(typval_T *argvars, typval_T *rettv);
256static void f_keys(typval_T *argvars, typval_T *rettv);
257static void f_last_buffer_nr(typval_T *argvars, typval_T *rettv);
258static void f_len(typval_T *argvars, typval_T *rettv);
259static void f_libcall(typval_T *argvars, typval_T *rettv);
260static void f_libcallnr(typval_T *argvars, typval_T *rettv);
261static void f_line(typval_T *argvars, typval_T *rettv);
262static void f_line2byte(typval_T *argvars, typval_T *rettv);
263static void f_lispindent(typval_T *argvars, typval_T *rettv);
264static void f_localtime(typval_T *argvars, typval_T *rettv);
265#ifdef FEAT_FLOAT
266static void f_log(typval_T *argvars, typval_T *rettv);
267static void f_log10(typval_T *argvars, typval_T *rettv);
268#endif
269#ifdef FEAT_LUA
270static void f_luaeval(typval_T *argvars, typval_T *rettv);
271#endif
272static void f_map(typval_T *argvars, typval_T *rettv);
273static void f_maparg(typval_T *argvars, typval_T *rettv);
274static void f_mapcheck(typval_T *argvars, typval_T *rettv);
275static void f_match(typval_T *argvars, typval_T *rettv);
276static void f_matchadd(typval_T *argvars, typval_T *rettv);
277static void f_matchaddpos(typval_T *argvars, typval_T *rettv);
278static void f_matcharg(typval_T *argvars, typval_T *rettv);
279static void f_matchdelete(typval_T *argvars, typval_T *rettv);
280static void f_matchend(typval_T *argvars, typval_T *rettv);
281static void f_matchlist(typval_T *argvars, typval_T *rettv);
282static void f_matchstr(typval_T *argvars, typval_T *rettv);
283static void f_matchstrpos(typval_T *argvars, typval_T *rettv);
284static void f_max(typval_T *argvars, typval_T *rettv);
285static void f_min(typval_T *argvars, typval_T *rettv);
286#ifdef vim_mkdir
287static void f_mkdir(typval_T *argvars, typval_T *rettv);
288#endif
289static void f_mode(typval_T *argvars, typval_T *rettv);
290#ifdef FEAT_MZSCHEME
291static void f_mzeval(typval_T *argvars, typval_T *rettv);
292#endif
293static void f_nextnonblank(typval_T *argvars, typval_T *rettv);
294static void f_nr2char(typval_T *argvars, typval_T *rettv);
295static void f_or(typval_T *argvars, typval_T *rettv);
296static void f_pathshorten(typval_T *argvars, typval_T *rettv);
297#ifdef FEAT_PERL
298static void f_perleval(typval_T *argvars, typval_T *rettv);
299#endif
300#ifdef FEAT_FLOAT
301static void f_pow(typval_T *argvars, typval_T *rettv);
302#endif
303static void f_prevnonblank(typval_T *argvars, typval_T *rettv);
304static void f_printf(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200305#ifdef FEAT_JOB_CHANNEL
306static void f_prompt_setcallback(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200307static void f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf2732452018-06-03 14:47:35 +0200308static void f_prompt_setprompt(typval_T *argvars, typval_T *rettv);
309#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200310static void f_pumvisible(typval_T *argvars, typval_T *rettv);
311#ifdef FEAT_PYTHON3
312static void f_py3eval(typval_T *argvars, typval_T *rettv);
313#endif
314#ifdef FEAT_PYTHON
315static void f_pyeval(typval_T *argvars, typval_T *rettv);
316#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100317#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
318static void f_pyxeval(typval_T *argvars, typval_T *rettv);
319#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200320static void f_range(typval_T *argvars, typval_T *rettv);
321static void f_readfile(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200322static void f_reg_executing(typval_T *argvars, typval_T *rettv);
323static void f_reg_recording(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200324static void f_reltime(typval_T *argvars, typval_T *rettv);
325#ifdef FEAT_FLOAT
326static void f_reltimefloat(typval_T *argvars, typval_T *rettv);
327#endif
328static void f_reltimestr(typval_T *argvars, typval_T *rettv);
329static void f_remote_expr(typval_T *argvars, typval_T *rettv);
330static void f_remote_foreground(typval_T *argvars, typval_T *rettv);
331static void f_remote_peek(typval_T *argvars, typval_T *rettv);
332static void f_remote_read(typval_T *argvars, typval_T *rettv);
333static void f_remote_send(typval_T *argvars, typval_T *rettv);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100334static void f_remote_startserver(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200335static void f_remove(typval_T *argvars, typval_T *rettv);
336static void f_rename(typval_T *argvars, typval_T *rettv);
337static void f_repeat(typval_T *argvars, typval_T *rettv);
338static void f_resolve(typval_T *argvars, typval_T *rettv);
339static void f_reverse(typval_T *argvars, typval_T *rettv);
340#ifdef FEAT_FLOAT
341static void f_round(typval_T *argvars, typval_T *rettv);
342#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100343#ifdef FEAT_RUBY
344static void f_rubyeval(typval_T *argvars, typval_T *rettv);
345#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200346static void f_screenattr(typval_T *argvars, typval_T *rettv);
347static void f_screenchar(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100348static void f_screenchars(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200349static void f_screencol(typval_T *argvars, typval_T *rettv);
350static void f_screenrow(typval_T *argvars, typval_T *rettv);
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100351static void f_screenstring(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200352static void f_search(typval_T *argvars, typval_T *rettv);
353static void f_searchdecl(typval_T *argvars, typval_T *rettv);
354static void f_searchpair(typval_T *argvars, typval_T *rettv);
355static void f_searchpairpos(typval_T *argvars, typval_T *rettv);
356static void f_searchpos(typval_T *argvars, typval_T *rettv);
357static void f_server2client(typval_T *argvars, typval_T *rettv);
358static void f_serverlist(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200359static void f_setbufline(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200360static void f_setbufvar(typval_T *argvars, typval_T *rettv);
361static void f_setcharsearch(typval_T *argvars, typval_T *rettv);
362static void f_setcmdpos(typval_T *argvars, typval_T *rettv);
363static void f_setfperm(typval_T *argvars, typval_T *rettv);
364static void f_setline(typval_T *argvars, typval_T *rettv);
365static void f_setloclist(typval_T *argvars, typval_T *rettv);
366static void f_setmatches(typval_T *argvars, typval_T *rettv);
367static void f_setpos(typval_T *argvars, typval_T *rettv);
368static void f_setqflist(typval_T *argvars, typval_T *rettv);
369static void f_setreg(typval_T *argvars, typval_T *rettv);
370static void f_settabvar(typval_T *argvars, typval_T *rettv);
371static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100372static void f_settagstack(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200373static void f_setwinvar(typval_T *argvars, typval_T *rettv);
374#ifdef FEAT_CRYPT
375static void f_sha256(typval_T *argvars, typval_T *rettv);
376#endif /* FEAT_CRYPT */
377static void f_shellescape(typval_T *argvars, typval_T *rettv);
378static void f_shiftwidth(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100379#ifdef FEAT_SIGNS
380static void f_sign_define(typval_T *argvars, typval_T *rettv);
381static void f_sign_getdefined(typval_T *argvars, typval_T *rettv);
382static void f_sign_getplaced(typval_T *argvars, typval_T *rettv);
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100383static void f_sign_jump(typval_T *argvars, typval_T *rettv);
Bram Moolenaar162b7142018-12-21 15:17:36 +0100384static void f_sign_place(typval_T *argvars, typval_T *rettv);
385static void f_sign_undefine(typval_T *argvars, typval_T *rettv);
386static void f_sign_unplace(typval_T *argvars, typval_T *rettv);
387#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200388static void f_simplify(typval_T *argvars, typval_T *rettv);
389#ifdef FEAT_FLOAT
390static void f_sin(typval_T *argvars, typval_T *rettv);
391static void f_sinh(typval_T *argvars, typval_T *rettv);
392#endif
393static void f_sort(typval_T *argvars, typval_T *rettv);
394static void f_soundfold(typval_T *argvars, typval_T *rettv);
395static void f_spellbadword(typval_T *argvars, typval_T *rettv);
396static void f_spellsuggest(typval_T *argvars, typval_T *rettv);
397static void f_split(typval_T *argvars, typval_T *rettv);
398#ifdef FEAT_FLOAT
399static void f_sqrt(typval_T *argvars, typval_T *rettv);
400static void f_str2float(typval_T *argvars, typval_T *rettv);
401#endif
402static void f_str2nr(typval_T *argvars, typval_T *rettv);
403static void f_strchars(typval_T *argvars, typval_T *rettv);
404#ifdef HAVE_STRFTIME
405static void f_strftime(typval_T *argvars, typval_T *rettv);
406#endif
407static void f_strgetchar(typval_T *argvars, typval_T *rettv);
408static void f_stridx(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200409static void f_strlen(typval_T *argvars, typval_T *rettv);
410static void f_strcharpart(typval_T *argvars, typval_T *rettv);
411static void f_strpart(typval_T *argvars, typval_T *rettv);
412static void f_strridx(typval_T *argvars, typval_T *rettv);
413static void f_strtrans(typval_T *argvars, typval_T *rettv);
414static void f_strdisplaywidth(typval_T *argvars, typval_T *rettv);
415static void f_strwidth(typval_T *argvars, typval_T *rettv);
416static void f_submatch(typval_T *argvars, typval_T *rettv);
417static void f_substitute(typval_T *argvars, typval_T *rettv);
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200418static void f_swapinfo(typval_T *argvars, typval_T *rettv);
Bram Moolenaar110bd602018-09-16 18:46:59 +0200419static void f_swapname(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200420static void f_synID(typval_T *argvars, typval_T *rettv);
421static void f_synIDattr(typval_T *argvars, typval_T *rettv);
422static void f_synIDtrans(typval_T *argvars, typval_T *rettv);
423static void f_synstack(typval_T *argvars, typval_T *rettv);
424static void f_synconcealed(typval_T *argvars, typval_T *rettv);
425static void f_system(typval_T *argvars, typval_T *rettv);
426static void f_systemlist(typval_T *argvars, typval_T *rettv);
427static void f_tabpagebuflist(typval_T *argvars, typval_T *rettv);
428static void f_tabpagenr(typval_T *argvars, typval_T *rettv);
429static void f_tabpagewinnr(typval_T *argvars, typval_T *rettv);
430static void f_taglist(typval_T *argvars, typval_T *rettv);
431static void f_tagfiles(typval_T *argvars, typval_T *rettv);
432static void f_tempname(typval_T *argvars, typval_T *rettv);
433static void f_test_alloc_fail(typval_T *argvars, typval_T *rettv);
434static void f_test_autochdir(typval_T *argvars, typval_T *rettv);
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200435static void f_test_feedinput(typval_T *argvars, typval_T *rettv);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200436static void f_test_option_not_set(typval_T *argvars, typval_T *rettv);
Bram Moolenaareb992cb2017-03-09 18:20:16 +0100437static void f_test_override(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100438static void f_test_refcount(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200439static void f_test_garbagecollect_now(typval_T *argvars, typval_T *rettv);
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100440static void f_test_ignore_error(typval_T *argvars, typval_T *rettv);
Bram Moolenaarc0f5a782019-01-13 15:16:13 +0100441static void f_test_null_blob(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200442#ifdef FEAT_JOB_CHANNEL
443static void f_test_null_channel(typval_T *argvars, typval_T *rettv);
444#endif
445static void f_test_null_dict(typval_T *argvars, typval_T *rettv);
446#ifdef FEAT_JOB_CHANNEL
447static void f_test_null_job(typval_T *argvars, typval_T *rettv);
448#endif
449static void f_test_null_list(typval_T *argvars, typval_T *rettv);
450static void f_test_null_partial(typval_T *argvars, typval_T *rettv);
451static void f_test_null_string(typval_T *argvars, typval_T *rettv);
Bram Moolenaarab186732018-09-14 21:27:06 +0200452#ifdef FEAT_GUI
453static void f_test_scrollbar(typval_T *argvars, typval_T *rettv);
454#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200455static void f_test_settime(typval_T *argvars, typval_T *rettv);
456#ifdef FEAT_FLOAT
457static void f_tan(typval_T *argvars, typval_T *rettv);
458static void f_tanh(typval_T *argvars, typval_T *rettv);
459#endif
460#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200461static void f_timer_info(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200462static void f_timer_pause(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200463static void f_timer_start(typval_T *argvars, typval_T *rettv);
464static void f_timer_stop(typval_T *argvars, typval_T *rettv);
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200465static void f_timer_stopall(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200466#endif
467static void f_tolower(typval_T *argvars, typval_T *rettv);
468static void f_toupper(typval_T *argvars, typval_T *rettv);
469static void f_tr(typval_T *argvars, typval_T *rettv);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100470static void f_trim(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200471#ifdef FEAT_FLOAT
472static void f_trunc(typval_T *argvars, typval_T *rettv);
473#endif
474static void f_type(typval_T *argvars, typval_T *rettv);
475static void f_undofile(typval_T *argvars, typval_T *rettv);
476static void f_undotree(typval_T *argvars, typval_T *rettv);
477static void f_uniq(typval_T *argvars, typval_T *rettv);
478static void f_values(typval_T *argvars, typval_T *rettv);
479static void f_virtcol(typval_T *argvars, typval_T *rettv);
480static void f_visualmode(typval_T *argvars, typval_T *rettv);
481static void f_wildmenumode(typval_T *argvars, typval_T *rettv);
482static void f_win_findbuf(typval_T *argvars, typval_T *rettv);
483static void f_win_getid(typval_T *argvars, typval_T *rettv);
484static void f_win_gotoid(typval_T *argvars, typval_T *rettv);
485static void f_win_id2tabwin(typval_T *argvars, typval_T *rettv);
486static void f_win_id2win(typval_T *argvars, typval_T *rettv);
Bram Moolenaar22044dc2017-12-02 15:43:37 +0100487static void f_win_screenpos(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200488static void f_winbufnr(typval_T *argvars, typval_T *rettv);
489static void f_wincol(typval_T *argvars, typval_T *rettv);
490static void f_winheight(typval_T *argvars, typval_T *rettv);
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +0200491static void f_winlayout(typval_T *argvars, typval_T *rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200492static void f_winline(typval_T *argvars, typval_T *rettv);
493static void f_winnr(typval_T *argvars, typval_T *rettv);
494static void f_winrestcmd(typval_T *argvars, typval_T *rettv);
495static void f_winrestview(typval_T *argvars, typval_T *rettv);
496static void f_winsaveview(typval_T *argvars, typval_T *rettv);
497static void f_winwidth(typval_T *argvars, typval_T *rettv);
498static void f_writefile(typval_T *argvars, typval_T *rettv);
499static void f_wordcount(typval_T *argvars, typval_T *rettv);
500static void f_xor(typval_T *argvars, typval_T *rettv);
501
502/*
503 * Array with names and number of arguments of all internal functions
504 * MUST BE KEPT SORTED IN strcmp() ORDER FOR BINARY SEARCH!
505 */
506static struct fst
507{
508 char *f_name; /* function name */
509 char f_min_argc; /* minimal number of arguments */
510 char f_max_argc; /* maximal number of arguments */
511 void (*f_func)(typval_T *args, typval_T *rvar);
512 /* implementation of function */
513} functions[] =
514{
515#ifdef FEAT_FLOAT
516 {"abs", 1, 1, f_abs},
517 {"acos", 1, 1, f_acos}, /* WJMc */
518#endif
519 {"add", 2, 2, f_add},
520 {"and", 2, 2, f_and},
521 {"append", 2, 2, f_append},
Bram Moolenaarca851592018-06-06 21:04:07 +0200522 {"appendbufline", 3, 3, f_appendbufline},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200523 {"argc", 0, 1, f_argc},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200524 {"argidx", 0, 0, f_argidx},
525 {"arglistid", 0, 2, f_arglistid},
Bram Moolenaare6e39892018-10-25 12:32:11 +0200526 {"argv", 0, 2, f_argv},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200527#ifdef FEAT_FLOAT
528 {"asin", 1, 1, f_asin}, /* WJMc */
529#endif
Bram Moolenaarb48e96f2018-02-13 12:26:14 +0100530 {"assert_beeps", 1, 2, f_assert_beeps},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200531 {"assert_equal", 2, 3, f_assert_equal},
Bram Moolenaard96ff162018-02-18 22:13:29 +0100532 {"assert_equalfile", 2, 2, f_assert_equalfile},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200533 {"assert_exception", 1, 2, f_assert_exception},
Bram Moolenaar1307d1c2018-10-07 20:16:49 +0200534 {"assert_fails", 1, 3, f_assert_fails},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200535 {"assert_false", 1, 2, f_assert_false},
Bram Moolenaar34215662016-12-04 13:37:41 +0100536 {"assert_inrange", 3, 4, f_assert_inrange},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200537 {"assert_match", 2, 3, f_assert_match},
538 {"assert_notequal", 2, 3, f_assert_notequal},
539 {"assert_notmatch", 2, 3, f_assert_notmatch},
Bram Moolenaar42205552017-03-18 19:42:22 +0100540 {"assert_report", 1, 1, f_assert_report},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200541 {"assert_true", 1, 2, f_assert_true},
542#ifdef FEAT_FLOAT
543 {"atan", 1, 1, f_atan},
544 {"atan2", 2, 2, f_atan2},
545#endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100546#ifdef FEAT_BEVAL
547 {"balloon_show", 1, 1, f_balloon_show},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100548# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +0100549 {"balloon_split", 1, 1, f_balloon_split},
Bram Moolenaar669a8282017-11-19 20:13:05 +0100550# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +0100551#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200552 {"browse", 4, 4, f_browse},
553 {"browsedir", 2, 2, f_browsedir},
554 {"bufexists", 1, 1, f_bufexists},
555 {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
556 {"buffer_name", 1, 1, f_bufname}, /* obsolete */
557 {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
558 {"buflisted", 1, 1, f_buflisted},
559 {"bufloaded", 1, 1, f_bufloaded},
560 {"bufname", 1, 1, f_bufname},
561 {"bufnr", 1, 2, f_bufnr},
562 {"bufwinid", 1, 1, f_bufwinid},
563 {"bufwinnr", 1, 1, f_bufwinnr},
564 {"byte2line", 1, 1, f_byte2line},
565 {"byteidx", 2, 2, f_byteidx},
566 {"byteidxcomp", 2, 2, f_byteidxcomp},
567 {"call", 2, 3, f_call},
568#ifdef FEAT_FLOAT
569 {"ceil", 1, 1, f_ceil},
570#endif
571#ifdef FEAT_JOB_CHANNEL
Bram Moolenaar4b785f62016-11-29 21:54:44 +0100572 {"ch_canread", 1, 1, f_ch_canread},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200573 {"ch_close", 1, 1, f_ch_close},
Bram Moolenaar0874a832016-09-01 15:11:51 +0200574 {"ch_close_in", 1, 1, f_ch_close_in},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200575 {"ch_evalexpr", 2, 3, f_ch_evalexpr},
576 {"ch_evalraw", 2, 3, f_ch_evalraw},
577 {"ch_getbufnr", 2, 2, f_ch_getbufnr},
578 {"ch_getjob", 1, 1, f_ch_getjob},
579 {"ch_info", 1, 1, f_ch_info},
580 {"ch_log", 1, 2, f_ch_log},
581 {"ch_logfile", 1, 2, f_ch_logfile},
582 {"ch_open", 1, 2, f_ch_open},
583 {"ch_read", 1, 2, f_ch_read},
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +0100584 {"ch_readblob", 1, 2, f_ch_readblob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200585 {"ch_readraw", 1, 2, f_ch_readraw},
586 {"ch_sendexpr", 2, 3, f_ch_sendexpr},
587 {"ch_sendraw", 2, 3, f_ch_sendraw},
588 {"ch_setoptions", 2, 2, f_ch_setoptions},
Bram Moolenaar7ef38102016-09-26 22:36:58 +0200589 {"ch_status", 1, 2, f_ch_status},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200590#endif
591 {"changenr", 0, 0, f_changenr},
592 {"char2nr", 1, 2, f_char2nr},
593 {"cindent", 1, 1, f_cindent},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100594 {"clearmatches", 0, 1, f_clearmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200595 {"col", 1, 1, f_col},
596#if defined(FEAT_INS_EXPAND)
597 {"complete", 2, 2, f_complete},
598 {"complete_add", 1, 1, f_complete_add},
599 {"complete_check", 0, 0, f_complete_check},
Bram Moolenaarfd133322019-03-29 12:20:27 +0100600 {"complete_info", 0, 1, f_complete_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200601#endif
602 {"confirm", 1, 4, f_confirm},
603 {"copy", 1, 1, f_copy},
604#ifdef FEAT_FLOAT
605 {"cos", 1, 1, f_cos},
606 {"cosh", 1, 1, f_cosh},
607#endif
608 {"count", 2, 4, f_count},
609 {"cscope_connection",0,3, f_cscope_connection},
610 {"cursor", 1, 3, f_cursor},
Bram Moolenaar4f974752019-02-17 17:44:42 +0100611#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +0200612 {"debugbreak", 1, 1, f_debugbreak},
613#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200614 {"deepcopy", 1, 2, f_deepcopy},
615 {"delete", 1, 2, f_delete},
Bram Moolenaard79a2622018-06-07 18:17:46 +0200616 {"deletebufline", 2, 3, f_deletebufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200617 {"did_filetype", 0, 0, f_did_filetype},
618 {"diff_filler", 1, 1, f_diff_filler},
619 {"diff_hlID", 2, 2, f_diff_hlID},
620 {"empty", 1, 1, f_empty},
621 {"escape", 2, 2, f_escape},
622 {"eval", 1, 1, f_eval},
623 {"eventhandler", 0, 0, f_eventhandler},
624 {"executable", 1, 1, f_executable},
625 {"execute", 1, 2, f_execute},
626 {"exepath", 1, 1, f_exepath},
627 {"exists", 1, 1, f_exists},
628#ifdef FEAT_FLOAT
629 {"exp", 1, 1, f_exp},
630#endif
631 {"expand", 1, 3, f_expand},
632 {"extend", 2, 3, f_extend},
633 {"feedkeys", 1, 2, f_feedkeys},
634 {"file_readable", 1, 1, f_filereadable}, /* obsolete */
635 {"filereadable", 1, 1, f_filereadable},
636 {"filewritable", 1, 1, f_filewritable},
637 {"filter", 2, 2, f_filter},
638 {"finddir", 1, 3, f_finddir},
639 {"findfile", 1, 3, f_findfile},
640#ifdef FEAT_FLOAT
641 {"float2nr", 1, 1, f_float2nr},
642 {"floor", 1, 1, f_floor},
643 {"fmod", 2, 2, f_fmod},
644#endif
645 {"fnameescape", 1, 1, f_fnameescape},
646 {"fnamemodify", 2, 2, f_fnamemodify},
647 {"foldclosed", 1, 1, f_foldclosed},
648 {"foldclosedend", 1, 1, f_foldclosedend},
649 {"foldlevel", 1, 1, f_foldlevel},
650 {"foldtext", 0, 0, f_foldtext},
651 {"foldtextresult", 1, 1, f_foldtextresult},
652 {"foreground", 0, 0, f_foreground},
Bram Moolenaar437bafe2016-08-01 15:40:54 +0200653 {"funcref", 1, 3, f_funcref},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200654 {"function", 1, 3, f_function},
655 {"garbagecollect", 0, 1, f_garbagecollect},
656 {"get", 2, 3, f_get},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200657 {"getbufinfo", 0, 1, f_getbufinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200658 {"getbufline", 2, 3, f_getbufline},
659 {"getbufvar", 2, 3, f_getbufvar},
Bram Moolenaar07ad8162018-02-13 13:59:59 +0100660 {"getchangelist", 1, 1, f_getchangelist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200661 {"getchar", 0, 1, f_getchar},
662 {"getcharmod", 0, 0, f_getcharmod},
663 {"getcharsearch", 0, 0, f_getcharsearch},
664 {"getcmdline", 0, 0, f_getcmdline},
665 {"getcmdpos", 0, 0, f_getcmdpos},
666 {"getcmdtype", 0, 0, f_getcmdtype},
667 {"getcmdwintype", 0, 0, f_getcmdwintype},
668#if defined(FEAT_CMDL_COMPL)
Bram Moolenaare9d58a62016-08-13 15:07:41 +0200669 {"getcompletion", 2, 3, f_getcompletion},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200670#endif
671 {"getcurpos", 0, 0, f_getcurpos},
672 {"getcwd", 0, 2, f_getcwd},
673 {"getfontname", 0, 1, f_getfontname},
674 {"getfperm", 1, 1, f_getfperm},
675 {"getfsize", 1, 1, f_getfsize},
676 {"getftime", 1, 1, f_getftime},
677 {"getftype", 1, 1, f_getftype},
Bram Moolenaar4f505882018-02-10 21:06:32 +0100678 {"getjumplist", 0, 2, f_getjumplist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200679 {"getline", 1, 2, f_getline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200680 {"getloclist", 1, 2, f_getloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100681 {"getmatches", 0, 1, f_getmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200682 {"getpid", 0, 0, f_getpid},
683 {"getpos", 1, 1, f_getpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200684 {"getqflist", 0, 1, f_getqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200685 {"getreg", 0, 3, f_getreg},
686 {"getregtype", 0, 1, f_getregtype},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200687 {"gettabinfo", 0, 1, f_gettabinfo},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200688 {"gettabvar", 2, 3, f_gettabvar},
689 {"gettabwinvar", 3, 4, f_gettabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100690 {"gettagstack", 0, 1, f_gettagstack},
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +0200691 {"getwininfo", 0, 1, f_getwininfo},
Bram Moolenaar3f54fd32018-03-03 21:29:55 +0100692 {"getwinpos", 0, 1, f_getwinpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200693 {"getwinposx", 0, 0, f_getwinposx},
694 {"getwinposy", 0, 0, f_getwinposy},
695 {"getwinvar", 2, 3, f_getwinvar},
696 {"glob", 1, 4, f_glob},
697 {"glob2regpat", 1, 1, f_glob2regpat},
698 {"globpath", 2, 5, f_globpath},
699 {"has", 1, 1, f_has},
700 {"has_key", 2, 2, f_has_key},
701 {"haslocaldir", 0, 2, f_haslocaldir},
702 {"hasmapto", 1, 3, f_hasmapto},
703 {"highlightID", 1, 1, f_hlID}, /* obsolete */
704 {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
705 {"histadd", 2, 2, f_histadd},
706 {"histdel", 1, 2, f_histdel},
707 {"histget", 1, 2, f_histget},
708 {"histnr", 1, 1, f_histnr},
709 {"hlID", 1, 1, f_hlID},
710 {"hlexists", 1, 1, f_hlexists},
711 {"hostname", 0, 0, f_hostname},
712 {"iconv", 3, 3, f_iconv},
713 {"indent", 1, 1, f_indent},
714 {"index", 2, 4, f_index},
715 {"input", 1, 3, f_input},
716 {"inputdialog", 1, 3, f_inputdialog},
717 {"inputlist", 1, 1, f_inputlist},
718 {"inputrestore", 0, 0, f_inputrestore},
719 {"inputsave", 0, 0, f_inputsave},
720 {"inputsecret", 1, 2, f_inputsecret},
721 {"insert", 2, 3, f_insert},
722 {"invert", 1, 1, f_invert},
723 {"isdirectory", 1, 1, f_isdirectory},
724 {"islocked", 1, 1, f_islocked},
725#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
726 {"isnan", 1, 1, f_isnan},
727#endif
728 {"items", 1, 1, f_items},
729#ifdef FEAT_JOB_CHANNEL
730 {"job_getchannel", 1, 1, f_job_getchannel},
Bram Moolenaare1fc5152018-04-21 19:49:08 +0200731 {"job_info", 0, 1, f_job_info},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200732 {"job_setoptions", 2, 2, f_job_setoptions},
733 {"job_start", 1, 2, f_job_start},
734 {"job_status", 1, 1, f_job_status},
735 {"job_stop", 1, 2, f_job_stop},
736#endif
737 {"join", 1, 2, f_join},
738 {"js_decode", 1, 1, f_js_decode},
739 {"js_encode", 1, 1, f_js_encode},
740 {"json_decode", 1, 1, f_json_decode},
741 {"json_encode", 1, 1, f_json_encode},
742 {"keys", 1, 1, f_keys},
743 {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
744 {"len", 1, 1, f_len},
745 {"libcall", 3, 3, f_libcall},
746 {"libcallnr", 3, 3, f_libcallnr},
747 {"line", 1, 1, f_line},
748 {"line2byte", 1, 1, f_line2byte},
749 {"lispindent", 1, 1, f_lispindent},
750 {"localtime", 0, 0, f_localtime},
751#ifdef FEAT_FLOAT
752 {"log", 1, 1, f_log},
753 {"log10", 1, 1, f_log10},
754#endif
755#ifdef FEAT_LUA
756 {"luaeval", 1, 2, f_luaeval},
757#endif
758 {"map", 2, 2, f_map},
759 {"maparg", 1, 4, f_maparg},
760 {"mapcheck", 1, 3, f_mapcheck},
761 {"match", 2, 4, f_match},
762 {"matchadd", 2, 5, f_matchadd},
763 {"matchaddpos", 2, 5, f_matchaddpos},
764 {"matcharg", 1, 1, f_matcharg},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100765 {"matchdelete", 1, 2, f_matchdelete},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200766 {"matchend", 2, 4, f_matchend},
767 {"matchlist", 2, 4, f_matchlist},
768 {"matchstr", 2, 4, f_matchstr},
769 {"matchstrpos", 2, 4, f_matchstrpos},
770 {"max", 1, 1, f_max},
771 {"min", 1, 1, f_min},
772#ifdef vim_mkdir
773 {"mkdir", 1, 3, f_mkdir},
774#endif
775 {"mode", 0, 1, f_mode},
776#ifdef FEAT_MZSCHEME
777 {"mzeval", 1, 1, f_mzeval},
778#endif
779 {"nextnonblank", 1, 1, f_nextnonblank},
780 {"nr2char", 1, 2, f_nr2char},
781 {"or", 2, 2, f_or},
782 {"pathshorten", 1, 1, f_pathshorten},
783#ifdef FEAT_PERL
784 {"perleval", 1, 1, f_perleval},
785#endif
786#ifdef FEAT_FLOAT
787 {"pow", 2, 2, f_pow},
788#endif
789 {"prevnonblank", 1, 1, f_prevnonblank},
Bram Moolenaarc71807d2018-03-03 15:06:52 +0100790 {"printf", 1, 19, f_printf},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200791#ifdef FEAT_JOB_CHANNEL
792 {"prompt_setcallback", 2, 2, f_prompt_setcallback},
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200793 {"prompt_setinterrupt", 2, 2, f_prompt_setinterrupt},
Bram Moolenaarf2732452018-06-03 14:47:35 +0200794 {"prompt_setprompt", 2, 2, f_prompt_setprompt},
795#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100796#ifdef FEAT_TEXT_PROP
797 {"prop_add", 3, 3, f_prop_add},
798 {"prop_clear", 1, 3, f_prop_clear},
799 {"prop_list", 1, 2, f_prop_list},
Bram Moolenaar0a2f5782019-03-22 13:20:43 +0100800 {"prop_remove", 1, 3, f_prop_remove},
Bram Moolenaar98aefe72018-12-13 22:20:09 +0100801 {"prop_type_add", 2, 2, f_prop_type_add},
802 {"prop_type_change", 2, 2, f_prop_type_change},
803 {"prop_type_delete", 1, 2, f_prop_type_delete},
804 {"prop_type_get", 1, 2, f_prop_type_get},
805 {"prop_type_list", 0, 1, f_prop_type_list},
806#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200807 {"pumvisible", 0, 0, f_pumvisible},
808#ifdef FEAT_PYTHON3
809 {"py3eval", 1, 1, f_py3eval},
810#endif
811#ifdef FEAT_PYTHON
812 {"pyeval", 1, 1, f_pyeval},
813#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +0100814#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
815 {"pyxeval", 1, 1, f_pyxeval},
816#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200817 {"range", 1, 3, f_range},
818 {"readfile", 1, 3, f_readfile},
Bram Moolenaar0b6d9112018-05-22 20:35:17 +0200819 {"reg_executing", 0, 0, f_reg_executing},
820 {"reg_recording", 0, 0, f_reg_recording},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200821 {"reltime", 0, 2, f_reltime},
822#ifdef FEAT_FLOAT
823 {"reltimefloat", 1, 1, f_reltimefloat},
824#endif
825 {"reltimestr", 1, 1, f_reltimestr},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100826 {"remote_expr", 2, 4, f_remote_expr},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200827 {"remote_foreground", 1, 1, f_remote_foreground},
828 {"remote_peek", 1, 2, f_remote_peek},
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +0100829 {"remote_read", 1, 2, f_remote_read},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200830 {"remote_send", 2, 3, f_remote_send},
Bram Moolenaar7416f3e2017-03-18 18:10:13 +0100831 {"remote_startserver", 1, 1, f_remote_startserver},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200832 {"remove", 2, 3, f_remove},
833 {"rename", 2, 2, f_rename},
834 {"repeat", 2, 2, f_repeat},
835 {"resolve", 1, 1, f_resolve},
836 {"reverse", 1, 1, f_reverse},
837#ifdef FEAT_FLOAT
838 {"round", 1, 1, f_round},
839#endif
Bram Moolenaare99be0e2019-03-26 22:51:09 +0100840#ifdef FEAT_RUBY
841 {"rubyeval", 1, 1, f_rubyeval},
842#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200843 {"screenattr", 2, 2, f_screenattr},
844 {"screenchar", 2, 2, f_screenchar},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100845 {"screenchars", 2, 2, f_screenchars},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200846 {"screencol", 0, 0, f_screencol},
847 {"screenrow", 0, 0, f_screenrow},
Bram Moolenaar2912abb2019-03-29 14:16:42 +0100848 {"screenstring", 2, 2, f_screenstring},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200849 {"search", 1, 4, f_search},
850 {"searchdecl", 1, 3, f_searchdecl},
851 {"searchpair", 3, 7, f_searchpair},
852 {"searchpairpos", 3, 7, f_searchpairpos},
853 {"searchpos", 1, 4, f_searchpos},
854 {"server2client", 2, 2, f_server2client},
855 {"serverlist", 0, 0, f_serverlist},
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +0200856 {"setbufline", 3, 3, f_setbufline},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200857 {"setbufvar", 3, 3, f_setbufvar},
858 {"setcharsearch", 1, 1, f_setcharsearch},
859 {"setcmdpos", 1, 1, f_setcmdpos},
860 {"setfperm", 2, 2, f_setfperm},
861 {"setline", 2, 2, f_setline},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200862 {"setloclist", 2, 4, f_setloclist},
Bram Moolenaaraff74912019-03-30 18:11:49 +0100863 {"setmatches", 1, 2, f_setmatches},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200864 {"setpos", 2, 2, f_setpos},
Bram Moolenaard823fa92016-08-12 16:29:27 +0200865 {"setqflist", 1, 3, f_setqflist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200866 {"setreg", 2, 3, f_setreg},
867 {"settabvar", 3, 3, f_settabvar},
868 {"settabwinvar", 4, 4, f_settabwinvar},
Bram Moolenaarf49cc602018-11-11 15:21:05 +0100869 {"settagstack", 2, 3, f_settagstack},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200870 {"setwinvar", 3, 3, f_setwinvar},
871#ifdef FEAT_CRYPT
872 {"sha256", 1, 1, f_sha256},
873#endif
874 {"shellescape", 1, 2, f_shellescape},
Bram Moolenaarf9514162018-11-22 03:08:29 +0100875 {"shiftwidth", 0, 1, f_shiftwidth},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100876#ifdef FEAT_SIGNS
877 {"sign_define", 1, 2, f_sign_define},
878 {"sign_getdefined", 0, 1, f_sign_getdefined},
879 {"sign_getplaced", 0, 2, f_sign_getplaced},
Bram Moolenaar6b7b7192019-01-11 13:42:41 +0100880 {"sign_jump", 3, 3, f_sign_jump},
Bram Moolenaar162b7142018-12-21 15:17:36 +0100881 {"sign_place", 4, 5, f_sign_place},
882 {"sign_undefine", 0, 1, f_sign_undefine},
883 {"sign_unplace", 1, 2, f_sign_unplace},
884#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200885 {"simplify", 1, 1, f_simplify},
886#ifdef FEAT_FLOAT
887 {"sin", 1, 1, f_sin},
888 {"sinh", 1, 1, f_sinh},
889#endif
890 {"sort", 1, 3, f_sort},
891 {"soundfold", 1, 1, f_soundfold},
892 {"spellbadword", 0, 1, f_spellbadword},
893 {"spellsuggest", 1, 3, f_spellsuggest},
894 {"split", 1, 3, f_split},
895#ifdef FEAT_FLOAT
896 {"sqrt", 1, 1, f_sqrt},
897 {"str2float", 1, 1, f_str2float},
898#endif
899 {"str2nr", 1, 2, f_str2nr},
900 {"strcharpart", 2, 3, f_strcharpart},
901 {"strchars", 1, 2, f_strchars},
902 {"strdisplaywidth", 1, 2, f_strdisplaywidth},
903#ifdef HAVE_STRFTIME
904 {"strftime", 1, 2, f_strftime},
905#endif
906 {"strgetchar", 2, 2, f_strgetchar},
907 {"stridx", 2, 3, f_stridx},
908 {"string", 1, 1, f_string},
909 {"strlen", 1, 1, f_strlen},
910 {"strpart", 2, 3, f_strpart},
911 {"strridx", 2, 3, f_strridx},
912 {"strtrans", 1, 1, f_strtrans},
913 {"strwidth", 1, 1, f_strwidth},
914 {"submatch", 1, 2, f_submatch},
915 {"substitute", 4, 4, f_substitute},
Bram Moolenaar00f123a2018-08-21 20:28:54 +0200916 {"swapinfo", 1, 1, f_swapinfo},
Bram Moolenaar110bd602018-09-16 18:46:59 +0200917 {"swapname", 1, 1, f_swapname},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200918 {"synID", 3, 3, f_synID},
919 {"synIDattr", 2, 3, f_synIDattr},
920 {"synIDtrans", 1, 1, f_synIDtrans},
921 {"synconcealed", 2, 2, f_synconcealed},
922 {"synstack", 2, 2, f_synstack},
923 {"system", 1, 2, f_system},
924 {"systemlist", 1, 2, f_systemlist},
925 {"tabpagebuflist", 0, 1, f_tabpagebuflist},
926 {"tabpagenr", 0, 1, f_tabpagenr},
927 {"tabpagewinnr", 1, 2, f_tabpagewinnr},
928 {"tagfiles", 0, 0, f_tagfiles},
Bram Moolenaarc6aafba2017-03-21 17:09:10 +0100929 {"taglist", 1, 2, f_taglist},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200930#ifdef FEAT_FLOAT
931 {"tan", 1, 1, f_tan},
932 {"tanh", 1, 1, f_tanh},
933#endif
934 {"tempname", 0, 0, f_tempname},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200935#ifdef FEAT_TERMINAL
Bram Moolenaard96ff162018-02-18 22:13:29 +0100936 {"term_dumpdiff", 2, 3, f_term_dumpdiff},
937 {"term_dumpload", 1, 2, f_term_dumpload},
Bram Moolenaarcafafb32018-02-22 21:07:09 +0100938 {"term_dumpwrite", 2, 3, f_term_dumpwrite},
Bram Moolenaare41e3b42017-08-11 16:24:50 +0200939 {"term_getaltscreen", 1, 1, f_term_getaltscreen},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200940# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
941 {"term_getansicolors", 1, 1, f_term_getansicolors},
942# endif
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200943 {"term_getattr", 2, 2, f_term_getattr},
Bram Moolenaar97870002017-07-30 18:28:38 +0200944 {"term_getcursor", 1, 1, f_term_getcursor},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200945 {"term_getjob", 1, 1, f_term_getjob},
Bram Moolenaar45356542017-08-06 17:53:31 +0200946 {"term_getline", 2, 2, f_term_getline},
Bram Moolenaar82b9ca02017-08-08 23:06:46 +0200947 {"term_getscrolled", 1, 1, f_term_getscrolled},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200948 {"term_getsize", 1, 1, f_term_getsize},
Bram Moolenaarb000e322017-07-30 19:38:21 +0200949 {"term_getstatus", 1, 1, f_term_getstatus},
950 {"term_gettitle", 1, 1, f_term_gettitle},
Bram Moolenaar2dc9d262017-09-08 14:39:30 +0200951 {"term_gettty", 1, 2, f_term_gettty},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200952 {"term_list", 0, 0, f_term_list},
Bram Moolenaar45356542017-08-06 17:53:31 +0200953 {"term_scrape", 2, 2, f_term_scrape},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200954 {"term_sendkeys", 2, 2, f_term_sendkeys},
Bram Moolenaarf59c6e82018-04-10 15:59:11 +0200955# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
956 {"term_setansicolors", 2, 2, f_term_setansicolors},
957# endif
Bram Moolenaar25cdd9c2018-03-10 20:28:12 +0100958 {"term_setkill", 2, 2, f_term_setkill},
Bram Moolenaar4d8bac82018-03-09 21:33:34 +0100959 {"term_setrestore", 2, 2, f_term_setrestore},
Bram Moolenaara42d3632018-04-14 17:05:38 +0200960 {"term_setsize", 3, 3, f_term_setsize},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200961 {"term_start", 1, 2, f_term_start},
Bram Moolenaarf3402b12017-08-06 19:07:08 +0200962 {"term_wait", 1, 2, f_term_wait},
Bram Moolenaarc6df10e2017-07-29 20:15:08 +0200963#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200964 {"test_alloc_fail", 3, 3, f_test_alloc_fail},
965 {"test_autochdir", 0, 0, f_test_autochdir},
Bram Moolenaar5e80de32017-09-03 15:48:12 +0200966 {"test_feedinput", 1, 1, f_test_feedinput},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200967 {"test_garbagecollect_now", 0, 0, f_test_garbagecollect_now},
Bram Moolenaare0c31f62017-03-01 15:07:05 +0100968 {"test_ignore_error", 1, 1, f_test_ignore_error},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100969 {"test_null_blob", 0, 0, f_test_null_blob},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200970#ifdef FEAT_JOB_CHANNEL
971 {"test_null_channel", 0, 0, f_test_null_channel},
972#endif
973 {"test_null_dict", 0, 0, f_test_null_dict},
974#ifdef FEAT_JOB_CHANNEL
975 {"test_null_job", 0, 0, f_test_null_job},
976#endif
977 {"test_null_list", 0, 0, f_test_null_list},
978 {"test_null_partial", 0, 0, f_test_null_partial},
979 {"test_null_string", 0, 0, f_test_null_string},
Bram Moolenaarfe8ef982018-09-13 20:31:54 +0200980 {"test_option_not_set", 1, 1, f_test_option_not_set},
Bram Moolenaarc3e92c12019-03-23 14:23:07 +0100981 {"test_override", 2, 2, f_test_override},
982 {"test_refcount", 1, 1, f_test_refcount},
Bram Moolenaarab186732018-09-14 21:27:06 +0200983#ifdef FEAT_GUI
984 {"test_scrollbar", 3, 3, f_test_scrollbar},
985#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200986 {"test_settime", 1, 1, f_test_settime},
987#ifdef FEAT_TIMERS
Bram Moolenaar8e97bd72016-08-06 22:05:07 +0200988 {"timer_info", 0, 1, f_timer_info},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200989 {"timer_pause", 2, 2, f_timer_pause},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200990 {"timer_start", 2, 3, f_timer_start},
991 {"timer_stop", 1, 1, f_timer_stop},
Bram Moolenaarb73598e2016-08-07 18:22:53 +0200992 {"timer_stopall", 0, 0, f_timer_stopall},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200993#endif
994 {"tolower", 1, 1, f_tolower},
995 {"toupper", 1, 1, f_toupper},
996 {"tr", 3, 3, f_tr},
Bram Moolenaar295ac5a2018-03-22 23:04:02 +0100997 {"trim", 1, 2, f_trim},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +0200998#ifdef FEAT_FLOAT
999 {"trunc", 1, 1, f_trunc},
1000#endif
1001 {"type", 1, 1, f_type},
1002 {"undofile", 1, 1, f_undofile},
1003 {"undotree", 0, 0, f_undotree},
1004 {"uniq", 1, 3, f_uniq},
1005 {"values", 1, 1, f_values},
1006 {"virtcol", 1, 1, f_virtcol},
1007 {"visualmode", 0, 1, f_visualmode},
1008 {"wildmenumode", 0, 0, f_wildmenumode},
1009 {"win_findbuf", 1, 1, f_win_findbuf},
1010 {"win_getid", 0, 2, f_win_getid},
1011 {"win_gotoid", 1, 1, f_win_gotoid},
1012 {"win_id2tabwin", 1, 1, f_win_id2tabwin},
1013 {"win_id2win", 1, 1, f_win_id2win},
Bram Moolenaar22044dc2017-12-02 15:43:37 +01001014 {"win_screenpos", 1, 1, f_win_screenpos},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001015 {"winbufnr", 1, 1, f_winbufnr},
1016 {"wincol", 0, 0, f_wincol},
1017 {"winheight", 1, 1, f_winheight},
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +02001018 {"winlayout", 0, 1, f_winlayout},
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001019 {"winline", 0, 0, f_winline},
1020 {"winnr", 0, 1, f_winnr},
1021 {"winrestcmd", 0, 0, f_winrestcmd},
1022 {"winrestview", 1, 1, f_winrestview},
1023 {"winsaveview", 0, 0, f_winsaveview},
1024 {"winwidth", 1, 1, f_winwidth},
1025 {"wordcount", 0, 0, f_wordcount},
1026 {"writefile", 2, 3, f_writefile},
1027 {"xor", 2, 2, f_xor},
1028};
1029
1030#if defined(FEAT_CMDL_COMPL) || defined(PROTO)
1031
1032/*
1033 * Function given to ExpandGeneric() to obtain the list of internal
1034 * or user defined function names.
1035 */
1036 char_u *
1037get_function_name(expand_T *xp, int idx)
1038{
1039 static int intidx = -1;
1040 char_u *name;
1041
1042 if (idx == 0)
1043 intidx = -1;
1044 if (intidx < 0)
1045 {
1046 name = get_user_func_name(xp, idx);
1047 if (name != NULL)
1048 return name;
1049 }
1050 if (++intidx < (int)(sizeof(functions) / sizeof(struct fst)))
1051 {
1052 STRCPY(IObuff, functions[intidx].f_name);
1053 STRCAT(IObuff, "(");
1054 if (functions[intidx].f_max_argc == 0)
1055 STRCAT(IObuff, ")");
1056 return IObuff;
1057 }
1058
1059 return NULL;
1060}
1061
1062/*
1063 * Function given to ExpandGeneric() to obtain the list of internal or
1064 * user defined variable or function names.
1065 */
1066 char_u *
1067get_expr_name(expand_T *xp, int idx)
1068{
1069 static int intidx = -1;
1070 char_u *name;
1071
1072 if (idx == 0)
1073 intidx = -1;
1074 if (intidx < 0)
1075 {
1076 name = get_function_name(xp, idx);
1077 if (name != NULL)
1078 return name;
1079 }
1080 return get_user_var_name(xp, ++intidx);
1081}
1082
1083#endif /* FEAT_CMDL_COMPL */
1084
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001085/*
1086 * Find internal function in table above.
1087 * Return index, or -1 if not found
1088 */
1089 int
1090find_internal_func(
1091 char_u *name) /* name of the function */
1092{
1093 int first = 0;
1094 int last = (int)(sizeof(functions) / sizeof(struct fst)) - 1;
1095 int cmp;
1096 int x;
1097
1098 /*
1099 * Find the function name in the table. Binary search.
1100 */
1101 while (first <= last)
1102 {
1103 x = first + ((unsigned)(last - first) >> 1);
1104 cmp = STRCMP(name, functions[x].f_name);
1105 if (cmp < 0)
1106 last = x - 1;
1107 else if (cmp > 0)
1108 first = x + 1;
1109 else
1110 return x;
1111 }
1112 return -1;
1113}
1114
1115 int
1116call_internal_func(
1117 char_u *name,
1118 int argcount,
1119 typval_T *argvars,
1120 typval_T *rettv)
1121{
1122 int i;
1123
1124 i = find_internal_func(name);
1125 if (i < 0)
1126 return ERROR_UNKNOWN;
1127 if (argcount < functions[i].f_min_argc)
1128 return ERROR_TOOFEW;
1129 if (argcount > functions[i].f_max_argc)
1130 return ERROR_TOOMANY;
1131 argvars[argcount].v_type = VAR_UNKNOWN;
1132 functions[i].f_func(argvars, rettv);
1133 return ERROR_NONE;
1134}
1135
1136/*
1137 * Return TRUE for a non-zero Number and a non-empty String.
1138 */
1139 static int
1140non_zero_arg(typval_T *argvars)
1141{
1142 return ((argvars[0].v_type == VAR_NUMBER
1143 && argvars[0].vval.v_number != 0)
1144 || (argvars[0].v_type == VAR_SPECIAL
1145 && argvars[0].vval.v_number == VVAL_TRUE)
1146 || (argvars[0].v_type == VAR_STRING
1147 && argvars[0].vval.v_string != NULL
1148 && *argvars[0].vval.v_string != NUL));
1149}
1150
1151/*
1152 * Get the lnum from the first argument.
1153 * Also accepts ".", "$", etc., but that only works for the current buffer.
1154 * Returns -1 on error.
1155 */
1156 static linenr_T
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001157tv_get_lnum(typval_T *argvars)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001158{
1159 typval_T rettv;
1160 linenr_T lnum;
1161
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001162 lnum = (linenr_T)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001163 if (lnum == 0) /* no valid number, try using line() */
1164 {
1165 rettv.v_type = VAR_NUMBER;
1166 f_line(argvars, &rettv);
1167 lnum = (linenr_T)rettv.vval.v_number;
1168 clear_tv(&rettv);
1169 }
1170 return lnum;
1171}
1172
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001173/*
1174 * Get the lnum from the first argument.
1175 * Also accepts "$", then "buf" is used.
1176 * Returns 0 on error.
1177 */
1178 static linenr_T
1179tv_get_lnum_buf(typval_T *argvars, buf_T *buf)
1180{
1181 if (argvars[0].v_type == VAR_STRING
1182 && argvars[0].vval.v_string != NULL
1183 && argvars[0].vval.v_string[0] == '$'
1184 && buf != NULL)
1185 return buf->b_ml.ml_line_count;
1186 return (linenr_T)tv_get_number_chk(&argvars[0], NULL);
1187}
1188
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001189#ifdef FEAT_FLOAT
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001190/*
1191 * Get the float value of "argvars[0]" into "f".
1192 * Returns FAIL when the argument is not a Number or Float.
1193 */
1194 static int
1195get_float_arg(typval_T *argvars, float_T *f)
1196{
1197 if (argvars[0].v_type == VAR_FLOAT)
1198 {
1199 *f = argvars[0].vval.v_float;
1200 return OK;
1201 }
1202 if (argvars[0].v_type == VAR_NUMBER)
1203 {
1204 *f = (float_T)argvars[0].vval.v_number;
1205 return OK;
1206 }
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001207 emsg(_("E808: Number or Float required"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001208 return FAIL;
1209}
1210
1211/*
1212 * "abs(expr)" function
1213 */
1214 static void
1215f_abs(typval_T *argvars, typval_T *rettv)
1216{
1217 if (argvars[0].v_type == VAR_FLOAT)
1218 {
1219 rettv->v_type = VAR_FLOAT;
1220 rettv->vval.v_float = fabs(argvars[0].vval.v_float);
1221 }
1222 else
1223 {
1224 varnumber_T n;
1225 int error = FALSE;
1226
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001227 n = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001228 if (error)
1229 rettv->vval.v_number = -1;
1230 else if (n > 0)
1231 rettv->vval.v_number = n;
1232 else
1233 rettv->vval.v_number = -n;
1234 }
1235}
1236
1237/*
1238 * "acos()" function
1239 */
1240 static void
1241f_acos(typval_T *argvars, typval_T *rettv)
1242{
1243 float_T f = 0.0;
1244
1245 rettv->v_type = VAR_FLOAT;
1246 if (get_float_arg(argvars, &f) == OK)
1247 rettv->vval.v_float = acos(f);
1248 else
1249 rettv->vval.v_float = 0.0;
1250}
1251#endif
1252
1253/*
1254 * "add(list, item)" function
1255 */
1256 static void
1257f_add(typval_T *argvars, typval_T *rettv)
1258{
1259 list_T *l;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001260 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001261
1262 rettv->vval.v_number = 1; /* Default: Failed */
1263 if (argvars[0].v_type == VAR_LIST)
1264 {
1265 if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001266 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001267 (char_u *)N_("add() argument"), TRUE)
1268 && list_append_tv(l, &argvars[1]) == OK)
1269 copy_tv(&argvars[0], rettv);
1270 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001271 else if (argvars[0].v_type == VAR_BLOB)
1272 {
1273 if ((b = argvars[0].vval.v_blob) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01001274 && !var_check_lock(b->bv_lock,
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001275 (char_u *)N_("add() argument"), TRUE))
1276 {
Bram Moolenaar05500ec2019-01-13 19:10:33 +01001277 int error = FALSE;
1278 varnumber_T n = tv_get_number_chk(&argvars[1], &error);
1279
1280 if (!error)
1281 {
1282 ga_append(&b->bv_ga, (int)n);
1283 copy_tv(&argvars[0], rettv);
1284 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01001285 }
1286 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001287 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01001288 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001289}
1290
1291/*
1292 * "and(expr, expr)" function
1293 */
1294 static void
1295f_and(typval_T *argvars, typval_T *rettv)
1296{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001297 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
1298 & tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaarca851592018-06-06 21:04:07 +02001299}
1300
1301/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02001302 * If there is a window for "curbuf", make it the current window.
1303 */
1304 static void
1305find_win_for_curbuf(void)
1306{
1307 wininfo_T *wip;
1308
1309 for (wip = curbuf->b_wininfo; wip != NULL; wip = wip->wi_next)
1310 {
1311 if (wip->wi_win != NULL)
1312 {
1313 curwin = wip->wi_win;
1314 break;
1315 }
1316 }
1317}
1318
1319/*
Bram Moolenaarca851592018-06-06 21:04:07 +02001320 * Set line or list of lines in buffer "buf".
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001321 */
1322 static void
Bram Moolenaarca851592018-06-06 21:04:07 +02001323set_buffer_lines(
1324 buf_T *buf,
1325 linenr_T lnum_arg,
1326 int append,
1327 typval_T *lines,
1328 typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001329{
Bram Moolenaarca851592018-06-06 21:04:07 +02001330 linenr_T lnum = lnum_arg + (append ? 1 : 0);
1331 char_u *line = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001332 list_T *l = NULL;
1333 listitem_T *li = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001334 long added = 0;
Bram Moolenaarca851592018-06-06 21:04:07 +02001335 linenr_T append_lnum;
1336 buf_T *curbuf_save = NULL;
1337 win_T *curwin_save = NULL;
1338 int is_curbuf = buf == curbuf;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001339
Bram Moolenaarca851592018-06-06 21:04:07 +02001340 /* When using the current buffer ml_mfp will be set if needed. Useful when
1341 * setline() is used on startup. For other buffers the buffer must be
1342 * loaded. */
1343 if (buf == NULL || (!is_curbuf && buf->b_ml.ml_mfp == NULL) || lnum < 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001344 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001345 rettv->vval.v_number = 1; /* FAIL */
1346 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001347 }
1348
Bram Moolenaarca851592018-06-06 21:04:07 +02001349 if (!is_curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001350 {
Bram Moolenaarca851592018-06-06 21:04:07 +02001351 curbuf_save = curbuf;
1352 curwin_save = curwin;
1353 curbuf = buf;
Bram Moolenaard79a2622018-06-07 18:17:46 +02001354 find_win_for_curbuf();
Bram Moolenaarca851592018-06-06 21:04:07 +02001355 }
1356
1357 if (append)
1358 // appendbufline() uses the line number below which we insert
1359 append_lnum = lnum - 1;
1360 else
1361 // setbufline() uses the line number above which we insert, we only
1362 // append if it's below the last line
1363 append_lnum = curbuf->b_ml.ml_line_count;
1364
1365 if (lines->v_type == VAR_LIST)
1366 {
1367 l = lines->vval.v_list;
1368 li = l->lv_first;
1369 }
1370 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001371 line = tv_get_string_chk(lines);
Bram Moolenaarca851592018-06-06 21:04:07 +02001372
1373 /* default result is zero == OK */
1374 for (;;)
1375 {
1376 if (l != NULL)
1377 {
1378 /* list argument, get next string */
1379 if (li == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001380 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001381 line = tv_get_string_chk(&li->li_tv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001382 li = li->li_next;
1383 }
1384
Bram Moolenaarca851592018-06-06 21:04:07 +02001385 rettv->vval.v_number = 1; /* FAIL */
1386 if (line == NULL || lnum > curbuf->b_ml.ml_line_count + 1)
1387 break;
1388
1389 /* When coming here from Insert mode, sync undo, so that this can be
1390 * undone separately from what was previously inserted. */
1391 if (u_sync_once == 2)
1392 {
1393 u_sync_once = 1; /* notify that u_sync() was called */
1394 u_sync(TRUE);
1395 }
1396
1397 if (!append && lnum <= curbuf->b_ml.ml_line_count)
1398 {
Bram Moolenaar21b50382019-01-04 18:07:24 +01001399 // Existing line, replace it.
1400 // Removes any existing text properties.
1401 if (u_savesub(lnum) == OK && ml_replace_len(
1402 lnum, line, (colnr_T)STRLEN(line) + 1, TRUE, TRUE) == OK)
Bram Moolenaarca851592018-06-06 21:04:07 +02001403 {
1404 changed_bytes(lnum, 0);
1405 if (is_curbuf && lnum == curwin->w_cursor.lnum)
1406 check_cursor_col();
1407 rettv->vval.v_number = 0; /* OK */
1408 }
1409 }
1410 else if (added > 0 || u_save(lnum - 1, lnum) == OK)
1411 {
1412 /* append the line */
1413 ++added;
1414 if (ml_append(lnum - 1, line, (colnr_T)0, FALSE) == OK)
1415 rettv->vval.v_number = 0; /* OK */
1416 }
1417
1418 if (l == NULL) /* only one string argument */
1419 break;
1420 ++lnum;
1421 }
1422
1423 if (added > 0)
1424 {
1425 win_T *wp;
1426 tabpage_T *tp;
1427
1428 appended_lines_mark(append_lnum, added);
1429 FOR_ALL_TAB_WINDOWS(tp, wp)
1430 if (wp->w_buffer == buf && wp->w_cursor.lnum > append_lnum)
1431 wp->w_cursor.lnum += added;
1432 check_cursor_col();
1433
Bram Moolenaarf2732452018-06-03 14:47:35 +02001434#ifdef FEAT_JOB_CHANNEL
1435 if (bt_prompt(curbuf) && (State & INSERT))
1436 // show the line with the prompt
1437 update_topline();
1438#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001439 }
Bram Moolenaarca851592018-06-06 21:04:07 +02001440
1441 if (!is_curbuf)
1442 {
1443 curbuf = curbuf_save;
1444 curwin = curwin_save;
1445 }
1446}
1447
1448/*
1449 * "append(lnum, string/list)" function
1450 */
1451 static void
1452f_append(typval_T *argvars, typval_T *rettv)
1453{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001454 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaarca851592018-06-06 21:04:07 +02001455
1456 set_buffer_lines(curbuf, lnum, TRUE, &argvars[1], rettv);
1457}
1458
1459/*
1460 * "appendbufline(buf, lnum, string/list)" function
1461 */
1462 static void
1463f_appendbufline(typval_T *argvars, typval_T *rettv)
1464{
1465 linenr_T lnum;
1466 buf_T *buf;
1467
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001468 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarca851592018-06-06 21:04:07 +02001469 if (buf == NULL)
1470 rettv->vval.v_number = 1; /* FAIL */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001471 else
Bram Moolenaarca851592018-06-06 21:04:07 +02001472 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001473 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +02001474 set_buffer_lines(buf, lnum, TRUE, &argvars[2], rettv);
1475 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001476}
1477
1478/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001479 * "argc([window id])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001480 */
1481 static void
Bram Moolenaare6e39892018-10-25 12:32:11 +02001482f_argc(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001483{
Bram Moolenaare6e39892018-10-25 12:32:11 +02001484 win_T *wp;
1485
1486 if (argvars[0].v_type == VAR_UNKNOWN)
1487 // use the current window
1488 rettv->vval.v_number = ARGCOUNT;
1489 else if (argvars[0].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001490 && tv_get_number(&argvars[0]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001491 // use the global argument list
1492 rettv->vval.v_number = GARGCOUNT;
1493 else
1494 {
1495 // use the argument list of the specified window
1496 wp = find_win_by_nr_or_id(&argvars[0]);
1497 if (wp != NULL)
1498 rettv->vval.v_number = WARGCOUNT(wp);
1499 else
1500 rettv->vval.v_number = -1;
1501 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001502}
1503
1504/*
1505 * "argidx()" function
1506 */
1507 static void
1508f_argidx(typval_T *argvars UNUSED, typval_T *rettv)
1509{
1510 rettv->vval.v_number = curwin->w_arg_idx;
1511}
1512
1513/*
1514 * "arglistid()" function
1515 */
1516 static void
1517f_arglistid(typval_T *argvars, typval_T *rettv)
1518{
1519 win_T *wp;
1520
1521 rettv->vval.v_number = -1;
1522 wp = find_tabwin(&argvars[0], &argvars[1]);
1523 if (wp != NULL)
1524 rettv->vval.v_number = wp->w_alist->id;
1525}
1526
1527/*
Bram Moolenaare6e39892018-10-25 12:32:11 +02001528 * Get the argument list for a given window
1529 */
1530 static void
1531get_arglist_as_rettv(aentry_T *arglist, int argcount, typval_T *rettv)
1532{
1533 int idx;
1534
1535 if (rettv_list_alloc(rettv) == OK && arglist != NULL)
1536 for (idx = 0; idx < argcount; ++idx)
1537 list_append_string(rettv->vval.v_list,
1538 alist_name(&arglist[idx]), -1);
1539}
1540
1541/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001542 * "argv(nr)" function
1543 */
1544 static void
1545f_argv(typval_T *argvars, typval_T *rettv)
1546{
1547 int idx;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001548 aentry_T *arglist = NULL;
1549 int argcount = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001550
1551 if (argvars[0].v_type != VAR_UNKNOWN)
1552 {
Bram Moolenaare6e39892018-10-25 12:32:11 +02001553 if (argvars[1].v_type == VAR_UNKNOWN)
1554 {
1555 arglist = ARGLIST;
1556 argcount = ARGCOUNT;
1557 }
1558 else if (argvars[1].v_type == VAR_NUMBER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001559 && tv_get_number(&argvars[1]) == -1)
Bram Moolenaare6e39892018-10-25 12:32:11 +02001560 {
1561 arglist = GARGLIST;
1562 argcount = GARGCOUNT;
1563 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001564 else
Bram Moolenaare6e39892018-10-25 12:32:11 +02001565 {
1566 win_T *wp = find_win_by_nr_or_id(&argvars[1]);
1567
1568 if (wp != NULL)
1569 {
1570 /* Use the argument list of the specified window */
1571 arglist = WARGLIST(wp);
1572 argcount = WARGCOUNT(wp);
1573 }
1574 }
1575
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001576 rettv->v_type = VAR_STRING;
Bram Moolenaare6e39892018-10-25 12:32:11 +02001577 rettv->vval.v_string = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001578 idx = tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaare6e39892018-10-25 12:32:11 +02001579 if (arglist != NULL && idx >= 0 && idx < argcount)
1580 rettv->vval.v_string = vim_strsave(alist_name(&arglist[idx]));
1581 else if (idx == -1)
1582 get_arglist_as_rettv(arglist, argcount, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001583 }
Bram Moolenaare6e39892018-10-25 12:32:11 +02001584 else
1585 get_arglist_as_rettv(ARGLIST, ARGCOUNT, rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001586}
1587
1588/*
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001589 * "assert_beeps(cmd [, error])" function
1590 */
1591 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001592f_assert_beeps(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001593{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001594 rettv->vval.v_number = assert_beeps(argvars);
Bram Moolenaarb48e96f2018-02-13 12:26:14 +01001595}
1596
1597/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001598 * "assert_equal(expected, actual[, msg])" function
1599 */
1600 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001601f_assert_equal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001602{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001603 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_EQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001604}
1605
1606/*
Bram Moolenaard96ff162018-02-18 22:13:29 +01001607 * "assert_equalfile(fname-one, fname-two)" function
1608 */
1609 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001610f_assert_equalfile(typval_T *argvars, typval_T *rettv)
Bram Moolenaard96ff162018-02-18 22:13:29 +01001611{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001612 rettv->vval.v_number = assert_equalfile(argvars);
Bram Moolenaard96ff162018-02-18 22:13:29 +01001613}
1614
1615/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001616 * "assert_notequal(expected, actual[, msg])" function
1617 */
1618 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001619f_assert_notequal(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001620{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001621 rettv->vval.v_number = assert_equal_common(argvars, ASSERT_NOTEQUAL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001622}
1623
1624/*
1625 * "assert_exception(string[, msg])" function
1626 */
1627 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001628f_assert_exception(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001629{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001630 rettv->vval.v_number = assert_exception(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001631}
1632
1633/*
Bram Moolenaar1307d1c2018-10-07 20:16:49 +02001634 * "assert_fails(cmd [, error[, msg]])" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001635 */
1636 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001637f_assert_fails(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001638{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001639 rettv->vval.v_number = assert_fails(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001640}
1641
1642/*
1643 * "assert_false(actual[, msg])" function
1644 */
1645 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001646f_assert_false(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001647{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001648 rettv->vval.v_number = assert_bool(argvars, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001649}
1650
1651/*
Bram Moolenaar61c04492016-07-23 15:35:35 +02001652 * "assert_inrange(lower, upper[, msg])" function
1653 */
1654 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001655f_assert_inrange(typval_T *argvars, typval_T *rettv)
Bram Moolenaar61c04492016-07-23 15:35:35 +02001656{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001657 rettv->vval.v_number = assert_inrange(argvars);
Bram Moolenaar61c04492016-07-23 15:35:35 +02001658}
1659
1660/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001661 * "assert_match(pattern, actual[, msg])" function
1662 */
1663 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001664f_assert_match(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001665{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001666 rettv->vval.v_number = assert_match_common(argvars, ASSERT_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001667}
1668
1669/*
1670 * "assert_notmatch(pattern, actual[, msg])" function
1671 */
1672 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001673f_assert_notmatch(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001674{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001675 rettv->vval.v_number = assert_match_common(argvars, ASSERT_NOTMATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001676}
1677
1678/*
Bram Moolenaar42205552017-03-18 19:42:22 +01001679 * "assert_report(msg)" function
1680 */
1681 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001682f_assert_report(typval_T *argvars, typval_T *rettv)
Bram Moolenaar42205552017-03-18 19:42:22 +01001683{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001684 rettv->vval.v_number = assert_report(argvars);
Bram Moolenaar42205552017-03-18 19:42:22 +01001685}
1686
1687/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001688 * "assert_true(actual[, msg])" function
1689 */
1690 static void
Bram Moolenaar65a54642018-04-28 16:56:53 +02001691f_assert_true(typval_T *argvars, typval_T *rettv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001692{
Bram Moolenaar65a54642018-04-28 16:56:53 +02001693 rettv->vval.v_number = assert_bool(argvars, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001694}
1695
1696#ifdef FEAT_FLOAT
1697/*
1698 * "asin()" function
1699 */
1700 static void
1701f_asin(typval_T *argvars, typval_T *rettv)
1702{
1703 float_T f = 0.0;
1704
1705 rettv->v_type = VAR_FLOAT;
1706 if (get_float_arg(argvars, &f) == OK)
1707 rettv->vval.v_float = asin(f);
1708 else
1709 rettv->vval.v_float = 0.0;
1710}
1711
1712/*
1713 * "atan()" function
1714 */
1715 static void
1716f_atan(typval_T *argvars, typval_T *rettv)
1717{
1718 float_T f = 0.0;
1719
1720 rettv->v_type = VAR_FLOAT;
1721 if (get_float_arg(argvars, &f) == OK)
1722 rettv->vval.v_float = atan(f);
1723 else
1724 rettv->vval.v_float = 0.0;
1725}
1726
1727/*
1728 * "atan2()" function
1729 */
1730 static void
1731f_atan2(typval_T *argvars, typval_T *rettv)
1732{
1733 float_T fx = 0.0, fy = 0.0;
1734
1735 rettv->v_type = VAR_FLOAT;
1736 if (get_float_arg(argvars, &fx) == OK
1737 && get_float_arg(&argvars[1], &fy) == OK)
1738 rettv->vval.v_float = atan2(fx, fy);
1739 else
1740 rettv->vval.v_float = 0.0;
1741}
1742#endif
1743
1744/*
Bram Moolenaar59716a22017-03-01 20:32:44 +01001745 * "balloon_show()" function
1746 */
1747#ifdef FEAT_BEVAL
1748 static void
1749f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
1750{
Bram Moolenaarcaf64342017-03-02 22:11:33 +01001751 if (balloonEval != NULL)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001752 {
1753 if (argvars[0].v_type == VAR_LIST
1754# ifdef FEAT_GUI
1755 && !gui.in_use
1756# endif
1757 )
1758 post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
1759 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001760 post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001761 }
1762}
1763
Bram Moolenaar669a8282017-11-19 20:13:05 +01001764# if defined(FEAT_BEVAL_TERM)
Bram Moolenaar246fe032017-11-19 19:56:27 +01001765 static void
1766f_balloon_split(typval_T *argvars, typval_T *rettv UNUSED)
1767{
1768 if (rettv_list_alloc(rettv) == OK)
1769 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001770 char_u *msg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001771
1772 if (msg != NULL)
1773 {
1774 pumitem_T *array;
1775 int size = split_message(msg, &array);
1776 int i;
1777
1778 /* Skip the first and last item, they are always empty. */
1779 for (i = 1; i < size - 1; ++i)
1780 list_append_string(rettv->vval.v_list, array[i].pum_text, -1);
Bram Moolenaarb301f6b2018-02-10 15:38:35 +01001781 while (size > 0)
1782 vim_free(array[--size].pum_text);
Bram Moolenaar246fe032017-11-19 19:56:27 +01001783 vim_free(array);
1784 }
1785 }
Bram Moolenaar59716a22017-03-01 20:32:44 +01001786}
Bram Moolenaar669a8282017-11-19 20:13:05 +01001787# endif
Bram Moolenaar59716a22017-03-01 20:32:44 +01001788#endif
1789
1790/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001791 * "browse(save, title, initdir, default)" function
1792 */
1793 static void
1794f_browse(typval_T *argvars UNUSED, typval_T *rettv)
1795{
1796#ifdef FEAT_BROWSE
1797 int save;
1798 char_u *title;
1799 char_u *initdir;
1800 char_u *defname;
1801 char_u buf[NUMBUFLEN];
1802 char_u buf2[NUMBUFLEN];
1803 int error = FALSE;
1804
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001805 save = (int)tv_get_number_chk(&argvars[0], &error);
1806 title = tv_get_string_chk(&argvars[1]);
1807 initdir = tv_get_string_buf_chk(&argvars[2], buf);
1808 defname = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001809
1810 if (error || title == NULL || initdir == NULL || defname == NULL)
1811 rettv->vval.v_string = NULL;
1812 else
1813 rettv->vval.v_string =
1814 do_browse(save ? BROWSE_SAVE : 0,
1815 title, defname, NULL, initdir, NULL, curbuf);
1816#else
1817 rettv->vval.v_string = NULL;
1818#endif
1819 rettv->v_type = VAR_STRING;
1820}
1821
1822/*
1823 * "browsedir(title, initdir)" function
1824 */
1825 static void
1826f_browsedir(typval_T *argvars UNUSED, typval_T *rettv)
1827{
1828#ifdef FEAT_BROWSE
1829 char_u *title;
1830 char_u *initdir;
1831 char_u buf[NUMBUFLEN];
1832
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001833 title = tv_get_string_chk(&argvars[0]);
1834 initdir = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001835
1836 if (title == NULL || initdir == NULL)
1837 rettv->vval.v_string = NULL;
1838 else
1839 rettv->vval.v_string = do_browse(BROWSE_DIR,
1840 title, NULL, NULL, initdir, NULL, curbuf);
1841#else
1842 rettv->vval.v_string = NULL;
1843#endif
1844 rettv->v_type = VAR_STRING;
1845}
1846
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001847/*
1848 * Find a buffer by number or exact name.
1849 */
1850 static buf_T *
1851find_buffer(typval_T *avar)
1852{
1853 buf_T *buf = NULL;
1854
1855 if (avar->v_type == VAR_NUMBER)
1856 buf = buflist_findnr((int)avar->vval.v_number);
1857 else if (avar->v_type == VAR_STRING && avar->vval.v_string != NULL)
1858 {
1859 buf = buflist_findname_exp(avar->vval.v_string);
1860 if (buf == NULL)
1861 {
1862 /* No full path name match, try a match with a URL or a "nofile"
1863 * buffer, these don't use the full path. */
Bram Moolenaar29323592016-07-24 22:04:11 +02001864 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001865 if (buf->b_fname != NULL
1866 && (path_with_url(buf->b_fname)
1867#ifdef FEAT_QUICKFIX
1868 || bt_nofile(buf)
1869#endif
1870 )
1871 && STRCMP(buf->b_fname, avar->vval.v_string) == 0)
1872 break;
1873 }
1874 }
1875 return buf;
1876}
1877
1878/*
1879 * "bufexists(expr)" function
1880 */
1881 static void
1882f_bufexists(typval_T *argvars, typval_T *rettv)
1883{
1884 rettv->vval.v_number = (find_buffer(&argvars[0]) != NULL);
1885}
1886
1887/*
1888 * "buflisted(expr)" function
1889 */
1890 static void
1891f_buflisted(typval_T *argvars, typval_T *rettv)
1892{
1893 buf_T *buf;
1894
1895 buf = find_buffer(&argvars[0]);
1896 rettv->vval.v_number = (buf != NULL && buf->b_p_bl);
1897}
1898
1899/*
1900 * "bufloaded(expr)" function
1901 */
1902 static void
1903f_bufloaded(typval_T *argvars, typval_T *rettv)
1904{
1905 buf_T *buf;
1906
1907 buf = find_buffer(&argvars[0]);
1908 rettv->vval.v_number = (buf != NULL && buf->b_ml.ml_mfp != NULL);
1909}
1910
1911 buf_T *
1912buflist_find_by_name(char_u *name, int curtab_only)
1913{
1914 int save_magic;
1915 char_u *save_cpo;
1916 buf_T *buf;
1917
1918 /* Ignore 'magic' and 'cpoptions' here to make scripts portable */
1919 save_magic = p_magic;
1920 p_magic = TRUE;
1921 save_cpo = p_cpo;
1922 p_cpo = (char_u *)"";
1923
1924 buf = buflist_findnr(buflist_findpat(name, name + STRLEN(name),
1925 TRUE, FALSE, curtab_only));
1926
1927 p_magic = save_magic;
1928 p_cpo = save_cpo;
1929 return buf;
1930}
1931
1932/*
1933 * Get buffer by number or pattern.
1934 */
Bram Moolenaarc6df10e2017-07-29 20:15:08 +02001935 buf_T *
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001936tv_get_buf(typval_T *tv, int curtab_only)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001937{
1938 char_u *name = tv->vval.v_string;
1939 buf_T *buf;
1940
1941 if (tv->v_type == VAR_NUMBER)
1942 return buflist_findnr((int)tv->vval.v_number);
1943 if (tv->v_type != VAR_STRING)
1944 return NULL;
1945 if (name == NULL || *name == NUL)
1946 return curbuf;
1947 if (name[0] == '$' && name[1] == NUL)
1948 return lastbuf;
1949
1950 buf = buflist_find_by_name(name, curtab_only);
1951
1952 /* If not found, try expanding the name, like done for bufexists(). */
1953 if (buf == NULL)
1954 buf = find_buffer(tv);
1955
1956 return buf;
1957}
1958
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001959#ifdef FEAT_SIGNS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001960/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001961 * Get the buffer from "arg" and give an error and return NULL if it is not
1962 * valid.
1963 */
1964 static buf_T *
1965get_buf_arg(typval_T *arg)
1966{
1967 buf_T *buf;
1968
1969 ++emsg_off;
1970 buf = tv_get_buf(arg, FALSE);
1971 --emsg_off;
1972 if (buf == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01001973 semsg(_("E158: Invalid buffer name: %s"), tv_get_string(arg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001974 return buf;
1975}
Bram Moolenaarec9d3002019-01-12 13:50:31 +01001976#endif
Bram Moolenaar6b7b7192019-01-11 13:42:41 +01001977
1978/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001979 * "bufname(expr)" function
1980 */
1981 static void
1982f_bufname(typval_T *argvars, typval_T *rettv)
1983{
1984 buf_T *buf;
1985
Bram Moolenaard155d7a2018-12-21 16:04:21 +01001986 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001987 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01001988 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02001989 rettv->v_type = VAR_STRING;
1990 if (buf != NULL && buf->b_fname != NULL)
1991 rettv->vval.v_string = vim_strsave(buf->b_fname);
1992 else
1993 rettv->vval.v_string = NULL;
1994 --emsg_off;
1995}
1996
1997/*
1998 * "bufnr(expr)" function
1999 */
2000 static void
2001f_bufnr(typval_T *argvars, typval_T *rettv)
2002{
2003 buf_T *buf;
2004 int error = FALSE;
2005 char_u *name;
2006
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002007 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002008 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002009 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002010 --emsg_off;
2011
2012 /* If the buffer isn't found and the second argument is not zero create a
2013 * new buffer. */
2014 if (buf == NULL
2015 && argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002016 && tv_get_number_chk(&argvars[1], &error) != 0
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002017 && !error
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002018 && (name = tv_get_string_chk(&argvars[0])) != NULL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002019 && !error)
2020 buf = buflist_new(name, NULL, (linenr_T)1, 0);
2021
2022 if (buf != NULL)
2023 rettv->vval.v_number = buf->b_fnum;
2024 else
2025 rettv->vval.v_number = -1;
2026}
2027
2028 static void
2029buf_win_common(typval_T *argvars, typval_T *rettv, int get_nr)
2030{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002031 win_T *wp;
2032 int winnr = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002033 buf_T *buf;
2034
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002035 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002036 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01002037 buf = tv_get_buf(&argvars[0], TRUE);
Bram Moolenaar29323592016-07-24 22:04:11 +02002038 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002039 {
2040 ++winnr;
2041 if (wp->w_buffer == buf)
2042 break;
2043 }
2044 rettv->vval.v_number = (wp != NULL ? (get_nr ? winnr : wp->w_id) : -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002045 --emsg_off;
2046}
2047
2048/*
2049 * "bufwinid(nr)" function
2050 */
2051 static void
2052f_bufwinid(typval_T *argvars, typval_T *rettv)
2053{
2054 buf_win_common(argvars, rettv, FALSE);
2055}
2056
2057/*
2058 * "bufwinnr(nr)" function
2059 */
2060 static void
2061f_bufwinnr(typval_T *argvars, typval_T *rettv)
2062{
2063 buf_win_common(argvars, rettv, TRUE);
2064}
2065
2066/*
2067 * "byte2line(byte)" function
2068 */
2069 static void
2070f_byte2line(typval_T *argvars UNUSED, typval_T *rettv)
2071{
2072#ifndef FEAT_BYTEOFF
2073 rettv->vval.v_number = -1;
2074#else
2075 long boff = 0;
2076
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002077 boff = tv_get_number(&argvars[0]) - 1; /* boff gets -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002078 if (boff < 0)
2079 rettv->vval.v_number = -1;
2080 else
2081 rettv->vval.v_number = ml_find_line_or_offset(curbuf,
2082 (linenr_T)0, &boff);
2083#endif
2084}
2085
2086 static void
2087byteidx(typval_T *argvars, typval_T *rettv, int comp UNUSED)
2088{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002089 char_u *t;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002090 char_u *str;
2091 varnumber_T idx;
2092
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002093 str = tv_get_string_chk(&argvars[0]);
2094 idx = tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002095 rettv->vval.v_number = -1;
2096 if (str == NULL || idx < 0)
2097 return;
2098
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002099 t = str;
2100 for ( ; idx > 0; idx--)
2101 {
2102 if (*t == NUL) /* EOL reached */
2103 return;
2104 if (enc_utf8 && comp)
2105 t += utf_ptr2len(t);
2106 else
2107 t += (*mb_ptr2len)(t);
2108 }
2109 rettv->vval.v_number = (varnumber_T)(t - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002110}
2111
2112/*
2113 * "byteidx()" function
2114 */
2115 static void
2116f_byteidx(typval_T *argvars, typval_T *rettv)
2117{
2118 byteidx(argvars, rettv, FALSE);
2119}
2120
2121/*
2122 * "byteidxcomp()" function
2123 */
2124 static void
2125f_byteidxcomp(typval_T *argvars, typval_T *rettv)
2126{
2127 byteidx(argvars, rettv, TRUE);
2128}
2129
2130/*
2131 * "call(func, arglist [, dict])" function
2132 */
2133 static void
2134f_call(typval_T *argvars, typval_T *rettv)
2135{
2136 char_u *func;
2137 partial_T *partial = NULL;
2138 dict_T *selfdict = NULL;
2139
2140 if (argvars[1].v_type != VAR_LIST)
2141 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002142 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002143 return;
2144 }
2145 if (argvars[1].vval.v_list == NULL)
2146 return;
2147
2148 if (argvars[0].v_type == VAR_FUNC)
2149 func = argvars[0].vval.v_string;
2150 else if (argvars[0].v_type == VAR_PARTIAL)
2151 {
2152 partial = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02002153 func = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002154 }
2155 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002156 func = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002157 if (*func == NUL)
2158 return; /* type error or empty name */
2159
2160 if (argvars[2].v_type != VAR_UNKNOWN)
2161 {
2162 if (argvars[2].v_type != VAR_DICT)
2163 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002164 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002165 return;
2166 }
2167 selfdict = argvars[2].vval.v_dict;
2168 }
2169
2170 (void)func_call(func, &argvars[1], partial, selfdict, rettv);
2171}
2172
2173#ifdef FEAT_FLOAT
2174/*
2175 * "ceil({float})" function
2176 */
2177 static void
2178f_ceil(typval_T *argvars, typval_T *rettv)
2179{
2180 float_T f = 0.0;
2181
2182 rettv->v_type = VAR_FLOAT;
2183 if (get_float_arg(argvars, &f) == OK)
2184 rettv->vval.v_float = ceil(f);
2185 else
2186 rettv->vval.v_float = 0.0;
2187}
2188#endif
2189
2190#ifdef FEAT_JOB_CHANNEL
2191/*
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002192 * "ch_canread()" function
2193 */
2194 static void
2195f_ch_canread(typval_T *argvars, typval_T *rettv)
2196{
Bram Moolenaar958dc692016-12-01 15:34:12 +01002197 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar4b785f62016-11-29 21:54:44 +01002198
2199 rettv->vval.v_number = 0;
2200 if (channel != NULL)
2201 rettv->vval.v_number = channel_has_readahead(channel, PART_SOCK)
2202 || channel_has_readahead(channel, PART_OUT)
2203 || channel_has_readahead(channel, PART_ERR);
2204}
2205
2206/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002207 * "ch_close()" function
2208 */
2209 static void
2210f_ch_close(typval_T *argvars, typval_T *rettv UNUSED)
2211{
2212 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2213
2214 if (channel != NULL)
2215 {
2216 channel_close(channel, FALSE);
2217 channel_clear(channel);
2218 }
2219}
2220
2221/*
Bram Moolenaar0874a832016-09-01 15:11:51 +02002222 * "ch_close()" function
2223 */
2224 static void
2225f_ch_close_in(typval_T *argvars, typval_T *rettv UNUSED)
2226{
2227 channel_T *channel = get_channel_arg(&argvars[0], TRUE, FALSE, 0);
2228
2229 if (channel != NULL)
2230 channel_close_in(channel);
2231}
2232
2233/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002234 * "ch_getbufnr()" function
2235 */
2236 static void
2237f_ch_getbufnr(typval_T *argvars, typval_T *rettv)
2238{
2239 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2240
2241 rettv->vval.v_number = -1;
2242 if (channel != NULL)
2243 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002244 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002245 int part;
2246
2247 if (STRCMP(what, "err") == 0)
2248 part = PART_ERR;
2249 else if (STRCMP(what, "out") == 0)
2250 part = PART_OUT;
2251 else if (STRCMP(what, "in") == 0)
2252 part = PART_IN;
2253 else
2254 part = PART_SOCK;
2255 if (channel->ch_part[part].ch_bufref.br_buf != NULL)
2256 rettv->vval.v_number =
2257 channel->ch_part[part].ch_bufref.br_buf->b_fnum;
2258 }
2259}
2260
2261/*
2262 * "ch_getjob()" function
2263 */
2264 static void
2265f_ch_getjob(typval_T *argvars, typval_T *rettv)
2266{
2267 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2268
2269 if (channel != NULL)
2270 {
2271 rettv->v_type = VAR_JOB;
2272 rettv->vval.v_job = channel->ch_job;
2273 if (channel->ch_job != NULL)
2274 ++channel->ch_job->jv_refcount;
2275 }
2276}
2277
2278/*
2279 * "ch_info()" function
2280 */
2281 static void
2282f_ch_info(typval_T *argvars, typval_T *rettv UNUSED)
2283{
2284 channel_T *channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2285
2286 if (channel != NULL && rettv_dict_alloc(rettv) != FAIL)
2287 channel_info(channel, rettv->vval.v_dict);
2288}
2289
2290/*
2291 * "ch_log()" function
2292 */
2293 static void
2294f_ch_log(typval_T *argvars, typval_T *rettv UNUSED)
2295{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002296 char_u *msg = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002297 channel_T *channel = NULL;
2298
2299 if (argvars[1].v_type != VAR_UNKNOWN)
2300 channel = get_channel_arg(&argvars[1], FALSE, FALSE, 0);
2301
Bram Moolenaard5359b22018-04-05 22:44:39 +02002302 ch_log(channel, "%s", msg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002303}
2304
2305/*
2306 * "ch_logfile()" function
2307 */
2308 static void
2309f_ch_logfile(typval_T *argvars, typval_T *rettv UNUSED)
2310{
2311 char_u *fname;
2312 char_u *opt = (char_u *)"";
2313 char_u buf[NUMBUFLEN];
2314
Bram Moolenaar6d87e9e2017-08-07 20:51:51 +02002315 /* Don't open a file in restricted mode. */
2316 if (check_restricted() || check_secure())
2317 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002318 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002319 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002320 opt = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002321 ch_logfile(fname, opt);
2322}
2323
2324/*
2325 * "ch_open()" function
2326 */
2327 static void
2328f_ch_open(typval_T *argvars, typval_T *rettv)
2329{
2330 rettv->v_type = VAR_CHANNEL;
2331 if (check_restricted() || check_secure())
2332 return;
2333 rettv->vval.v_channel = channel_open_func(argvars);
2334}
2335
2336/*
2337 * "ch_read()" function
2338 */
2339 static void
2340f_ch_read(typval_T *argvars, typval_T *rettv)
2341{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002342 common_channel_read(argvars, rettv, FALSE, FALSE);
2343}
2344
2345/*
2346 * "ch_readblob()" function
2347 */
2348 static void
2349f_ch_readblob(typval_T *argvars, typval_T *rettv)
2350{
2351 common_channel_read(argvars, rettv, TRUE, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002352}
2353
2354/*
2355 * "ch_readraw()" function
2356 */
2357 static void
2358f_ch_readraw(typval_T *argvars, typval_T *rettv)
2359{
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01002360 common_channel_read(argvars, rettv, TRUE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002361}
2362
2363/*
2364 * "ch_evalexpr()" function
2365 */
2366 static void
2367f_ch_evalexpr(typval_T *argvars, typval_T *rettv)
2368{
2369 ch_expr_common(argvars, rettv, TRUE);
2370}
2371
2372/*
2373 * "ch_sendexpr()" function
2374 */
2375 static void
2376f_ch_sendexpr(typval_T *argvars, typval_T *rettv)
2377{
2378 ch_expr_common(argvars, rettv, FALSE);
2379}
2380
2381/*
2382 * "ch_evalraw()" function
2383 */
2384 static void
2385f_ch_evalraw(typval_T *argvars, typval_T *rettv)
2386{
2387 ch_raw_common(argvars, rettv, TRUE);
2388}
2389
2390/*
2391 * "ch_sendraw()" function
2392 */
2393 static void
2394f_ch_sendraw(typval_T *argvars, typval_T *rettv)
2395{
2396 ch_raw_common(argvars, rettv, FALSE);
2397}
2398
2399/*
2400 * "ch_setoptions()" function
2401 */
2402 static void
2403f_ch_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
2404{
2405 channel_T *channel;
2406 jobopt_T opt;
2407
2408 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
2409 if (channel == NULL)
2410 return;
2411 clear_job_options(&opt);
2412 if (get_job_options(&argvars[1], &opt,
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002413 JO_CB_ALL + JO_TIMEOUT_ALL + JO_MODE_ALL, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002414 channel_set_options(channel, &opt);
2415 free_job_options(&opt);
2416}
2417
2418/*
2419 * "ch_status()" function
2420 */
2421 static void
2422f_ch_status(typval_T *argvars, typval_T *rettv)
2423{
2424 channel_T *channel;
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002425 jobopt_T opt;
2426 int part = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002427
2428 /* return an empty string by default */
2429 rettv->v_type = VAR_STRING;
2430 rettv->vval.v_string = NULL;
2431
2432 channel = get_channel_arg(&argvars[0], FALSE, FALSE, 0);
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002433
2434 if (argvars[1].v_type != VAR_UNKNOWN)
2435 {
2436 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02002437 if (get_job_options(&argvars[1], &opt, JO_PART, 0) == OK
Bram Moolenaar7ef38102016-09-26 22:36:58 +02002438 && (opt.jo_set & JO_PART))
2439 part = opt.jo_part;
2440 }
2441
2442 rettv->vval.v_string = vim_strsave((char_u *)channel_status(channel, part));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002443}
2444#endif
2445
2446/*
2447 * "changenr()" function
2448 */
2449 static void
2450f_changenr(typval_T *argvars UNUSED, typval_T *rettv)
2451{
2452 rettv->vval.v_number = curbuf->b_u_seq_cur;
2453}
2454
2455/*
2456 * "char2nr(string)" function
2457 */
2458 static void
2459f_char2nr(typval_T *argvars, typval_T *rettv)
2460{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002461 if (has_mbyte)
2462 {
2463 int utf8 = 0;
2464
2465 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002466 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002467
2468 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01002469 rettv->vval.v_number = utf_ptr2char(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002470 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002471 rettv->vval.v_number = (*mb_ptr2char)(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002472 }
2473 else
Bram Moolenaar13505972019-01-24 15:04:48 +01002474 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002475}
2476
2477/*
2478 * "cindent(lnum)" function
2479 */
2480 static void
2481f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
2482{
2483#ifdef FEAT_CINDENT
2484 pos_T pos;
2485 linenr_T lnum;
2486
2487 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002488 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002489 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2490 {
2491 curwin->w_cursor.lnum = lnum;
2492 rettv->vval.v_number = get_c_indent();
2493 curwin->w_cursor = pos;
2494 }
2495 else
2496#endif
2497 rettv->vval.v_number = -1;
2498}
2499
Bram Moolenaaraff74912019-03-30 18:11:49 +01002500 static win_T *
2501get_optional_window(typval_T *argvars, int idx)
2502{
2503 win_T *win = curwin;
2504
2505 if (argvars[idx].v_type != VAR_UNKNOWN)
2506 {
2507 win = find_win_by_nr_or_id(&argvars[idx]);
2508 if (win == NULL)
2509 {
2510 emsg(_(e_invalwindow));
2511 return NULL;
2512 }
2513 }
2514 return win;
2515}
2516
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002517/*
2518 * "clearmatches()" function
2519 */
2520 static void
2521f_clearmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2522{
2523#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01002524 win_T *win = get_optional_window(argvars, 0);
2525
2526 if (win != NULL)
2527 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002528#endif
2529}
2530
2531/*
2532 * "col(string)" function
2533 */
2534 static void
2535f_col(typval_T *argvars, typval_T *rettv)
2536{
2537 colnr_T col = 0;
2538 pos_T *fp;
2539 int fnum = curbuf->b_fnum;
2540
2541 fp = var2fpos(&argvars[0], FALSE, &fnum);
2542 if (fp != NULL && fnum == curbuf->b_fnum)
2543 {
2544 if (fp->col == MAXCOL)
2545 {
2546 /* '> can be MAXCOL, get the length of the line then */
2547 if (fp->lnum <= curbuf->b_ml.ml_line_count)
2548 col = (colnr_T)STRLEN(ml_get(fp->lnum)) + 1;
2549 else
2550 col = MAXCOL;
2551 }
2552 else
2553 {
2554 col = fp->col + 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002555 /* col(".") when the cursor is on the NUL at the end of the line
2556 * because of "coladd" can be seen as an extra column. */
2557 if (virtual_active() && fp == &curwin->w_cursor)
2558 {
2559 char_u *p = ml_get_cursor();
2560
2561 if (curwin->w_cursor.coladd >= (colnr_T)chartabsize(p,
2562 curwin->w_virtcol - curwin->w_cursor.coladd))
2563 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002564 int l;
2565
2566 if (*p != NUL && p[(l = (*mb_ptr2len)(p))] == NUL)
2567 col += l;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002568 }
2569 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002570 }
2571 }
2572 rettv->vval.v_number = col;
2573}
2574
2575#if defined(FEAT_INS_EXPAND)
2576/*
2577 * "complete()" function
2578 */
2579 static void
2580f_complete(typval_T *argvars, typval_T *rettv UNUSED)
2581{
2582 int startcol;
2583
2584 if ((State & INSERT) == 0)
2585 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002586 emsg(_("E785: complete() can only be used in Insert mode"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002587 return;
2588 }
2589
2590 /* Check for undo allowed here, because if something was already inserted
2591 * the line was already saved for undo and this check isn't done. */
2592 if (!undo_allowed())
2593 return;
2594
2595 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
2596 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002597 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002598 return;
2599 }
2600
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002601 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002602 if (startcol <= 0)
2603 return;
2604
2605 set_completion(startcol - 1, argvars[1].vval.v_list);
2606}
2607
2608/*
2609 * "complete_add()" function
2610 */
2611 static void
2612f_complete_add(typval_T *argvars, typval_T *rettv)
2613{
2614 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0);
2615}
2616
2617/*
2618 * "complete_check()" function
2619 */
2620 static void
2621f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2622{
2623 int saved = RedrawingDisabled;
2624
2625 RedrawingDisabled = 0;
Bram Moolenaar472e8592016-10-15 17:06:47 +02002626 ins_compl_check_keys(0, TRUE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002627 rettv->vval.v_number = ins_compl_interrupted();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002628 RedrawingDisabled = saved;
2629}
Bram Moolenaarfd133322019-03-29 12:20:27 +01002630
2631/*
2632 * "complete_info()" function
2633 */
2634 static void
2635f_complete_info(typval_T *argvars, typval_T *rettv)
2636{
2637 list_T *what_list = NULL;
2638
2639 if (rettv_dict_alloc(rettv) != OK)
2640 return;
2641
2642 if (argvars[0].v_type != VAR_UNKNOWN)
2643 {
2644 if (argvars[0].v_type != VAR_LIST)
2645 {
2646 emsg(_(e_listreq));
2647 return;
2648 }
2649 what_list = argvars[0].vval.v_list;
2650 }
2651 get_complete_info(what_list, rettv->vval.v_dict);
2652}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002653#endif
2654
2655/*
2656 * "confirm(message, buttons[, default [, type]])" function
2657 */
2658 static void
2659f_confirm(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2660{
2661#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
2662 char_u *message;
2663 char_u *buttons = NULL;
2664 char_u buf[NUMBUFLEN];
2665 char_u buf2[NUMBUFLEN];
2666 int def = 1;
2667 int type = VIM_GENERIC;
2668 char_u *typestr;
2669 int error = FALSE;
2670
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002671 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002672 if (message == NULL)
2673 error = TRUE;
2674 if (argvars[1].v_type != VAR_UNKNOWN)
2675 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002676 buttons = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002677 if (buttons == NULL)
2678 error = TRUE;
2679 if (argvars[2].v_type != VAR_UNKNOWN)
2680 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002681 def = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002682 if (argvars[3].v_type != VAR_UNKNOWN)
2683 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002684 typestr = tv_get_string_buf_chk(&argvars[3], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002685 if (typestr == NULL)
2686 error = TRUE;
2687 else
2688 {
2689 switch (TOUPPER_ASC(*typestr))
2690 {
2691 case 'E': type = VIM_ERROR; break;
2692 case 'Q': type = VIM_QUESTION; break;
2693 case 'I': type = VIM_INFO; break;
2694 case 'W': type = VIM_WARNING; break;
2695 case 'G': type = VIM_GENERIC; break;
2696 }
2697 }
2698 }
2699 }
2700 }
2701
2702 if (buttons == NULL || *buttons == NUL)
2703 buttons = (char_u *)_("&Ok");
2704
2705 if (!error)
2706 rettv->vval.v_number = do_dialog(type, NULL, message, buttons,
2707 def, NULL, FALSE);
2708#endif
2709}
2710
2711/*
2712 * "copy()" function
2713 */
2714 static void
2715f_copy(typval_T *argvars, typval_T *rettv)
2716{
2717 item_copy(&argvars[0], rettv, FALSE, 0);
2718}
2719
2720#ifdef FEAT_FLOAT
2721/*
2722 * "cos()" function
2723 */
2724 static void
2725f_cos(typval_T *argvars, typval_T *rettv)
2726{
2727 float_T f = 0.0;
2728
2729 rettv->v_type = VAR_FLOAT;
2730 if (get_float_arg(argvars, &f) == OK)
2731 rettv->vval.v_float = cos(f);
2732 else
2733 rettv->vval.v_float = 0.0;
2734}
2735
2736/*
2737 * "cosh()" function
2738 */
2739 static void
2740f_cosh(typval_T *argvars, typval_T *rettv)
2741{
2742 float_T f = 0.0;
2743
2744 rettv->v_type = VAR_FLOAT;
2745 if (get_float_arg(argvars, &f) == OK)
2746 rettv->vval.v_float = cosh(f);
2747 else
2748 rettv->vval.v_float = 0.0;
2749}
2750#endif
2751
2752/*
2753 * "count()" function
2754 */
2755 static void
2756f_count(typval_T *argvars, typval_T *rettv)
2757{
2758 long n = 0;
2759 int ic = FALSE;
Bram Moolenaar9966b212017-07-28 16:46:57 +02002760 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002761
Bram Moolenaar9966b212017-07-28 16:46:57 +02002762 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002763 ic = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002764
2765 if (argvars[0].v_type == VAR_STRING)
2766 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002767 char_u *expr = tv_get_string_chk(&argvars[1]);
Bram Moolenaar9966b212017-07-28 16:46:57 +02002768 char_u *p = argvars[0].vval.v_string;
2769 char_u *next;
2770
Bram Moolenaar338e47f2017-12-19 11:55:26 +01002771 if (!error && expr != NULL && *expr != NUL && p != NULL)
Bram Moolenaar9966b212017-07-28 16:46:57 +02002772 {
2773 if (ic)
2774 {
2775 size_t len = STRLEN(expr);
2776
2777 while (*p != NUL)
2778 {
2779 if (MB_STRNICMP(p, expr, len) == 0)
2780 {
2781 ++n;
2782 p += len;
2783 }
2784 else
2785 MB_PTR_ADV(p);
2786 }
2787 }
2788 else
2789 while ((next = (char_u *)strstr((char *)p, (char *)expr))
2790 != NULL)
2791 {
2792 ++n;
2793 p = next + STRLEN(expr);
2794 }
2795 }
2796
2797 }
2798 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002799 {
2800 listitem_T *li;
2801 list_T *l;
2802 long idx;
2803
2804 if ((l = argvars[0].vval.v_list) != NULL)
2805 {
2806 li = l->lv_first;
2807 if (argvars[2].v_type != VAR_UNKNOWN)
2808 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002809 if (argvars[3].v_type != VAR_UNKNOWN)
2810 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002811 idx = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002812 if (!error)
2813 {
2814 li = list_find(l, idx);
2815 if (li == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002816 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002817 }
2818 }
2819 if (error)
2820 li = NULL;
2821 }
2822
2823 for ( ; li != NULL; li = li->li_next)
2824 if (tv_equal(&li->li_tv, &argvars[1], ic, FALSE))
2825 ++n;
2826 }
2827 }
2828 else if (argvars[0].v_type == VAR_DICT)
2829 {
2830 int todo;
2831 dict_T *d;
2832 hashitem_T *hi;
2833
2834 if ((d = argvars[0].vval.v_dict) != NULL)
2835 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002836 if (argvars[2].v_type != VAR_UNKNOWN)
2837 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002838 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002839 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002840 }
2841
2842 todo = error ? 0 : (int)d->dv_hashtab.ht_used;
2843 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
2844 {
2845 if (!HASHITEM_EMPTY(hi))
2846 {
2847 --todo;
2848 if (tv_equal(&HI2DI(hi)->di_tv, &argvars[1], ic, FALSE))
2849 ++n;
2850 }
2851 }
2852 }
2853 }
2854 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002855 semsg(_(e_listdictarg), "count()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002856 rettv->vval.v_number = n;
2857}
2858
2859/*
2860 * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function
2861 *
2862 * Checks the existence of a cscope connection.
2863 */
2864 static void
2865f_cscope_connection(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
2866{
2867#ifdef FEAT_CSCOPE
2868 int num = 0;
2869 char_u *dbpath = NULL;
2870 char_u *prepend = NULL;
2871 char_u buf[NUMBUFLEN];
2872
2873 if (argvars[0].v_type != VAR_UNKNOWN
2874 && argvars[1].v_type != VAR_UNKNOWN)
2875 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002876 num = (int)tv_get_number(&argvars[0]);
2877 dbpath = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002878 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002879 prepend = tv_get_string_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002880 }
2881
2882 rettv->vval.v_number = cs_connection(num, dbpath, prepend);
2883#endif
2884}
2885
2886/*
2887 * "cursor(lnum, col)" function, or
2888 * "cursor(list)"
2889 *
2890 * Moves the cursor to the specified line and column.
2891 * Returns 0 when the position could be set, -1 otherwise.
2892 */
2893 static void
2894f_cursor(typval_T *argvars, typval_T *rettv)
2895{
2896 long line, col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002897 long coladd = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002898 int set_curswant = TRUE;
2899
2900 rettv->vval.v_number = -1;
2901 if (argvars[1].v_type == VAR_UNKNOWN)
2902 {
2903 pos_T pos;
2904 colnr_T curswant = -1;
2905
2906 if (list2fpos(argvars, &pos, NULL, &curswant) == FAIL)
2907 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002908 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002909 return;
2910 }
2911 line = pos.lnum;
2912 col = pos.col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002913 coladd = pos.coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002914 if (curswant >= 0)
2915 {
2916 curwin->w_curswant = curswant - 1;
2917 set_curswant = FALSE;
2918 }
2919 }
2920 else
2921 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002922 line = tv_get_lnum(argvars);
2923 col = (long)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002924 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002925 coladd = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002926 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01002927 if (line < 0 || col < 0 || coladd < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002928 return; /* type error; errmsg already given */
2929 if (line > 0)
2930 curwin->w_cursor.lnum = line;
2931 if (col > 0)
2932 curwin->w_cursor.col = col - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002933 curwin->w_cursor.coladd = coladd;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002934
2935 /* Make sure the cursor is in a valid position. */
2936 check_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002937 /* Correct cursor for multi-byte character. */
2938 if (has_mbyte)
2939 mb_adjust_cursor();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002940
2941 curwin->w_set_curswant = set_curswant;
2942 rettv->vval.v_number = 0;
2943}
2944
Bram Moolenaar4f974752019-02-17 17:44:42 +01002945#ifdef MSWIN
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002946/*
2947 * "debugbreak()" function
2948 */
2949 static void
2950f_debugbreak(typval_T *argvars, typval_T *rettv)
2951{
2952 int pid;
2953
2954 rettv->vval.v_number = FAIL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002955 pid = (int)tv_get_number(&argvars[0]);
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002956 if (pid == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002957 emsg(_(e_invarg));
Bram Moolenaar4551c0a2018-06-20 22:38:21 +02002958 else
2959 {
2960 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
2961
2962 if (hProcess != NULL)
2963 {
2964 DebugBreakProcess(hProcess);
2965 CloseHandle(hProcess);
2966 rettv->vval.v_number = OK;
2967 }
2968 }
2969}
2970#endif
2971
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002972/*
2973 * "deepcopy()" function
2974 */
2975 static void
2976f_deepcopy(typval_T *argvars, typval_T *rettv)
2977{
2978 int noref = 0;
2979 int copyID;
2980
2981 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01002982 noref = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002983 if (noref < 0 || noref > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01002984 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02002985 else
2986 {
2987 copyID = get_copyID();
2988 item_copy(&argvars[0], rettv, TRUE, noref == 0 ? copyID : 0);
2989 }
2990}
2991
2992/*
2993 * "delete()" function
2994 */
2995 static void
2996f_delete(typval_T *argvars, typval_T *rettv)
2997{
2998 char_u nbuf[NUMBUFLEN];
2999 char_u *name;
3000 char_u *flags;
3001
3002 rettv->vval.v_number = -1;
3003 if (check_restricted() || check_secure())
3004 return;
3005
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003006 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003007 if (name == NULL || *name == NUL)
3008 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003009 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003010 return;
3011 }
3012
3013 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003014 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003015 else
3016 flags = (char_u *)"";
3017
3018 if (*flags == NUL)
3019 /* delete a file */
3020 rettv->vval.v_number = mch_remove(name) == 0 ? 0 : -1;
3021 else if (STRCMP(flags, "d") == 0)
3022 /* delete an empty directory */
3023 rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
3024 else if (STRCMP(flags, "rf") == 0)
3025 /* delete a directory recursively */
3026 rettv->vval.v_number = delete_recursive(name);
3027 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003028 semsg(_(e_invexpr2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003029}
3030
3031/*
Bram Moolenaard79a2622018-06-07 18:17:46 +02003032 * "deletebufline()" function
3033 */
3034 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +02003035f_deletebufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaard79a2622018-06-07 18:17:46 +02003036{
3037 buf_T *buf;
3038 linenr_T first, last;
3039 linenr_T lnum;
3040 long count;
3041 int is_curbuf;
3042 buf_T *curbuf_save = NULL;
3043 win_T *curwin_save = NULL;
3044 tabpage_T *tp;
3045 win_T *wp;
3046
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01003047 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003048 if (buf == NULL)
3049 {
3050 rettv->vval.v_number = 1; /* FAIL */
3051 return;
3052 }
3053 is_curbuf = buf == curbuf;
3054
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003055 first = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003056 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003057 last = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaard79a2622018-06-07 18:17:46 +02003058 else
3059 last = first;
3060
3061 if (buf->b_ml.ml_mfp == NULL || first < 1
3062 || first > buf->b_ml.ml_line_count || last < first)
3063 {
3064 rettv->vval.v_number = 1; /* FAIL */
3065 return;
3066 }
3067
3068 if (!is_curbuf)
3069 {
3070 curbuf_save = curbuf;
3071 curwin_save = curwin;
3072 curbuf = buf;
3073 find_win_for_curbuf();
3074 }
3075 if (last > curbuf->b_ml.ml_line_count)
3076 last = curbuf->b_ml.ml_line_count;
3077 count = last - first + 1;
3078
3079 // When coming here from Insert mode, sync undo, so that this can be
3080 // undone separately from what was previously inserted.
3081 if (u_sync_once == 2)
3082 {
3083 u_sync_once = 1; // notify that u_sync() was called
3084 u_sync(TRUE);
3085 }
3086
3087 if (u_save(first - 1, last + 1) == FAIL)
3088 {
3089 rettv->vval.v_number = 1; /* FAIL */
3090 return;
3091 }
3092
3093 for (lnum = first; lnum <= last; ++lnum)
3094 ml_delete(first, TRUE);
3095
3096 FOR_ALL_TAB_WINDOWS(tp, wp)
3097 if (wp->w_buffer == buf)
3098 {
3099 if (wp->w_cursor.lnum > last)
3100 wp->w_cursor.lnum -= count;
3101 else if (wp->w_cursor.lnum> first)
3102 wp->w_cursor.lnum = first;
3103 if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
3104 wp->w_cursor.lnum = wp->w_buffer->b_ml.ml_line_count;
3105 }
3106 check_cursor_col();
3107 deleted_lines_mark(first, count);
3108
3109 if (!is_curbuf)
3110 {
3111 curbuf = curbuf_save;
3112 curwin = curwin_save;
3113 }
3114}
3115
3116/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003117 * "did_filetype()" function
3118 */
3119 static void
3120f_did_filetype(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3121{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003122 rettv->vval.v_number = did_filetype;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003123}
3124
3125/*
3126 * "diff_filler()" function
3127 */
3128 static void
3129f_diff_filler(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3130{
3131#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003132 rettv->vval.v_number = diff_check_fill(curwin, tv_get_lnum(argvars));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003133#endif
3134}
3135
3136/*
3137 * "diff_hlID()" function
3138 */
3139 static void
3140f_diff_hlID(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
3141{
3142#ifdef FEAT_DIFF
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003143 linenr_T lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003144 static linenr_T prev_lnum = 0;
Bram Moolenaar79518e22017-02-17 16:31:35 +01003145 static varnumber_T changedtick = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003146 static int fnum = 0;
3147 static int change_start = 0;
3148 static int change_end = 0;
3149 static hlf_T hlID = (hlf_T)0;
3150 int filler_lines;
3151 int col;
3152
3153 if (lnum < 0) /* ignore type error in {lnum} arg */
3154 lnum = 0;
3155 if (lnum != prev_lnum
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003156 || changedtick != CHANGEDTICK(curbuf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003157 || fnum != curbuf->b_fnum)
3158 {
3159 /* New line, buffer, change: need to get the values. */
3160 filler_lines = diff_check(curwin, lnum);
3161 if (filler_lines < 0)
3162 {
3163 if (filler_lines == -1)
3164 {
3165 change_start = MAXCOL;
3166 change_end = -1;
3167 if (diff_find_change(curwin, lnum, &change_start, &change_end))
3168 hlID = HLF_ADD; /* added line */
3169 else
3170 hlID = HLF_CHD; /* changed line */
3171 }
3172 else
3173 hlID = HLF_ADD; /* added line */
3174 }
3175 else
3176 hlID = (hlf_T)0;
3177 prev_lnum = lnum;
Bram Moolenaar95c526e2017-02-25 14:59:34 +01003178 changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003179 fnum = curbuf->b_fnum;
3180 }
3181
3182 if (hlID == HLF_CHD || hlID == HLF_TXD)
3183 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003184 col = tv_get_number(&argvars[1]) - 1; /* ignore type error in {col} */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003185 if (col >= change_start && col <= change_end)
3186 hlID = HLF_TXD; /* changed text */
3187 else
3188 hlID = HLF_CHD; /* changed line */
3189 }
3190 rettv->vval.v_number = hlID == (hlf_T)0 ? 0 : (int)hlID;
3191#endif
3192}
3193
3194/*
3195 * "empty({expr})" function
3196 */
3197 static void
3198f_empty(typval_T *argvars, typval_T *rettv)
3199{
3200 int n = FALSE;
3201
3202 switch (argvars[0].v_type)
3203 {
3204 case VAR_STRING:
3205 case VAR_FUNC:
3206 n = argvars[0].vval.v_string == NULL
3207 || *argvars[0].vval.v_string == NUL;
3208 break;
3209 case VAR_PARTIAL:
3210 n = FALSE;
3211 break;
3212 case VAR_NUMBER:
3213 n = argvars[0].vval.v_number == 0;
3214 break;
3215 case VAR_FLOAT:
3216#ifdef FEAT_FLOAT
3217 n = argvars[0].vval.v_float == 0.0;
3218 break;
3219#endif
3220 case VAR_LIST:
3221 n = argvars[0].vval.v_list == NULL
3222 || argvars[0].vval.v_list->lv_first == NULL;
3223 break;
3224 case VAR_DICT:
3225 n = argvars[0].vval.v_dict == NULL
3226 || argvars[0].vval.v_dict->dv_hashtab.ht_used == 0;
3227 break;
3228 case VAR_SPECIAL:
3229 n = argvars[0].vval.v_number != VVAL_TRUE;
3230 break;
3231
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003232 case VAR_BLOB:
3233 n = argvars[0].vval.v_blob == NULL
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01003234 || argvars[0].vval.v_blob->bv_ga.ga_len == 0;
3235 break;
3236
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003237 case VAR_JOB:
3238#ifdef FEAT_JOB_CHANNEL
3239 n = argvars[0].vval.v_job == NULL
3240 || argvars[0].vval.v_job->jv_status != JOB_STARTED;
3241 break;
3242#endif
3243 case VAR_CHANNEL:
3244#ifdef FEAT_JOB_CHANNEL
3245 n = argvars[0].vval.v_channel == NULL
3246 || !channel_is_open(argvars[0].vval.v_channel);
3247 break;
3248#endif
3249 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +01003250 internal_error("f_empty(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003251 n = TRUE;
3252 break;
3253 }
3254
3255 rettv->vval.v_number = n;
3256}
3257
3258/*
3259 * "escape({string}, {chars})" function
3260 */
3261 static void
3262f_escape(typval_T *argvars, typval_T *rettv)
3263{
3264 char_u buf[NUMBUFLEN];
3265
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003266 rettv->vval.v_string = vim_strsave_escaped(tv_get_string(&argvars[0]),
3267 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003268 rettv->v_type = VAR_STRING;
3269}
3270
3271/*
3272 * "eval()" function
3273 */
3274 static void
3275f_eval(typval_T *argvars, typval_T *rettv)
3276{
3277 char_u *s, *p;
3278
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003279 s = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003280 if (s != NULL)
3281 s = skipwhite(s);
3282
3283 p = s;
3284 if (s == NULL || eval1(&s, rettv, TRUE) == FAIL)
3285 {
3286 if (p != NULL && !aborting())
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003287 semsg(_(e_invexpr2), p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003288 need_clr_eos = FALSE;
3289 rettv->v_type = VAR_NUMBER;
3290 rettv->vval.v_number = 0;
3291 }
3292 else if (*s != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003293 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003294}
3295
3296/*
3297 * "eventhandler()" function
3298 */
3299 static void
3300f_eventhandler(typval_T *argvars UNUSED, typval_T *rettv)
3301{
3302 rettv->vval.v_number = vgetc_busy;
3303}
3304
3305/*
3306 * "executable()" function
3307 */
3308 static void
3309f_executable(typval_T *argvars, typval_T *rettv)
3310{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003311 char_u *name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003312
3313 /* Check in $PATH and also check directly if there is a directory name. */
3314 rettv->vval.v_number = mch_can_exe(name, NULL, TRUE)
3315 || (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
3316}
3317
3318static garray_T redir_execute_ga;
3319
3320/*
3321 * Append "value[value_len]" to the execute() output.
3322 */
3323 void
3324execute_redir_str(char_u *value, int value_len)
3325{
3326 int len;
3327
3328 if (value_len == -1)
3329 len = (int)STRLEN(value); /* Append the entire string */
3330 else
3331 len = value_len; /* Append only "value_len" characters */
3332 if (ga_grow(&redir_execute_ga, len) == OK)
3333 {
3334 mch_memmove((char *)redir_execute_ga.ga_data
3335 + redir_execute_ga.ga_len, value, len);
3336 redir_execute_ga.ga_len += len;
3337 }
3338}
3339
3340/*
3341 * Get next line from a list.
3342 * Called by do_cmdline() to get the next line.
3343 * Returns allocated string, or NULL for end of function.
3344 */
3345
3346 static char_u *
3347get_list_line(
3348 int c UNUSED,
3349 void *cookie,
3350 int indent UNUSED)
3351{
3352 listitem_T **p = (listitem_T **)cookie;
3353 listitem_T *item = *p;
3354 char_u buf[NUMBUFLEN];
3355 char_u *s;
3356
3357 if (item == NULL)
3358 return NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003359 s = tv_get_string_buf_chk(&item->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003360 *p = item->li_next;
3361 return s == NULL ? NULL : vim_strsave(s);
3362}
3363
3364/*
3365 * "execute()" function
3366 */
3367 static void
3368f_execute(typval_T *argvars, typval_T *rettv)
3369{
3370 char_u *cmd = NULL;
3371 list_T *list = NULL;
3372 int save_msg_silent = msg_silent;
3373 int save_emsg_silent = emsg_silent;
3374 int save_emsg_noredir = emsg_noredir;
3375 int save_redir_execute = redir_execute;
Bram Moolenaar20951482017-12-25 13:44:43 +01003376 int save_redir_off = redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003377 garray_T save_ga;
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003378 int save_msg_col = msg_col;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003379 int echo_output = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003380
3381 rettv->vval.v_string = NULL;
3382 rettv->v_type = VAR_STRING;
3383
3384 if (argvars[0].v_type == VAR_LIST)
3385 {
3386 list = argvars[0].vval.v_list;
3387 if (list == NULL || list->lv_first == NULL)
3388 /* empty list, no commands, empty output */
3389 return;
3390 ++list->lv_refcount;
3391 }
3392 else
3393 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003394 cmd = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003395 if (cmd == NULL)
3396 return;
3397 }
3398
3399 if (argvars[1].v_type != VAR_UNKNOWN)
3400 {
3401 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003402 char_u *s = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003403
3404 if (s == NULL)
3405 return;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003406 if (*s == NUL)
3407 echo_output = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003408 if (STRNCMP(s, "silent", 6) == 0)
3409 ++msg_silent;
3410 if (STRCMP(s, "silent!") == 0)
3411 {
3412 emsg_silent = TRUE;
3413 emsg_noredir = TRUE;
3414 }
3415 }
3416 else
3417 ++msg_silent;
3418
3419 if (redir_execute)
3420 save_ga = redir_execute_ga;
3421 ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
3422 redir_execute = TRUE;
Bram Moolenaar20951482017-12-25 13:44:43 +01003423 redir_off = FALSE;
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003424 if (!echo_output)
3425 msg_col = 0; // prevent leading spaces
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003426
3427 if (cmd != NULL)
3428 do_cmdline_cmd(cmd);
3429 else
3430 {
3431 listitem_T *item = list->lv_first;
3432
3433 do_cmdline(NULL, get_list_line, (void *)&item,
3434 DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
3435 --list->lv_refcount;
3436 }
3437
Bram Moolenaard297f352017-01-29 20:31:21 +01003438 /* Need to append a NUL to the result. */
3439 if (ga_grow(&redir_execute_ga, 1) == OK)
3440 {
3441 ((char *)redir_execute_ga.ga_data)[redir_execute_ga.ga_len] = NUL;
3442 rettv->vval.v_string = redir_execute_ga.ga_data;
3443 }
3444 else
3445 {
3446 ga_clear(&redir_execute_ga);
3447 rettv->vval.v_string = NULL;
3448 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003449 msg_silent = save_msg_silent;
3450 emsg_silent = save_emsg_silent;
3451 emsg_noredir = save_emsg_noredir;
3452
3453 redir_execute = save_redir_execute;
3454 if (redir_execute)
3455 redir_execute_ga = save_ga;
Bram Moolenaar20951482017-12-25 13:44:43 +01003456 redir_off = save_redir_off;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003457
Bram Moolenaar10ccaa12018-12-07 16:38:23 +01003458 // "silent reg" or "silent echo x" leaves msg_col somewhere in the line.
Bram Moolenaar446e7a32018-12-08 13:57:42 +01003459 if (echo_output)
3460 // When not working silently: put it in column zero. A following
3461 // "echon" will overwrite the message, unavoidably.
3462 msg_col = 0;
3463 else
3464 // When working silently: Put it back where it was, since nothing
3465 // should have been written.
3466 msg_col = save_msg_col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003467}
3468
3469/*
3470 * "exepath()" function
3471 */
3472 static void
3473f_exepath(typval_T *argvars, typval_T *rettv)
3474{
3475 char_u *p = NULL;
3476
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003477 (void)mch_can_exe(tv_get_string(&argvars[0]), &p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003478 rettv->v_type = VAR_STRING;
3479 rettv->vval.v_string = p;
3480}
3481
3482/*
3483 * "exists()" function
3484 */
3485 static void
3486f_exists(typval_T *argvars, typval_T *rettv)
3487{
3488 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003489 int n = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003490
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003491 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003492 if (*p == '$') /* environment variable */
3493 {
3494 /* first try "normal" environment variables (fast) */
3495 if (mch_getenv(p + 1) != NULL)
3496 n = TRUE;
3497 else
3498 {
3499 /* try expanding things like $VIM and ${HOME} */
3500 p = expand_env_save(p);
3501 if (p != NULL && *p != '$')
3502 n = TRUE;
3503 vim_free(p);
3504 }
3505 }
3506 else if (*p == '&' || *p == '+') /* option */
3507 {
3508 n = (get_option_tv(&p, NULL, TRUE) == OK);
3509 if (*skipwhite(p) != NUL)
3510 n = FALSE; /* trailing garbage */
3511 }
3512 else if (*p == '*') /* internal or user defined function */
3513 {
Bram Moolenaarb54c3ff2016-07-31 14:11:58 +02003514 n = function_exists(p + 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003515 }
3516 else if (*p == ':')
3517 {
3518 n = cmd_exists(p + 1);
3519 }
3520 else if (*p == '#')
3521 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003522 if (p[1] == '#')
3523 n = autocmd_supported(p + 2);
3524 else
3525 n = au_exists(p + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003526 }
3527 else /* internal variable */
3528 {
Bram Moolenaarc6f9f732018-02-11 19:06:26 +01003529 n = var_exists(p);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003530 }
3531
3532 rettv->vval.v_number = n;
3533}
3534
3535#ifdef FEAT_FLOAT
3536/*
3537 * "exp()" function
3538 */
3539 static void
3540f_exp(typval_T *argvars, typval_T *rettv)
3541{
3542 float_T f = 0.0;
3543
3544 rettv->v_type = VAR_FLOAT;
3545 if (get_float_arg(argvars, &f) == OK)
3546 rettv->vval.v_float = exp(f);
3547 else
3548 rettv->vval.v_float = 0.0;
3549}
3550#endif
3551
3552/*
3553 * "expand()" function
3554 */
3555 static void
3556f_expand(typval_T *argvars, typval_T *rettv)
3557{
3558 char_u *s;
3559 int len;
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003560 char *errormsg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003561 int options = WILD_SILENT|WILD_USE_NL|WILD_LIST_NOTFOUND;
3562 expand_T xpc;
3563 int error = FALSE;
3564 char_u *result;
3565
3566 rettv->v_type = VAR_STRING;
3567 if (argvars[1].v_type != VAR_UNKNOWN
3568 && argvars[2].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003569 && tv_get_number_chk(&argvars[2], &error)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003570 && !error)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02003571 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003572
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003573 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003574 if (*s == '%' || *s == '#' || *s == '<')
3575 {
3576 ++emsg_off;
3577 result = eval_vars(s, s, &len, NULL, &errormsg, NULL);
3578 --emsg_off;
3579 if (rettv->v_type == VAR_LIST)
3580 {
3581 if (rettv_list_alloc(rettv) != FAIL && result != NULL)
3582 list_append_string(rettv->vval.v_list, result, -1);
3583 else
3584 vim_free(result);
3585 }
3586 else
3587 rettv->vval.v_string = result;
3588 }
3589 else
3590 {
3591 /* When the optional second argument is non-zero, don't remove matches
3592 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
3593 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003594 && tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003595 options |= WILD_KEEP_ALL;
3596 if (!error)
3597 {
3598 ExpandInit(&xpc);
3599 xpc.xp_context = EXPAND_FILES;
3600 if (p_wic)
3601 options += WILD_ICASE;
3602 if (rettv->v_type == VAR_STRING)
3603 rettv->vval.v_string = ExpandOne(&xpc, s, NULL,
3604 options, WILD_ALL);
3605 else if (rettv_list_alloc(rettv) != FAIL)
3606 {
3607 int i;
3608
3609 ExpandOne(&xpc, s, NULL, options, WILD_ALL_KEEP);
3610 for (i = 0; i < xpc.xp_numfiles; i++)
3611 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
3612 ExpandCleanup(&xpc);
3613 }
3614 }
3615 else
3616 rettv->vval.v_string = NULL;
3617 }
3618}
3619
3620/*
3621 * "extend(list, list [, idx])" function
3622 * "extend(dict, dict [, action])" function
3623 */
3624 static void
3625f_extend(typval_T *argvars, typval_T *rettv)
3626{
3627 char_u *arg_errmsg = (char_u *)N_("extend() argument");
3628
3629 if (argvars[0].v_type == VAR_LIST && argvars[1].v_type == VAR_LIST)
3630 {
3631 list_T *l1, *l2;
3632 listitem_T *item;
3633 long before;
3634 int error = FALSE;
3635
3636 l1 = argvars[0].vval.v_list;
3637 l2 = argvars[1].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003638 if (l1 != NULL && !var_check_lock(l1->lv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003639 && l2 != NULL)
3640 {
3641 if (argvars[2].v_type != VAR_UNKNOWN)
3642 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003643 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003644 if (error)
3645 return; /* type error; errmsg already given */
3646
3647 if (before == l1->lv_len)
3648 item = NULL;
3649 else
3650 {
3651 item = list_find(l1, before);
3652 if (item == NULL)
3653 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003654 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003655 return;
3656 }
3657 }
3658 }
3659 else
3660 item = NULL;
3661 list_extend(l1, l2, item);
3662
3663 copy_tv(&argvars[0], rettv);
3664 }
3665 }
3666 else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
3667 {
3668 dict_T *d1, *d2;
3669 char_u *action;
3670 int i;
3671
3672 d1 = argvars[0].vval.v_dict;
3673 d2 = argvars[1].vval.v_dict;
Bram Moolenaar05c00c02019-02-11 22:00:11 +01003674 if (d1 != NULL && !var_check_lock(d1->dv_lock, arg_errmsg, TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003675 && d2 != NULL)
3676 {
3677 /* Check the third argument. */
3678 if (argvars[2].v_type != VAR_UNKNOWN)
3679 {
3680 static char *(av[]) = {"keep", "force", "error"};
3681
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003682 action = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003683 if (action == NULL)
3684 return; /* type error; errmsg already given */
3685 for (i = 0; i < 3; ++i)
3686 if (STRCMP(action, av[i]) == 0)
3687 break;
3688 if (i == 3)
3689 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003690 semsg(_(e_invarg2), action);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003691 return;
3692 }
3693 }
3694 else
3695 action = (char_u *)"force";
3696
3697 dict_extend(d1, d2, action);
3698
3699 copy_tv(&argvars[0], rettv);
3700 }
3701 }
3702 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003703 semsg(_(e_listdictarg), "extend()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003704}
3705
3706/*
3707 * "feedkeys()" function
3708 */
3709 static void
3710f_feedkeys(typval_T *argvars, typval_T *rettv UNUSED)
3711{
3712 int remap = TRUE;
3713 int insert = FALSE;
3714 char_u *keys, *flags;
3715 char_u nbuf[NUMBUFLEN];
3716 int typed = FALSE;
3717 int execute = FALSE;
3718 int dangerous = FALSE;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003719 int lowlevel = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003720 char_u *keys_esc;
3721
3722 /* This is not allowed in the sandbox. If the commands would still be
3723 * executed in the sandbox it would be OK, but it probably happens later,
3724 * when "sandbox" is no longer set. */
3725 if (check_secure())
3726 return;
3727
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003728 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003729
3730 if (argvars[1].v_type != VAR_UNKNOWN)
3731 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003732 flags = tv_get_string_buf(&argvars[1], nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003733 for ( ; *flags != NUL; ++flags)
3734 {
3735 switch (*flags)
3736 {
3737 case 'n': remap = FALSE; break;
3738 case 'm': remap = TRUE; break;
3739 case 't': typed = TRUE; break;
3740 case 'i': insert = TRUE; break;
3741 case 'x': execute = TRUE; break;
3742 case '!': dangerous = TRUE; break;
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003743 case 'L': lowlevel = TRUE; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003744 }
3745 }
3746 }
3747
3748 if (*keys != NUL || execute)
3749 {
3750 /* Need to escape K_SPECIAL and CSI before putting the string in the
3751 * typeahead buffer. */
3752 keys_esc = vim_strsave_escape_csi(keys);
3753 if (keys_esc != NULL)
3754 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003755 if (lowlevel)
3756 {
3757#ifdef USE_INPUT_BUF
3758 add_to_input_buf(keys, (int)STRLEN(keys));
3759#else
3760 emsg(_("E980: lowlevel input not supported"));
3761#endif
3762 }
3763 else
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003764 {
Bram Moolenaar5e66b422019-01-24 21:58:10 +01003765 ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003766 insert ? 0 : typebuf.tb_len, !typed, FALSE);
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003767 if (vgetc_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003768#ifdef FEAT_TIMERS
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003769 || timer_busy
Bram Moolenaar5d7be4f2017-06-25 13:40:17 +02003770#endif
Bram Moolenaar8d4ce562019-01-30 22:01:40 +01003771 )
3772 typebuf_was_filled = TRUE;
3773 }
3774 vim_free(keys_esc);
3775
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003776 if (execute)
3777 {
3778 int save_msg_scroll = msg_scroll;
3779
3780 /* Avoid a 1 second delay when the keys start Insert mode. */
3781 msg_scroll = FALSE;
3782
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003783 if (!dangerous)
3784 ++ex_normal_busy;
Bram Moolenaar586c70c2018-10-02 16:23:58 +02003785 exec_normal(TRUE, FALSE, TRUE);
Bram Moolenaarb2ac14c2018-05-01 18:47:59 +02003786 if (!dangerous)
3787 --ex_normal_busy;
3788
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003789 msg_scroll |= save_msg_scroll;
3790 }
3791 }
3792 }
3793}
3794
3795/*
3796 * "filereadable()" function
3797 */
3798 static void
3799f_filereadable(typval_T *argvars, typval_T *rettv)
3800{
3801 int fd;
3802 char_u *p;
3803 int n;
3804
3805#ifndef O_NONBLOCK
3806# define O_NONBLOCK 0
3807#endif
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003808 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003809 if (*p && !mch_isdir(p) && (fd = mch_open((char *)p,
3810 O_RDONLY | O_NONBLOCK, 0)) >= 0)
3811 {
3812 n = TRUE;
3813 close(fd);
3814 }
3815 else
3816 n = FALSE;
3817
3818 rettv->vval.v_number = n;
3819}
3820
3821/*
3822 * Return 0 for not writable, 1 for writable file, 2 for a dir which we have
3823 * rights to write into.
3824 */
3825 static void
3826f_filewritable(typval_T *argvars, typval_T *rettv)
3827{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003828 rettv->vval.v_number = filewritable(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003829}
3830
3831 static void
3832findfilendir(
3833 typval_T *argvars UNUSED,
3834 typval_T *rettv,
3835 int find_what UNUSED)
3836{
3837#ifdef FEAT_SEARCHPATH
3838 char_u *fname;
3839 char_u *fresult = NULL;
3840 char_u *path = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
3841 char_u *p;
3842 char_u pathbuf[NUMBUFLEN];
3843 int count = 1;
3844 int first = TRUE;
3845 int error = FALSE;
3846#endif
3847
3848 rettv->vval.v_string = NULL;
3849 rettv->v_type = VAR_STRING;
3850
3851#ifdef FEAT_SEARCHPATH
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003852 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003853
3854 if (argvars[1].v_type != VAR_UNKNOWN)
3855 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003856 p = tv_get_string_buf_chk(&argvars[1], pathbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003857 if (p == NULL)
3858 error = TRUE;
3859 else
3860 {
3861 if (*p != NUL)
3862 path = p;
3863
3864 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003865 count = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003866 }
3867 }
3868
3869 if (count < 0 && rettv_list_alloc(rettv) == FAIL)
3870 error = TRUE;
3871
3872 if (*fname != NUL && !error)
3873 {
3874 do
3875 {
3876 if (rettv->v_type == VAR_STRING || rettv->v_type == VAR_LIST)
3877 vim_free(fresult);
3878 fresult = find_file_in_path_option(first ? fname : NULL,
3879 first ? (int)STRLEN(fname) : 0,
3880 0, first, path,
3881 find_what,
3882 curbuf->b_ffname,
3883 find_what == FINDFILE_DIR
3884 ? (char_u *)"" : curbuf->b_p_sua);
3885 first = FALSE;
3886
3887 if (fresult != NULL && rettv->v_type == VAR_LIST)
3888 list_append_string(rettv->vval.v_list, fresult, -1);
3889
3890 } while ((rettv->v_type == VAR_LIST || --count > 0) && fresult != NULL);
3891 }
3892
3893 if (rettv->v_type == VAR_STRING)
3894 rettv->vval.v_string = fresult;
3895#endif
3896}
3897
3898/*
3899 * "filter()" function
3900 */
3901 static void
3902f_filter(typval_T *argvars, typval_T *rettv)
3903{
3904 filter_map(argvars, rettv, FALSE);
3905}
3906
3907/*
3908 * "finddir({fname}[, {path}[, {count}]])" function
3909 */
3910 static void
3911f_finddir(typval_T *argvars, typval_T *rettv)
3912{
3913 findfilendir(argvars, rettv, FINDFILE_DIR);
3914}
3915
3916/*
3917 * "findfile({fname}[, {path}[, {count}]])" function
3918 */
3919 static void
3920f_findfile(typval_T *argvars, typval_T *rettv)
3921{
3922 findfilendir(argvars, rettv, FINDFILE_FILE);
3923}
3924
3925#ifdef FEAT_FLOAT
3926/*
3927 * "float2nr({float})" function
3928 */
3929 static void
3930f_float2nr(typval_T *argvars, typval_T *rettv)
3931{
3932 float_T f = 0.0;
3933
3934 if (get_float_arg(argvars, &f) == OK)
3935 {
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003936 if (f <= -VARNUM_MAX + DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003937 rettv->vval.v_number = -VARNUM_MAX;
Bram Moolenaar863e80b2017-06-04 20:30:00 +02003938 else if (f >= VARNUM_MAX - DBL_EPSILON)
Bram Moolenaar7a40ea22017-01-22 18:34:57 +01003939 rettv->vval.v_number = VARNUM_MAX;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003940 else
3941 rettv->vval.v_number = (varnumber_T)f;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003942 }
3943}
3944
3945/*
3946 * "floor({float})" function
3947 */
3948 static void
3949f_floor(typval_T *argvars, typval_T *rettv)
3950{
3951 float_T f = 0.0;
3952
3953 rettv->v_type = VAR_FLOAT;
3954 if (get_float_arg(argvars, &f) == OK)
3955 rettv->vval.v_float = floor(f);
3956 else
3957 rettv->vval.v_float = 0.0;
3958}
3959
3960/*
3961 * "fmod()" function
3962 */
3963 static void
3964f_fmod(typval_T *argvars, typval_T *rettv)
3965{
3966 float_T fx = 0.0, fy = 0.0;
3967
3968 rettv->v_type = VAR_FLOAT;
3969 if (get_float_arg(argvars, &fx) == OK
3970 && get_float_arg(&argvars[1], &fy) == OK)
3971 rettv->vval.v_float = fmod(fx, fy);
3972 else
3973 rettv->vval.v_float = 0.0;
3974}
3975#endif
3976
3977/*
3978 * "fnameescape({string})" function
3979 */
3980 static void
3981f_fnameescape(typval_T *argvars, typval_T *rettv)
3982{
3983 rettv->vval.v_string = vim_strsave_fnameescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01003984 tv_get_string(&argvars[0]), FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02003985 rettv->v_type = VAR_STRING;
3986}
3987
3988/*
3989 * "fnamemodify({fname}, {mods})" function
3990 */
3991 static void
3992f_fnamemodify(typval_T *argvars, typval_T *rettv)
3993{
3994 char_u *fname;
3995 char_u *mods;
3996 int usedlen = 0;
3997 int len;
3998 char_u *fbuf = NULL;
3999 char_u buf[NUMBUFLEN];
4000
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004001 fname = tv_get_string_chk(&argvars[0]);
4002 mods = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004003 if (fname == NULL || mods == NULL)
4004 fname = NULL;
4005 else
4006 {
4007 len = (int)STRLEN(fname);
Bram Moolenaar00136dc2018-07-25 21:19:13 +02004008 (void)modify_fname(mods, FALSE, &usedlen, &fname, &fbuf, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004009 }
4010
4011 rettv->v_type = VAR_STRING;
4012 if (fname == NULL)
4013 rettv->vval.v_string = NULL;
4014 else
4015 rettv->vval.v_string = vim_strnsave(fname, len);
4016 vim_free(fbuf);
4017}
4018
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004019/*
4020 * "foldclosed()" function
4021 */
4022 static void
4023foldclosed_both(
4024 typval_T *argvars UNUSED,
4025 typval_T *rettv,
4026 int end UNUSED)
4027{
4028#ifdef FEAT_FOLDING
4029 linenr_T lnum;
4030 linenr_T first, last;
4031
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004032 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004033 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4034 {
4035 if (hasFoldingWin(curwin, lnum, &first, &last, FALSE, NULL))
4036 {
4037 if (end)
4038 rettv->vval.v_number = (varnumber_T)last;
4039 else
4040 rettv->vval.v_number = (varnumber_T)first;
4041 return;
4042 }
4043 }
4044#endif
4045 rettv->vval.v_number = -1;
4046}
4047
4048/*
4049 * "foldclosed()" function
4050 */
4051 static void
4052f_foldclosed(typval_T *argvars, typval_T *rettv)
4053{
4054 foldclosed_both(argvars, rettv, FALSE);
4055}
4056
4057/*
4058 * "foldclosedend()" function
4059 */
4060 static void
4061f_foldclosedend(typval_T *argvars, typval_T *rettv)
4062{
4063 foldclosed_both(argvars, rettv, TRUE);
4064}
4065
4066/*
4067 * "foldlevel()" function
4068 */
4069 static void
4070f_foldlevel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4071{
4072#ifdef FEAT_FOLDING
4073 linenr_T lnum;
4074
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004075 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004076 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4077 rettv->vval.v_number = foldLevel(lnum);
4078#endif
4079}
4080
4081/*
4082 * "foldtext()" function
4083 */
4084 static void
4085f_foldtext(typval_T *argvars UNUSED, typval_T *rettv)
4086{
4087#ifdef FEAT_FOLDING
4088 linenr_T foldstart;
4089 linenr_T foldend;
4090 char_u *dashes;
4091 linenr_T lnum;
4092 char_u *s;
4093 char_u *r;
4094 int len;
4095 char *txt;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004096 long count;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004097#endif
4098
4099 rettv->v_type = VAR_STRING;
4100 rettv->vval.v_string = NULL;
4101#ifdef FEAT_FOLDING
4102 foldstart = (linenr_T)get_vim_var_nr(VV_FOLDSTART);
4103 foldend = (linenr_T)get_vim_var_nr(VV_FOLDEND);
4104 dashes = get_vim_var_str(VV_FOLDDASHES);
4105 if (foldstart > 0 && foldend <= curbuf->b_ml.ml_line_count
4106 && dashes != NULL)
4107 {
4108 /* Find first non-empty line in the fold. */
Bram Moolenaar69aa0992016-07-17 22:33:53 +02004109 for (lnum = foldstart; lnum < foldend; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004110 if (!linewhite(lnum))
4111 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004112
4113 /* Find interesting text in this line. */
4114 s = skipwhite(ml_get(lnum));
4115 /* skip C comment-start */
4116 if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
4117 {
4118 s = skipwhite(s + 2);
4119 if (*skipwhite(s) == NUL
4120 && lnum + 1 < (linenr_T)get_vim_var_nr(VV_FOLDEND))
4121 {
4122 s = skipwhite(ml_get(lnum + 1));
4123 if (*s == '*')
4124 s = skipwhite(s + 1);
4125 }
4126 }
Bram Moolenaaree695f72016-08-03 22:08:45 +02004127 count = (long)(foldend - foldstart + 1);
Bram Moolenaar1c465442017-03-12 20:10:05 +01004128 txt = NGETTEXT("+-%s%3ld line: ", "+-%s%3ld lines: ", count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004129 r = alloc((unsigned)(STRLEN(txt)
4130 + STRLEN(dashes) /* for %s */
4131 + 20 /* for %3ld */
4132 + STRLEN(s))); /* concatenated */
4133 if (r != NULL)
4134 {
Bram Moolenaaree695f72016-08-03 22:08:45 +02004135 sprintf((char *)r, txt, dashes, count);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004136 len = (int)STRLEN(r);
4137 STRCAT(r, s);
4138 /* remove 'foldmarker' and 'commentstring' */
4139 foldtext_cleanup(r + len);
4140 rettv->vval.v_string = r;
4141 }
4142 }
4143#endif
4144}
4145
4146/*
4147 * "foldtextresult(lnum)" function
4148 */
4149 static void
4150f_foldtextresult(typval_T *argvars UNUSED, typval_T *rettv)
4151{
4152#ifdef FEAT_FOLDING
4153 linenr_T lnum;
4154 char_u *text;
Bram Moolenaaree695f72016-08-03 22:08:45 +02004155 char_u buf[FOLD_TEXT_LEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004156 foldinfo_T foldinfo;
4157 int fold_count;
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004158 static int entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004159#endif
4160
4161 rettv->v_type = VAR_STRING;
4162 rettv->vval.v_string = NULL;
4163#ifdef FEAT_FOLDING
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004164 if (entered)
4165 return; /* reject recursive use */
4166 entered = TRUE;
4167
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004168 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004169 /* treat illegal types and illegal string values for {lnum} the same */
4170 if (lnum < 0)
4171 lnum = 0;
4172 fold_count = foldedCount(curwin, lnum, &foldinfo);
4173 if (fold_count > 0)
4174 {
Bram Moolenaarc6aafba2017-03-21 17:09:10 +01004175 text = get_foldtext(curwin, lnum, lnum + fold_count - 1,
4176 &foldinfo, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004177 if (text == buf)
4178 text = vim_strsave(text);
4179 rettv->vval.v_string = text;
4180 }
Bram Moolenaar495b7dd2017-09-16 17:19:22 +02004181
4182 entered = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004183#endif
4184}
4185
4186/*
4187 * "foreground()" function
4188 */
4189 static void
4190f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
4191{
4192#ifdef FEAT_GUI
4193 if (gui.in_use)
4194 gui_mch_set_foreground();
4195#else
Bram Moolenaar4f974752019-02-17 17:44:42 +01004196# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004197 win32_set_foreground();
4198# endif
4199#endif
4200}
4201
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004202 static void
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004203common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004204{
4205 char_u *s;
4206 char_u *name;
4207 int use_string = FALSE;
4208 partial_T *arg_pt = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004209 char_u *trans_name = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004210
4211 if (argvars[0].v_type == VAR_FUNC)
4212 {
4213 /* function(MyFunc, [arg], dict) */
4214 s = argvars[0].vval.v_string;
4215 }
4216 else if (argvars[0].v_type == VAR_PARTIAL
4217 && argvars[0].vval.v_partial != NULL)
4218 {
4219 /* function(dict.MyFunc, [arg]) */
4220 arg_pt = argvars[0].vval.v_partial;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004221 s = partial_name(arg_pt);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004222 }
4223 else
4224 {
4225 /* function('MyFunc', [arg], dict) */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004226 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004227 use_string = TRUE;
4228 }
4229
Bram Moolenaar843b8842016-08-21 14:36:15 +02004230 if ((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL) || is_funcref)
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004231 {
4232 name = s;
4233 trans_name = trans_function_name(&name, FALSE,
4234 TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
4235 if (*name != NUL)
4236 s = NULL;
4237 }
4238
Bram Moolenaar843b8842016-08-21 14:36:15 +02004239 if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))
4240 || (is_funcref && trans_name == NULL))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004241 semsg(_(e_invarg2), use_string ? tv_get_string(&argvars[0]) : s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004242 /* Don't check an autoload name for existence here. */
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004243 else if (trans_name != NULL && (is_funcref
4244 ? find_func(trans_name) == NULL
4245 : !translated_function_exists(trans_name)))
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004246 semsg(_("E700: Unknown function: %s"), s);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004247 else
4248 {
4249 int dict_idx = 0;
4250 int arg_idx = 0;
4251 list_T *list = NULL;
4252
4253 if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
4254 {
4255 char sid_buf[25];
4256 int off = *s == 's' ? 2 : 5;
4257
4258 /* Expand s: and <SID> into <SNR>nr_, so that the function can
4259 * also be called from another script. Using trans_function_name()
4260 * would also work, but some plugins depend on the name being
4261 * printable text. */
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02004262 sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004263 name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
4264 if (name != NULL)
4265 {
4266 STRCPY(name, sid_buf);
4267 STRCAT(name, s + off);
4268 }
4269 }
4270 else
4271 name = vim_strsave(s);
4272
4273 if (argvars[1].v_type != VAR_UNKNOWN)
4274 {
4275 if (argvars[2].v_type != VAR_UNKNOWN)
4276 {
4277 /* function(name, [args], dict) */
4278 arg_idx = 1;
4279 dict_idx = 2;
4280 }
4281 else if (argvars[1].v_type == VAR_DICT)
4282 /* function(name, dict) */
4283 dict_idx = 1;
4284 else
4285 /* function(name, [args]) */
4286 arg_idx = 1;
4287 if (dict_idx > 0)
4288 {
4289 if (argvars[dict_idx].v_type != VAR_DICT)
4290 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004291 emsg(_("E922: expected a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004292 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004293 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004294 }
4295 if (argvars[dict_idx].vval.v_dict == NULL)
4296 dict_idx = 0;
4297 }
4298 if (arg_idx > 0)
4299 {
4300 if (argvars[arg_idx].v_type != VAR_LIST)
4301 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004302 emsg(_("E923: Second argument of function() must be a list or a dict"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004303 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004304 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004305 }
4306 list = argvars[arg_idx].vval.v_list;
4307 if (list == NULL || list->lv_len == 0)
4308 arg_idx = 0;
4309 }
4310 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004311 if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004312 {
4313 partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
4314
4315 /* result is a VAR_PARTIAL */
4316 if (pt == NULL)
4317 vim_free(name);
4318 else
4319 {
4320 if (arg_idx > 0 || (arg_pt != NULL && arg_pt->pt_argc > 0))
4321 {
4322 listitem_T *li;
4323 int i = 0;
4324 int arg_len = 0;
4325 int lv_len = 0;
4326
4327 if (arg_pt != NULL)
4328 arg_len = arg_pt->pt_argc;
4329 if (list != NULL)
4330 lv_len = list->lv_len;
4331 pt->pt_argc = arg_len + lv_len;
4332 pt->pt_argv = (typval_T *)alloc(
4333 sizeof(typval_T) * pt->pt_argc);
4334 if (pt->pt_argv == NULL)
4335 {
4336 vim_free(pt);
4337 vim_free(name);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004338 goto theend;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004339 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004340 for (i = 0; i < arg_len; i++)
4341 copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
4342 if (lv_len > 0)
4343 for (li = list->lv_first; li != NULL;
4344 li = li->li_next)
4345 copy_tv(&li->li_tv, &pt->pt_argv[i++]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004346 }
4347
4348 /* For "function(dict.func, [], dict)" and "func" is a partial
4349 * use "dict". That is backwards compatible. */
4350 if (dict_idx > 0)
4351 {
4352 /* The dict is bound explicitly, pt_auto is FALSE. */
4353 pt->pt_dict = argvars[dict_idx].vval.v_dict;
4354 ++pt->pt_dict->dv_refcount;
4355 }
4356 else if (arg_pt != NULL)
4357 {
4358 /* If the dict was bound automatically the result is also
4359 * bound automatically. */
4360 pt->pt_dict = arg_pt->pt_dict;
4361 pt->pt_auto = arg_pt->pt_auto;
4362 if (pt->pt_dict != NULL)
4363 ++pt->pt_dict->dv_refcount;
4364 }
4365
4366 pt->pt_refcount = 1;
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004367 if (arg_pt != NULL && arg_pt->pt_func != NULL)
4368 {
4369 pt->pt_func = arg_pt->pt_func;
4370 func_ptr_ref(pt->pt_func);
4371 vim_free(name);
4372 }
4373 else if (is_funcref)
4374 {
4375 pt->pt_func = find_func(trans_name);
4376 func_ptr_ref(pt->pt_func);
4377 vim_free(name);
4378 }
4379 else
4380 {
4381 pt->pt_name = name;
4382 func_ref(name);
4383 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004384 }
4385 rettv->v_type = VAR_PARTIAL;
4386 rettv->vval.v_partial = pt;
4387 }
4388 else
4389 {
4390 /* result is a VAR_FUNC */
4391 rettv->v_type = VAR_FUNC;
4392 rettv->vval.v_string = name;
4393 func_ref(name);
4394 }
4395 }
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004396theend:
4397 vim_free(trans_name);
4398}
4399
4400/*
4401 * "funcref()" function
4402 */
4403 static void
4404f_funcref(typval_T *argvars, typval_T *rettv)
4405{
4406 common_function(argvars, rettv, TRUE);
4407}
4408
4409/*
4410 * "function()" function
4411 */
4412 static void
4413f_function(typval_T *argvars, typval_T *rettv)
4414{
4415 common_function(argvars, rettv, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004416}
4417
4418/*
4419 * "garbagecollect()" function
4420 */
4421 static void
4422f_garbagecollect(typval_T *argvars, typval_T *rettv UNUSED)
4423{
4424 /* This is postponed until we are back at the toplevel, because we may be
4425 * using Lists and Dicts internally. E.g.: ":echo [garbagecollect()]". */
4426 want_garbage_collect = TRUE;
4427
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004428 if (argvars[0].v_type != VAR_UNKNOWN && tv_get_number(&argvars[0]) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004429 garbage_collect_at_exit = TRUE;
4430}
4431
4432/*
4433 * "get()" function
4434 */
4435 static void
4436f_get(typval_T *argvars, typval_T *rettv)
4437{
4438 listitem_T *li;
4439 list_T *l;
4440 dictitem_T *di;
4441 dict_T *d;
4442 typval_T *tv = NULL;
4443
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004444 if (argvars[0].v_type == VAR_BLOB)
4445 {
4446 int error = FALSE;
4447 int idx = tv_get_number_chk(&argvars[1], &error);
4448
4449 if (!error)
4450 {
4451 rettv->v_type = VAR_NUMBER;
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004452 if (idx < 0)
4453 idx = blob_len(argvars[0].vval.v_blob) + idx;
4454 if (idx < 0 || idx >= blob_len(argvars[0].vval.v_blob))
4455 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004456 else
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004457 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004458 rettv->vval.v_number = blob_get(argvars[0].vval.v_blob, idx);
Bram Moolenaar2ea773b2019-01-15 22:16:42 +01004459 tv = rettv;
4460 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01004461 }
4462 }
4463 else if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004464 {
4465 if ((l = argvars[0].vval.v_list) != NULL)
4466 {
4467 int error = FALSE;
4468
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004469 li = list_find(l, (long)tv_get_number_chk(&argvars[1], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004470 if (!error && li != NULL)
4471 tv = &li->li_tv;
4472 }
4473 }
4474 else if (argvars[0].v_type == VAR_DICT)
4475 {
4476 if ((d = argvars[0].vval.v_dict) != NULL)
4477 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004478 di = dict_find(d, tv_get_string(&argvars[1]), -1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004479 if (di != NULL)
4480 tv = &di->di_tv;
4481 }
4482 }
4483 else if (argvars[0].v_type == VAR_PARTIAL || argvars[0].v_type == VAR_FUNC)
4484 {
4485 partial_T *pt;
4486 partial_T fref_pt;
4487
4488 if (argvars[0].v_type == VAR_PARTIAL)
4489 pt = argvars[0].vval.v_partial;
4490 else
4491 {
4492 vim_memset(&fref_pt, 0, sizeof(fref_pt));
4493 fref_pt.pt_name = argvars[0].vval.v_string;
4494 pt = &fref_pt;
4495 }
4496
4497 if (pt != NULL)
4498 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004499 char_u *what = tv_get_string(&argvars[1]);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004500 char_u *n;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004501
4502 if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
4503 {
4504 rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004505 n = partial_name(pt);
4506 if (n == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004507 rettv->vval.v_string = NULL;
4508 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +02004509 {
4510 rettv->vval.v_string = vim_strsave(n);
4511 if (rettv->v_type == VAR_FUNC)
4512 func_ref(rettv->vval.v_string);
4513 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004514 }
4515 else if (STRCMP(what, "dict") == 0)
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004516 rettv_dict_set(rettv, pt->pt_dict);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004517 else if (STRCMP(what, "args") == 0)
4518 {
4519 rettv->v_type = VAR_LIST;
4520 if (rettv_list_alloc(rettv) == OK)
4521 {
4522 int i;
4523
4524 for (i = 0; i < pt->pt_argc; ++i)
4525 list_append_tv(rettv->vval.v_list, &pt->pt_argv[i]);
4526 }
4527 }
4528 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01004529 semsg(_(e_invarg2), what);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004530 return;
4531 }
4532 }
4533 else
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01004534 semsg(_(e_listdictblobarg), "get()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004535
4536 if (tv == NULL)
4537 {
4538 if (argvars[2].v_type != VAR_UNKNOWN)
4539 copy_tv(&argvars[2], rettv);
4540 }
4541 else
4542 copy_tv(tv, rettv);
4543}
4544
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004545/*
4546 * Returns buffer options, variables and other attributes in a dictionary.
4547 */
4548 static dict_T *
4549get_buffer_info(buf_T *buf)
4550{
4551 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004552 tabpage_T *tp;
4553 win_T *wp;
4554 list_T *windows;
4555
4556 dict = dict_alloc();
4557 if (dict == NULL)
4558 return NULL;
4559
Bram Moolenaare0be1672018-07-08 16:50:37 +02004560 dict_add_number(dict, "bufnr", buf->b_fnum);
4561 dict_add_string(dict, "name", buf->b_ffname);
4562 dict_add_number(dict, "lnum", buf == curbuf ? curwin->w_cursor.lnum
4563 : buflist_findlnum(buf));
4564 dict_add_number(dict, "loaded", buf->b_ml.ml_mfp != NULL);
4565 dict_add_number(dict, "listed", buf->b_p_bl);
4566 dict_add_number(dict, "changed", bufIsChanged(buf));
4567 dict_add_number(dict, "changedtick", CHANGEDTICK(buf));
4568 dict_add_number(dict, "hidden",
4569 buf->b_ml.ml_mfp != NULL && buf->b_nwindows == 0);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004570
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02004571 /* Get a reference to buffer variables */
4572 dict_add_dict(dict, "variables", buf->b_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004573
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004574 /* List of windows displaying this buffer */
4575 windows = list_alloc();
4576 if (windows != NULL)
4577 {
4578 FOR_ALL_TAB_WINDOWS(tp, wp)
4579 if (wp->w_buffer == buf)
4580 list_append_number(windows, (varnumber_T)wp->w_id);
4581 dict_add_list(dict, "windows", windows);
4582 }
4583
4584#ifdef FEAT_SIGNS
4585 if (buf->b_signlist != NULL)
4586 {
4587 /* List of signs placed in this buffer */
4588 list_T *signs = list_alloc();
4589 if (signs != NULL)
4590 {
4591 get_buffer_signs(buf, signs);
4592 dict_add_list(dict, "signs", signs);
4593 }
4594 }
4595#endif
4596
4597 return dict;
4598}
4599
4600/*
4601 * "getbufinfo()" function
4602 */
4603 static void
4604f_getbufinfo(typval_T *argvars, typval_T *rettv)
4605{
4606 buf_T *buf = NULL;
4607 buf_T *argbuf = NULL;
4608 dict_T *d;
4609 int filtered = FALSE;
4610 int sel_buflisted = FALSE;
4611 int sel_bufloaded = FALSE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004612 int sel_bufmodified = FALSE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004613
4614 if (rettv_list_alloc(rettv) != OK)
4615 return;
4616
4617 /* List of all the buffers or selected buffers */
4618 if (argvars[0].v_type == VAR_DICT)
4619 {
4620 dict_T *sel_d = argvars[0].vval.v_dict;
4621
4622 if (sel_d != NULL)
4623 {
4624 dictitem_T *di;
4625
4626 filtered = TRUE;
4627
4628 di = dict_find(sel_d, (char_u *)"buflisted", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004629 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004630 sel_buflisted = TRUE;
4631
4632 di = dict_find(sel_d, (char_u *)"bufloaded", -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_bufloaded = TRUE;
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004635
4636 di = dict_find(sel_d, (char_u *)"bufmodified", -1);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004637 if (di != NULL && tv_get_number(&di->di_tv))
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004638 sel_bufmodified = TRUE;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004639 }
4640 }
4641 else if (argvars[0].v_type != VAR_UNKNOWN)
4642 {
4643 /* Information about one buffer. Argument specifies the buffer */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004644 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004645 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004646 argbuf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004647 --emsg_off;
4648 if (argbuf == NULL)
4649 return;
4650 }
4651
4652 /* Return information about all the buffers or a specified buffer */
Bram Moolenaar386600f2016-08-15 22:16:25 +02004653 FOR_ALL_BUFFERS(buf)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004654 {
4655 if (argbuf != NULL && argbuf != buf)
4656 continue;
4657 if (filtered && ((sel_bufloaded && buf->b_ml.ml_mfp == NULL)
Bram Moolenaar8e6a31d2017-12-10 21:06:22 +01004658 || (sel_buflisted && !buf->b_p_bl)
4659 || (sel_bufmodified && !buf->b_changed)))
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02004660 continue;
4661
4662 d = get_buffer_info(buf);
4663 if (d != NULL)
4664 list_append_dict(rettv->vval.v_list, d);
4665 if (argbuf != NULL)
4666 return;
4667 }
4668}
4669
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004670/*
4671 * Get line or list of lines from buffer "buf" into "rettv".
4672 * Return a range (from start to end) of lines in rettv from the specified
4673 * buffer.
4674 * If 'retlist' is TRUE, then the lines are returned as a Vim List.
4675 */
4676 static void
4677get_buffer_lines(
4678 buf_T *buf,
4679 linenr_T start,
4680 linenr_T end,
4681 int retlist,
4682 typval_T *rettv)
4683{
4684 char_u *p;
4685
4686 rettv->v_type = VAR_STRING;
4687 rettv->vval.v_string = NULL;
4688 if (retlist && rettv_list_alloc(rettv) == FAIL)
4689 return;
4690
4691 if (buf == NULL || buf->b_ml.ml_mfp == NULL || start < 0)
4692 return;
4693
4694 if (!retlist)
4695 {
4696 if (start >= 1 && start <= buf->b_ml.ml_line_count)
4697 p = ml_get_buf(buf, start, FALSE);
4698 else
4699 p = (char_u *)"";
4700 rettv->vval.v_string = vim_strsave(p);
4701 }
4702 else
4703 {
4704 if (end < start)
4705 return;
4706
4707 if (start < 1)
4708 start = 1;
4709 if (end > buf->b_ml.ml_line_count)
4710 end = buf->b_ml.ml_line_count;
4711 while (start <= end)
4712 if (list_append_string(rettv->vval.v_list,
4713 ml_get_buf(buf, start++, FALSE), -1) == FAIL)
4714 break;
4715 }
4716}
4717
4718/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004719 * "getbufline()" function
4720 */
4721 static void
4722f_getbufline(typval_T *argvars, typval_T *rettv)
4723{
4724 linenr_T lnum;
4725 linenr_T end;
4726 buf_T *buf;
4727
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004728 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004729 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004730 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004731 --emsg_off;
4732
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004733 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004734 if (argvars[2].v_type == VAR_UNKNOWN)
4735 end = lnum;
4736 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004737 end = tv_get_lnum_buf(&argvars[2], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004738
4739 get_buffer_lines(buf, lnum, end, TRUE, rettv);
4740}
4741
4742/*
4743 * "getbufvar()" function
4744 */
4745 static void
4746f_getbufvar(typval_T *argvars, typval_T *rettv)
4747{
4748 buf_T *buf;
4749 buf_T *save_curbuf;
4750 char_u *varname;
4751 dictitem_T *v;
4752 int done = FALSE;
4753
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004754 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
4755 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004756 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004757 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004758
4759 rettv->v_type = VAR_STRING;
4760 rettv->vval.v_string = NULL;
4761
4762 if (buf != NULL && varname != NULL)
4763 {
4764 /* set curbuf to be our buf, temporarily */
4765 save_curbuf = curbuf;
4766 curbuf = buf;
4767
Bram Moolenaar30567352016-08-27 21:25:44 +02004768 if (*varname == '&')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004769 {
Bram Moolenaar30567352016-08-27 21:25:44 +02004770 if (varname[1] == NUL)
4771 {
4772 /* get all buffer-local options in a dict */
4773 dict_T *opts = get_winbuf_options(TRUE);
4774
4775 if (opts != NULL)
4776 {
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02004777 rettv_dict_set(rettv, opts);
Bram Moolenaar30567352016-08-27 21:25:44 +02004778 done = TRUE;
4779 }
4780 }
4781 else if (get_option_tv(&varname, rettv, TRUE) == OK)
4782 /* buffer-local-option */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004783 done = TRUE;
4784 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004785 else
4786 {
4787 /* Look up the variable. */
4788 /* Let getbufvar({nr}, "") return the "b:" dictionary. */
4789 v = find_var_in_ht(&curbuf->b_vars->dv_hashtab,
4790 'b', varname, FALSE);
4791 if (v != NULL)
4792 {
4793 copy_tv(&v->di_tv, rettv);
4794 done = TRUE;
4795 }
4796 }
4797
4798 /* restore previous notion of curbuf */
4799 curbuf = save_curbuf;
4800 }
4801
4802 if (!done && argvars[2].v_type != VAR_UNKNOWN)
4803 /* use the default value */
4804 copy_tv(&argvars[2], rettv);
4805
4806 --emsg_off;
4807}
4808
4809/*
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004810 * "getchangelist()" function
4811 */
4812 static void
4813f_getchangelist(typval_T *argvars, typval_T *rettv)
4814{
4815#ifdef FEAT_JUMPLIST
4816 buf_T *buf;
4817 int i;
4818 list_T *l;
4819 dict_T *d;
4820#endif
4821
4822 if (rettv_list_alloc(rettv) != OK)
4823 return;
4824
4825#ifdef FEAT_JUMPLIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004826 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004827 ++emsg_off;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01004828 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar341a64c2018-02-13 19:21:17 +01004829 --emsg_off;
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004830 if (buf == NULL)
4831 return;
4832
4833 l = list_alloc();
4834 if (l == NULL)
4835 return;
4836
4837 if (list_append_list(rettv->vval.v_list, l) == FAIL)
4838 return;
4839 /*
4840 * The current window change list index tracks only the position in the
4841 * current buffer change list. For other buffers, use the change list
4842 * length as the current index.
4843 */
4844 list_append_number(rettv->vval.v_list,
4845 (varnumber_T)((buf == curwin->w_buffer)
4846 ? curwin->w_changelistidx : buf->b_changelistlen));
4847
4848 for (i = 0; i < buf->b_changelistlen; ++i)
4849 {
4850 if (buf->b_changelist[i].lnum == 0)
4851 continue;
4852 if ((d = dict_alloc()) == NULL)
4853 return;
4854 if (list_append_dict(l, d) == FAIL)
4855 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02004856 dict_add_number(d, "lnum", (long)buf->b_changelist[i].lnum);
4857 dict_add_number(d, "col", (long)buf->b_changelist[i].col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02004858 dict_add_number(d, "coladd", (long)buf->b_changelist[i].coladd);
Bram Moolenaar07ad8162018-02-13 13:59:59 +01004859 }
4860#endif
4861}
4862/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004863 * "getchar()" function
4864 */
4865 static void
4866f_getchar(typval_T *argvars, typval_T *rettv)
4867{
4868 varnumber_T n;
4869 int error = FALSE;
4870
Bram Moolenaar84d93902018-09-11 20:10:20 +02004871#ifdef MESSAGE_QUEUE
4872 // vpeekc() used to check for messages, but that caused problems, invoking
4873 // a callback where it was not expected. Some plugins use getchar(1) in a
4874 // loop to await a message, therefore make sure we check for messages here.
4875 parse_queued_messages();
4876#endif
4877
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004878 /* Position the cursor. Needed after a message that ends in a space. */
4879 windgoto(msg_row, msg_col);
4880
4881 ++no_mapping;
4882 ++allow_keys;
4883 for (;;)
4884 {
4885 if (argvars[0].v_type == VAR_UNKNOWN)
4886 /* getchar(): blocking wait. */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004887 n = plain_vgetc();
Bram Moolenaard155d7a2018-12-21 16:04:21 +01004888 else if (tv_get_number_chk(&argvars[0], &error) == 1)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004889 /* getchar(1): only check if char avail */
4890 n = vpeekc_any();
4891 else if (error || vpeekc_any() == NUL)
4892 /* illegal argument or getchar(0) and no char avail: return zero */
4893 n = 0;
4894 else
4895 /* getchar(0) and char avail: return char */
Bram Moolenaarec2da362017-01-21 20:04:22 +01004896 n = plain_vgetc();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004897
4898 if (n == K_IGNORE)
4899 continue;
4900 break;
4901 }
4902 --no_mapping;
4903 --allow_keys;
4904
4905 set_vim_var_nr(VV_MOUSE_WIN, 0);
4906 set_vim_var_nr(VV_MOUSE_WINID, 0);
4907 set_vim_var_nr(VV_MOUSE_LNUM, 0);
4908 set_vim_var_nr(VV_MOUSE_COL, 0);
4909
4910 rettv->vval.v_number = n;
4911 if (IS_SPECIAL(n) || mod_mask != 0)
4912 {
4913 char_u temp[10]; /* modifier: 3, mbyte-char: 6, NUL: 1 */
4914 int i = 0;
4915
4916 /* Turn a special key into three bytes, plus modifier. */
4917 if (mod_mask != 0)
4918 {
4919 temp[i++] = K_SPECIAL;
4920 temp[i++] = KS_MODIFIER;
4921 temp[i++] = mod_mask;
4922 }
4923 if (IS_SPECIAL(n))
4924 {
4925 temp[i++] = K_SPECIAL;
4926 temp[i++] = K_SECOND(n);
4927 temp[i++] = K_THIRD(n);
4928 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004929 else if (has_mbyte)
4930 i += (*mb_char2bytes)(n, temp + i);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004931 else
4932 temp[i++] = n;
4933 temp[i++] = NUL;
4934 rettv->v_type = VAR_STRING;
4935 rettv->vval.v_string = vim_strsave(temp);
4936
4937#ifdef FEAT_MOUSE
4938 if (is_mouse_key(n))
4939 {
4940 int row = mouse_row;
4941 int col = mouse_col;
4942 win_T *win;
4943 linenr_T lnum;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004944 win_T *wp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004945 int winnr = 1;
4946
4947 if (row >= 0 && col >= 0)
4948 {
4949 /* Find the window at the mouse coordinates and compute the
4950 * text position. */
4951 win = mouse_find_win(&row, &col);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02004952 if (win == NULL)
4953 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004954 (void)mouse_comp_pos(win, &row, &col, &lnum);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004955 for (wp = firstwin; wp != win; wp = wp->w_next)
4956 ++winnr;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004957 set_vim_var_nr(VV_MOUSE_WIN, winnr);
4958 set_vim_var_nr(VV_MOUSE_WINID, win->w_id);
4959 set_vim_var_nr(VV_MOUSE_LNUM, lnum);
4960 set_vim_var_nr(VV_MOUSE_COL, col + 1);
4961 }
4962 }
4963#endif
4964 }
4965}
4966
4967/*
4968 * "getcharmod()" function
4969 */
4970 static void
4971f_getcharmod(typval_T *argvars UNUSED, typval_T *rettv)
4972{
4973 rettv->vval.v_number = mod_mask;
4974}
4975
4976/*
4977 * "getcharsearch()" function
4978 */
4979 static void
4980f_getcharsearch(typval_T *argvars UNUSED, typval_T *rettv)
4981{
4982 if (rettv_dict_alloc(rettv) != FAIL)
4983 {
4984 dict_T *dict = rettv->vval.v_dict;
4985
Bram Moolenaare0be1672018-07-08 16:50:37 +02004986 dict_add_string(dict, "char", last_csearch());
4987 dict_add_number(dict, "forward", last_csearch_forward());
4988 dict_add_number(dict, "until", last_csearch_until());
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02004989 }
4990}
4991
4992/*
4993 * "getcmdline()" function
4994 */
4995 static void
4996f_getcmdline(typval_T *argvars UNUSED, typval_T *rettv)
4997{
4998 rettv->v_type = VAR_STRING;
4999 rettv->vval.v_string = get_cmdline_str();
5000}
5001
5002/*
5003 * "getcmdpos()" function
5004 */
5005 static void
5006f_getcmdpos(typval_T *argvars UNUSED, typval_T *rettv)
5007{
5008 rettv->vval.v_number = get_cmdline_pos() + 1;
5009}
5010
5011/*
5012 * "getcmdtype()" function
5013 */
5014 static void
5015f_getcmdtype(typval_T *argvars UNUSED, typval_T *rettv)
5016{
5017 rettv->v_type = VAR_STRING;
5018 rettv->vval.v_string = alloc(2);
5019 if (rettv->vval.v_string != NULL)
5020 {
5021 rettv->vval.v_string[0] = get_cmdline_type();
5022 rettv->vval.v_string[1] = NUL;
5023 }
5024}
5025
5026/*
5027 * "getcmdwintype()" function
5028 */
5029 static void
5030f_getcmdwintype(typval_T *argvars UNUSED, typval_T *rettv)
5031{
5032 rettv->v_type = VAR_STRING;
5033 rettv->vval.v_string = NULL;
5034#ifdef FEAT_CMDWIN
5035 rettv->vval.v_string = alloc(2);
5036 if (rettv->vval.v_string != NULL)
5037 {
5038 rettv->vval.v_string[0] = cmdwin_type;
5039 rettv->vval.v_string[1] = NUL;
5040 }
5041#endif
5042}
5043
5044#if defined(FEAT_CMDL_COMPL)
5045/*
5046 * "getcompletion()" function
5047 */
5048 static void
5049f_getcompletion(typval_T *argvars, typval_T *rettv)
5050{
5051 char_u *pat;
5052 expand_T xpc;
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005053 int filtered = FALSE;
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005054 int options = WILD_SILENT | WILD_USE_NL | WILD_ADD_SLASH
5055 | WILD_NO_BEEP;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005056
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005057 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005058 filtered = tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005059
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005060 if (p_wic)
5061 options |= WILD_ICASE;
5062
Bram Moolenaare9d58a62016-08-13 15:07:41 +02005063 /* For filtered results, 'wildignore' is used */
5064 if (!filtered)
5065 options |= WILD_KEEP_ALL;
5066
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005067 ExpandInit(&xpc);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005068 xpc.xp_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005069 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005070 xpc.xp_context = cmdcomplete_str_to_type(tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005071 if (xpc.xp_context == EXPAND_NOTHING)
5072 {
5073 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005074 semsg(_(e_invarg2), argvars[1].vval.v_string);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005075 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005076 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005077 return;
5078 }
5079
5080# if defined(FEAT_MENU)
5081 if (xpc.xp_context == EXPAND_MENUS)
5082 {
5083 set_context_in_menu_cmd(&xpc, (char_u *)"menu", xpc.xp_pattern, FALSE);
5084 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5085 }
5086# endif
Bram Moolenaarb650b982016-08-05 20:35:13 +02005087#ifdef FEAT_CSCOPE
5088 if (xpc.xp_context == EXPAND_CSCOPE)
5089 {
5090 set_context_in_cscope_cmd(&xpc, xpc.xp_pattern, CMD_cscope);
5091 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5092 }
5093#endif
Bram Moolenaar7522f692016-08-06 14:12:50 +02005094#ifdef FEAT_SIGNS
5095 if (xpc.xp_context == EXPAND_SIGN)
5096 {
5097 set_context_in_sign_cmd(&xpc, xpc.xp_pattern);
5098 xpc.xp_pattern_len = (int)STRLEN(xpc.xp_pattern);
5099 }
5100#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005101
5102 pat = addstar(xpc.xp_pattern, xpc.xp_pattern_len, xpc.xp_context);
5103 if ((rettv_list_alloc(rettv) != FAIL) && (pat != NULL))
5104 {
Bram Moolenaarb56195e2016-07-28 22:53:37 +02005105 int i;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005106
5107 ExpandOne(&xpc, pat, NULL, options, WILD_ALL_KEEP);
5108
5109 for (i = 0; i < xpc.xp_numfiles; i++)
5110 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
5111 }
5112 vim_free(pat);
5113 ExpandCleanup(&xpc);
5114}
5115#endif
5116
5117/*
5118 * "getcwd()" function
5119 */
5120 static void
5121f_getcwd(typval_T *argvars, typval_T *rettv)
5122{
5123 win_T *wp = NULL;
5124 char_u *cwd;
Bram Moolenaar54591292018-02-09 20:53:59 +01005125 int global = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005126
5127 rettv->v_type = VAR_STRING;
5128 rettv->vval.v_string = NULL;
5129
Bram Moolenaar54591292018-02-09 20:53:59 +01005130 if (argvars[0].v_type == VAR_NUMBER && argvars[0].vval.v_number == -1)
5131 global = TRUE;
5132 else
5133 wp = find_tabwin(&argvars[0], &argvars[1]);
5134
5135 if (wp != NULL && wp->w_localdir != NULL)
5136 rettv->vval.v_string = vim_strsave(wp->w_localdir);
5137 else if (wp != NULL || global)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005138 {
Bram Moolenaar54591292018-02-09 20:53:59 +01005139 if (globaldir != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005140 rettv->vval.v_string = vim_strsave(globaldir);
5141 else
5142 {
5143 cwd = alloc(MAXPATHL);
5144 if (cwd != NULL)
5145 {
5146 if (mch_dirname(cwd, MAXPATHL) != FAIL)
5147 rettv->vval.v_string = vim_strsave(cwd);
5148 vim_free(cwd);
5149 }
5150 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005151 }
Bram Moolenaar3c5b8cd2018-09-02 14:25:05 +02005152#ifdef BACKSLASH_IN_FILENAME
5153 if (rettv->vval.v_string != NULL)
5154 slash_adjust(rettv->vval.v_string);
5155#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005156}
5157
5158/*
5159 * "getfontname()" function
5160 */
5161 static void
5162f_getfontname(typval_T *argvars UNUSED, typval_T *rettv)
5163{
5164 rettv->v_type = VAR_STRING;
5165 rettv->vval.v_string = NULL;
5166#ifdef FEAT_GUI
5167 if (gui.in_use)
5168 {
5169 GuiFont font;
5170 char_u *name = NULL;
5171
5172 if (argvars[0].v_type == VAR_UNKNOWN)
5173 {
5174 /* Get the "Normal" font. Either the name saved by
5175 * hl_set_font_name() or from the font ID. */
5176 font = gui.norm_font;
5177 name = hl_get_font_name();
5178 }
5179 else
5180 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005181 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005182 if (STRCMP(name, "*") == 0) /* don't use font dialog */
5183 return;
5184 font = gui_mch_get_font(name, FALSE);
5185 if (font == NOFONT)
5186 return; /* Invalid font name, return empty string. */
5187 }
5188 rettv->vval.v_string = gui_mch_get_fontname(font, name);
5189 if (argvars[0].v_type != VAR_UNKNOWN)
5190 gui_mch_free_font(font);
5191 }
5192#endif
5193}
5194
5195/*
5196 * "getfperm({fname})" function
5197 */
5198 static void
5199f_getfperm(typval_T *argvars, typval_T *rettv)
5200{
5201 char_u *fname;
5202 stat_T st;
5203 char_u *perm = NULL;
5204 char_u flags[] = "rwx";
5205 int i;
5206
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005207 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005208
5209 rettv->v_type = VAR_STRING;
5210 if (mch_stat((char *)fname, &st) >= 0)
5211 {
5212 perm = vim_strsave((char_u *)"---------");
5213 if (perm != NULL)
5214 {
5215 for (i = 0; i < 9; i++)
5216 {
5217 if (st.st_mode & (1 << (8 - i)))
5218 perm[i] = flags[i % 3];
5219 }
5220 }
5221 }
5222 rettv->vval.v_string = perm;
5223}
5224
5225/*
5226 * "getfsize({fname})" function
5227 */
5228 static void
5229f_getfsize(typval_T *argvars, typval_T *rettv)
5230{
5231 char_u *fname;
5232 stat_T st;
5233
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005234 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005235
5236 rettv->v_type = VAR_NUMBER;
5237
5238 if (mch_stat((char *)fname, &st) >= 0)
5239 {
5240 if (mch_isdir(fname))
5241 rettv->vval.v_number = 0;
5242 else
5243 {
5244 rettv->vval.v_number = (varnumber_T)st.st_size;
5245
5246 /* non-perfect check for overflow */
5247 if ((off_T)rettv->vval.v_number != (off_T)st.st_size)
5248 rettv->vval.v_number = -2;
5249 }
5250 }
5251 else
5252 rettv->vval.v_number = -1;
5253}
5254
5255/*
5256 * "getftime({fname})" function
5257 */
5258 static void
5259f_getftime(typval_T *argvars, typval_T *rettv)
5260{
5261 char_u *fname;
5262 stat_T st;
5263
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005264 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005265
5266 if (mch_stat((char *)fname, &st) >= 0)
5267 rettv->vval.v_number = (varnumber_T)st.st_mtime;
5268 else
5269 rettv->vval.v_number = -1;
5270}
5271
5272/*
5273 * "getftype({fname})" function
5274 */
5275 static void
5276f_getftype(typval_T *argvars, typval_T *rettv)
5277{
5278 char_u *fname;
5279 stat_T st;
5280 char_u *type = NULL;
5281 char *t;
5282
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005283 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005284
5285 rettv->v_type = VAR_STRING;
5286 if (mch_lstat((char *)fname, &st) >= 0)
5287 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005288 if (S_ISREG(st.st_mode))
5289 t = "file";
5290 else if (S_ISDIR(st.st_mode))
5291 t = "dir";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005292 else if (S_ISLNK(st.st_mode))
5293 t = "link";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005294 else if (S_ISBLK(st.st_mode))
5295 t = "bdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005296 else if (S_ISCHR(st.st_mode))
5297 t = "cdev";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005298 else if (S_ISFIFO(st.st_mode))
5299 t = "fifo";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005300 else if (S_ISSOCK(st.st_mode))
Bram Moolenaar1598f992018-08-09 22:08:57 +02005301 t = "socket";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005302 else
5303 t = "other";
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005304 type = vim_strsave((char_u *)t);
5305 }
5306 rettv->vval.v_string = type;
5307}
5308
5309/*
Bram Moolenaar4f505882018-02-10 21:06:32 +01005310 * "getjumplist()" function
5311 */
5312 static void
5313f_getjumplist(typval_T *argvars, typval_T *rettv)
5314{
5315#ifdef FEAT_JUMPLIST
5316 win_T *wp;
5317 int i;
5318 list_T *l;
5319 dict_T *d;
5320#endif
5321
5322 if (rettv_list_alloc(rettv) != OK)
5323 return;
5324
5325#ifdef FEAT_JUMPLIST
5326 wp = find_tabwin(&argvars[0], &argvars[1]);
5327 if (wp == NULL)
5328 return;
5329
Bram Moolenaar57ee2b62019-02-12 22:15:06 +01005330 cleanup_jumplist(wp, TRUE);
5331
Bram Moolenaar4f505882018-02-10 21:06:32 +01005332 l = list_alloc();
5333 if (l == NULL)
5334 return;
5335
5336 if (list_append_list(rettv->vval.v_list, l) == FAIL)
5337 return;
5338 list_append_number(rettv->vval.v_list, (varnumber_T)wp->w_jumplistidx);
5339
5340 for (i = 0; i < wp->w_jumplistlen; ++i)
5341 {
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005342 if (wp->w_jumplist[i].fmark.mark.lnum == 0)
5343 continue;
Bram Moolenaar4f505882018-02-10 21:06:32 +01005344 if ((d = dict_alloc()) == NULL)
5345 return;
5346 if (list_append_dict(l, d) == FAIL)
5347 return;
Bram Moolenaare0be1672018-07-08 16:50:37 +02005348 dict_add_number(d, "lnum", (long)wp->w_jumplist[i].fmark.mark.lnum);
5349 dict_add_number(d, "col", (long)wp->w_jumplist[i].fmark.mark.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005350 dict_add_number(d, "coladd", (long)wp->w_jumplist[i].fmark.mark.coladd);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005351 dict_add_number(d, "bufnr", (long)wp->w_jumplist[i].fmark.fnum);
Bram Moolenaara7e18d22018-02-11 14:29:49 +01005352 if (wp->w_jumplist[i].fname != NULL)
Bram Moolenaare0be1672018-07-08 16:50:37 +02005353 dict_add_string(d, "filename", wp->w_jumplist[i].fname);
Bram Moolenaar4f505882018-02-10 21:06:32 +01005354 }
5355#endif
5356}
5357
5358/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005359 * "getline(lnum, [end])" function
5360 */
5361 static void
5362f_getline(typval_T *argvars, typval_T *rettv)
5363{
5364 linenr_T lnum;
5365 linenr_T end;
5366 int retlist;
5367
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005368 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005369 if (argvars[1].v_type == VAR_UNKNOWN)
5370 {
5371 end = 0;
5372 retlist = FALSE;
5373 }
5374 else
5375 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005376 end = tv_get_lnum(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005377 retlist = TRUE;
5378 }
5379
5380 get_buffer_lines(curbuf, lnum, end, retlist, rettv);
5381}
5382
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005383#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005384 static void
5385get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
5386{
Bram Moolenaard823fa92016-08-12 16:29:27 +02005387 if (what_arg->v_type == VAR_UNKNOWN)
5388 {
5389 if (rettv_list_alloc(rettv) == OK)
5390 if (is_qf || wp != NULL)
Bram Moolenaar7adf06f2017-08-27 15:23:41 +02005391 (void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005392 }
5393 else
5394 {
5395 if (rettv_dict_alloc(rettv) == OK)
5396 if (is_qf || (wp != NULL))
5397 {
5398 if (what_arg->v_type == VAR_DICT)
5399 {
5400 dict_T *d = what_arg->vval.v_dict;
5401
5402 if (d != NULL)
Bram Moolenaarb4d5fba2017-09-11 19:31:28 +02005403 qf_get_properties(wp, d, rettv->vval.v_dict);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005404 }
5405 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01005406 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +02005407 }
5408 }
Bram Moolenaard823fa92016-08-12 16:29:27 +02005409}
Bram Moolenaar4ae20952016-08-13 15:29:14 +02005410#endif
Bram Moolenaard823fa92016-08-12 16:29:27 +02005411
5412/*
5413 * "getloclist()" function
5414 */
5415 static void
5416f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5417{
5418#ifdef FEAT_QUICKFIX
5419 win_T *wp;
5420
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005421 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaard823fa92016-08-12 16:29:27 +02005422 get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
5423#endif
5424}
5425
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005426/*
5427 * "getmatches()" function
5428 */
5429 static void
5430f_getmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5431{
5432#ifdef FEAT_SEARCH_EXTRA
5433 dict_T *dict;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005434 matchitem_T *cur;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005435 int i;
Bram Moolenaaraff74912019-03-30 18:11:49 +01005436 win_T *win = get_optional_window(argvars, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005437
Bram Moolenaaraff74912019-03-30 18:11:49 +01005438 if (rettv_list_alloc(rettv) == FAIL || win == NULL)
5439 return;
5440
5441 cur = win->w_match_head;
5442 while (cur != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005443 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005444 dict = dict_alloc();
5445 if (dict == NULL)
5446 return;
5447 if (cur->match.regprog == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005448 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005449 /* match added with matchaddpos() */
5450 for (i = 0; i < MAXPOSMATCH; ++i)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005451 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005452 llpos_T *llpos;
5453 char buf[6];
5454 list_T *l;
5455
5456 llpos = &cur->pos.pos[i];
5457 if (llpos->lnum == 0)
5458 break;
5459 l = list_alloc();
5460 if (l == NULL)
5461 break;
5462 list_append_number(l, (varnumber_T)llpos->lnum);
5463 if (llpos->col > 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005464 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01005465 list_append_number(l, (varnumber_T)llpos->col);
5466 list_append_number(l, (varnumber_T)llpos->len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005467 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005468 sprintf(buf, "pos%d", i + 1);
5469 dict_add_list(dict, buf, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005470 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005471 }
Bram Moolenaaraff74912019-03-30 18:11:49 +01005472 else
5473 {
5474 dict_add_string(dict, "pattern", cur->pattern);
5475 }
5476 dict_add_string(dict, "group", syn_id2name(cur->hlg_id));
5477 dict_add_number(dict, "priority", (long)cur->priority);
5478 dict_add_number(dict, "id", (long)cur->id);
5479# if defined(FEAT_CONCEAL)
5480 if (cur->conceal_char)
5481 {
5482 char_u buf[MB_MAXBYTES + 1];
5483
5484 buf[(*mb_char2bytes)((int)cur->conceal_char, buf)] = NUL;
5485 dict_add_string(dict, "conceal", (char_u *)&buf);
5486 }
5487# endif
5488 list_append_dict(rettv->vval.v_list, dict);
5489 cur = cur->next;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005490 }
5491#endif
5492}
5493
5494/*
5495 * "getpid()" function
5496 */
5497 static void
5498f_getpid(typval_T *argvars UNUSED, typval_T *rettv)
5499{
5500 rettv->vval.v_number = mch_get_pid();
5501}
5502
5503 static void
5504getpos_both(
5505 typval_T *argvars,
5506 typval_T *rettv,
5507 int getcurpos)
5508{
5509 pos_T *fp;
5510 list_T *l;
5511 int fnum = -1;
5512
5513 if (rettv_list_alloc(rettv) == OK)
5514 {
5515 l = rettv->vval.v_list;
5516 if (getcurpos)
5517 fp = &curwin->w_cursor;
5518 else
5519 fp = var2fpos(&argvars[0], TRUE, &fnum);
5520 if (fnum != -1)
5521 list_append_number(l, (varnumber_T)fnum);
5522 else
5523 list_append_number(l, (varnumber_T)0);
5524 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->lnum
5525 : (varnumber_T)0);
5526 list_append_number(l, (fp != NULL)
5527 ? (varnumber_T)(fp->col == MAXCOL ? MAXCOL : fp->col + 1)
5528 : (varnumber_T)0);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005529 list_append_number(l, (fp != NULL) ? (varnumber_T)fp->coladd :
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005530 (varnumber_T)0);
5531 if (getcurpos)
5532 {
Bram Moolenaar19a66852019-03-07 11:25:32 +01005533 int save_set_curswant = curwin->w_set_curswant;
5534 colnr_T save_curswant = curwin->w_curswant;
5535 colnr_T save_virtcol = curwin->w_virtcol;
5536
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005537 update_curswant();
5538 list_append_number(l, curwin->w_curswant == MAXCOL ?
5539 (varnumber_T)MAXCOL : (varnumber_T)curwin->w_curswant + 1);
Bram Moolenaar19a66852019-03-07 11:25:32 +01005540
5541 // Do not change "curswant", as it is unexpected that a get
5542 // function has a side effect.
5543 if (save_set_curswant)
5544 {
5545 curwin->w_set_curswant = save_set_curswant;
5546 curwin->w_curswant = save_curswant;
5547 curwin->w_virtcol = save_virtcol;
5548 curwin->w_valid &= ~VALID_VIRTCOL;
5549 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005550 }
5551 }
5552 else
5553 rettv->vval.v_number = FALSE;
5554}
5555
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005556/*
5557 * "getcurpos()" function
5558 */
5559 static void
5560f_getcurpos(typval_T *argvars, typval_T *rettv)
5561{
5562 getpos_both(argvars, rettv, TRUE);
5563}
5564
5565/*
5566 * "getpos(string)" function
5567 */
5568 static void
5569f_getpos(typval_T *argvars, typval_T *rettv)
5570{
5571 getpos_both(argvars, rettv, FALSE);
5572}
5573
5574/*
Bram Moolenaard823fa92016-08-12 16:29:27 +02005575 * "getqflist()" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005576 */
5577 static void
5578f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
5579{
5580#ifdef FEAT_QUICKFIX
Bram Moolenaard823fa92016-08-12 16:29:27 +02005581 get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005582#endif
5583}
5584
5585/*
5586 * "getreg()" function
5587 */
5588 static void
5589f_getreg(typval_T *argvars, typval_T *rettv)
5590{
5591 char_u *strregname;
5592 int regname;
5593 int arg2 = FALSE;
5594 int return_list = FALSE;
5595 int error = FALSE;
5596
5597 if (argvars[0].v_type != VAR_UNKNOWN)
5598 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005599 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005600 error = strregname == NULL;
5601 if (argvars[1].v_type != VAR_UNKNOWN)
5602 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005603 arg2 = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005604 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005605 return_list = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005606 }
5607 }
5608 else
5609 strregname = get_vim_var_str(VV_REG);
5610
5611 if (error)
5612 return;
5613
5614 regname = (strregname == NULL ? '"' : *strregname);
5615 if (regname == 0)
5616 regname = '"';
5617
5618 if (return_list)
5619 {
5620 rettv->v_type = VAR_LIST;
5621 rettv->vval.v_list = (list_T *)get_reg_contents(regname,
5622 (arg2 ? GREG_EXPR_SRC : 0) | GREG_LIST);
5623 if (rettv->vval.v_list == NULL)
5624 (void)rettv_list_alloc(rettv);
5625 else
5626 ++rettv->vval.v_list->lv_refcount;
5627 }
5628 else
5629 {
5630 rettv->v_type = VAR_STRING;
5631 rettv->vval.v_string = get_reg_contents(regname,
5632 arg2 ? GREG_EXPR_SRC : 0);
5633 }
5634}
5635
5636/*
5637 * "getregtype()" function
5638 */
5639 static void
5640f_getregtype(typval_T *argvars, typval_T *rettv)
5641{
5642 char_u *strregname;
5643 int regname;
5644 char_u buf[NUMBUFLEN + 2];
5645 long reglen = 0;
5646
5647 if (argvars[0].v_type != VAR_UNKNOWN)
5648 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005649 strregname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005650 if (strregname == NULL) /* type error; errmsg already given */
5651 {
5652 rettv->v_type = VAR_STRING;
5653 rettv->vval.v_string = NULL;
5654 return;
5655 }
5656 }
5657 else
5658 /* Default to v:register */
5659 strregname = get_vim_var_str(VV_REG);
5660
5661 regname = (strregname == NULL ? '"' : *strregname);
5662 if (regname == 0)
5663 regname = '"';
5664
5665 buf[0] = NUL;
5666 buf[1] = NUL;
5667 switch (get_reg_type(regname, &reglen))
5668 {
5669 case MLINE: buf[0] = 'V'; break;
5670 case MCHAR: buf[0] = 'v'; break;
5671 case MBLOCK:
5672 buf[0] = Ctrl_V;
5673 sprintf((char *)buf + 1, "%ld", reglen + 1);
5674 break;
5675 }
5676 rettv->v_type = VAR_STRING;
5677 rettv->vval.v_string = vim_strsave(buf);
5678}
5679
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005680/*
5681 * Returns information (variables, options, etc.) about a tab page
5682 * as a dictionary.
5683 */
5684 static dict_T *
5685get_tabpage_info(tabpage_T *tp, int tp_idx)
5686{
5687 win_T *wp;
5688 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005689 list_T *l;
5690
5691 dict = dict_alloc();
5692 if (dict == NULL)
5693 return NULL;
5694
Bram Moolenaare0be1672018-07-08 16:50:37 +02005695 dict_add_number(dict, "tabnr", tp_idx);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005696
5697 l = list_alloc();
5698 if (l != NULL)
5699 {
5700 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
5701 wp; wp = wp->w_next)
5702 list_append_number(l, (varnumber_T)wp->w_id);
5703 dict_add_list(dict, "windows", l);
5704 }
5705
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005706 /* Make a reference to tabpage variables */
5707 dict_add_dict(dict, "variables", tp->tp_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005708
5709 return dict;
5710}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005711
5712/*
5713 * "gettabinfo()" function
5714 */
5715 static void
5716f_gettabinfo(typval_T *argvars, typval_T *rettv)
5717{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005718 tabpage_T *tp, *tparg = NULL;
5719 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005720 int tpnr = 0;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005721
5722 if (rettv_list_alloc(rettv) != OK)
5723 return;
5724
5725 if (argvars[0].v_type != VAR_UNKNOWN)
5726 {
5727 /* Information about one tab page */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005728 tparg = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005729 if (tparg == NULL)
5730 return;
5731 }
5732
5733 /* Get information about a specific tab page or all tab pages */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005734 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005735 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005736 tpnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005737 if (tparg != NULL && tp != tparg)
5738 continue;
5739 d = get_tabpage_info(tp, tpnr);
5740 if (d != NULL)
5741 list_append_dict(rettv->vval.v_list, d);
5742 if (tparg != NULL)
5743 return;
5744 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005745}
5746
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005747/*
5748 * "gettabvar()" function
5749 */
5750 static void
5751f_gettabvar(typval_T *argvars, typval_T *rettv)
5752{
5753 win_T *oldcurwin;
5754 tabpage_T *tp, *oldtabpage;
5755 dictitem_T *v;
5756 char_u *varname;
5757 int done = FALSE;
5758
5759 rettv->v_type = VAR_STRING;
5760 rettv->vval.v_string = NULL;
5761
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005762 varname = tv_get_string_chk(&argvars[1]);
5763 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005764 if (tp != NULL && varname != NULL)
5765 {
5766 /* Set tp to be our tabpage, temporarily. Also set the window to the
5767 * first window in the tabpage, otherwise the window is not valid. */
5768 if (switch_win(&oldcurwin, &oldtabpage,
Bram Moolenaar816968d2017-09-29 21:29:18 +02005769 tp == curtab || tp->tp_firstwin == NULL ? firstwin
5770 : tp->tp_firstwin, tp, TRUE) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005771 {
5772 /* look up the variable */
5773 /* Let gettabvar({nr}, "") return the "t:" dictionary. */
5774 v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
5775 if (v != NULL)
5776 {
5777 copy_tv(&v->di_tv, rettv);
5778 done = TRUE;
5779 }
5780 }
5781
5782 /* restore previous notion of curwin */
5783 restore_win(oldcurwin, oldtabpage, TRUE);
5784 }
5785
5786 if (!done && argvars[2].v_type != VAR_UNKNOWN)
5787 copy_tv(&argvars[2], rettv);
5788}
5789
5790/*
5791 * "gettabwinvar()" function
5792 */
5793 static void
5794f_gettabwinvar(typval_T *argvars, typval_T *rettv)
5795{
5796 getwinvar(argvars, rettv, 1);
5797}
5798
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005799/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +01005800 * "gettagstack()" function
5801 */
5802 static void
5803f_gettagstack(typval_T *argvars, typval_T *rettv)
5804{
5805 win_T *wp = curwin; // default is current window
5806
5807 if (rettv_dict_alloc(rettv) != OK)
5808 return;
5809
5810 if (argvars[0].v_type != VAR_UNKNOWN)
5811 {
5812 wp = find_win_by_nr_or_id(&argvars[0]);
5813 if (wp == NULL)
5814 return;
5815 }
5816
5817 get_tagstack(wp, rettv->vval.v_dict);
5818}
5819
5820/*
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005821 * Returns information about a window as a dictionary.
5822 */
5823 static dict_T *
5824get_win_info(win_T *wp, short tpnr, short winnr)
5825{
5826 dict_T *dict;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005827
5828 dict = dict_alloc();
5829 if (dict == NULL)
5830 return NULL;
5831
Bram Moolenaare0be1672018-07-08 16:50:37 +02005832 dict_add_number(dict, "tabnr", tpnr);
5833 dict_add_number(dict, "winnr", winnr);
5834 dict_add_number(dict, "winid", wp->w_id);
5835 dict_add_number(dict, "height", wp->w_height);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005836 dict_add_number(dict, "winrow", wp->w_winrow + 1);
Bram Moolenaar8fcb60f2019-03-04 13:18:30 +01005837 dict_add_number(dict, "topline", wp->w_topline);
5838 dict_add_number(dict, "botline", wp->w_botline - 1);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005839#ifdef FEAT_MENU
Bram Moolenaare0be1672018-07-08 16:50:37 +02005840 dict_add_number(dict, "winbar", wp->w_winbar_height);
Bram Moolenaar1b9645d2017-09-17 23:03:31 +02005841#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +02005842 dict_add_number(dict, "width", wp->w_width);
Bram Moolenaar7132ddc2018-07-15 17:01:11 +02005843 dict_add_number(dict, "wincol", wp->w_wincol + 1);
Bram Moolenaare0be1672018-07-08 16:50:37 +02005844 dict_add_number(dict, "bufnr", wp->w_buffer->b_fnum);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005845
Bram Moolenaar69905d12017-08-13 18:14:47 +02005846#ifdef FEAT_TERMINAL
Bram Moolenaare0be1672018-07-08 16:50:37 +02005847 dict_add_number(dict, "terminal", bt_terminal(wp->w_buffer));
Bram Moolenaar69905d12017-08-13 18:14:47 +02005848#endif
Bram Moolenaar386600f2016-08-15 22:16:25 +02005849#ifdef FEAT_QUICKFIX
Bram Moolenaare0be1672018-07-08 16:50:37 +02005850 dict_add_number(dict, "quickfix", bt_quickfix(wp->w_buffer));
5851 dict_add_number(dict, "loclist",
5852 (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL));
Bram Moolenaar386600f2016-08-15 22:16:25 +02005853#endif
5854
Bram Moolenaar30567352016-08-27 21:25:44 +02005855 /* Add a reference to window variables */
Bram Moolenaar9f8187c2016-08-27 20:34:01 +02005856 dict_add_dict(dict, "variables", wp->w_vars);
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005857
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005858 return dict;
5859}
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005860
5861/*
5862 * "getwininfo()" function
5863 */
5864 static void
5865f_getwininfo(typval_T *argvars, typval_T *rettv)
5866{
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005867 tabpage_T *tp;
5868 win_T *wp = NULL, *wparg = NULL;
5869 dict_T *d;
Bram Moolenaar386600f2016-08-15 22:16:25 +02005870 short tabnr = 0, winnr;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005871
5872 if (rettv_list_alloc(rettv) != OK)
5873 return;
5874
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005875 if (argvars[0].v_type != VAR_UNKNOWN)
5876 {
Bram Moolenaareeb1b9c2019-02-10 22:59:04 +01005877 wparg = win_id2wp(tv_get_number(&argvars[0]));
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005878 if (wparg == NULL)
5879 return;
5880 }
5881
5882 /* Collect information about either all the windows across all the tab
5883 * pages or one particular window.
5884 */
Bram Moolenaar386600f2016-08-15 22:16:25 +02005885 FOR_ALL_TABPAGES(tp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005886 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005887 tabnr++;
5888 winnr = 0;
5889 FOR_ALL_WINDOWS_IN_TAB(tp, wp)
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005890 {
Bram Moolenaar386600f2016-08-15 22:16:25 +02005891 winnr++;
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005892 if (wparg != NULL && wp != wparg)
5893 continue;
5894 d = get_win_info(wp, tabnr, winnr);
5895 if (d != NULL)
5896 list_append_dict(rettv->vval.v_list, d);
5897 if (wparg != NULL)
5898 /* found information about a specific window */
5899 return;
5900 }
5901 }
Bram Moolenaarb5ae48e2016-08-12 22:23:25 +02005902}
5903
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005904/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02005905 * "win_findbuf()" function
5906 */
5907 static void
5908f_win_findbuf(typval_T *argvars, typval_T *rettv)
5909{
5910 if (rettv_list_alloc(rettv) != FAIL)
5911 win_findbuf(argvars, rettv->vval.v_list);
5912}
5913
5914/*
5915 * "win_getid()" function
5916 */
5917 static void
5918f_win_getid(typval_T *argvars, typval_T *rettv)
5919{
5920 rettv->vval.v_number = win_getid(argvars);
5921}
5922
5923/*
5924 * "win_gotoid()" function
5925 */
5926 static void
5927f_win_gotoid(typval_T *argvars, typval_T *rettv)
5928{
5929 rettv->vval.v_number = win_gotoid(argvars);
5930}
5931
5932/*
5933 * "win_id2tabwin()" function
5934 */
5935 static void
5936f_win_id2tabwin(typval_T *argvars, typval_T *rettv)
5937{
5938 if (rettv_list_alloc(rettv) != FAIL)
5939 win_id2tabwin(argvars, rettv->vval.v_list);
5940}
5941
5942/*
5943 * "win_id2win()" function
5944 */
5945 static void
5946f_win_id2win(typval_T *argvars, typval_T *rettv)
5947{
5948 rettv->vval.v_number = win_id2win(argvars);
5949}
5950
5951/*
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005952 * "win_screenpos()" function
5953 */
5954 static void
5955f_win_screenpos(typval_T *argvars, typval_T *rettv)
5956{
5957 win_T *wp;
5958
5959 if (rettv_list_alloc(rettv) == FAIL)
5960 return;
5961
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02005962 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar22044dc2017-12-02 15:43:37 +01005963 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_winrow + 1);
5964 list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1);
5965}
5966
5967/*
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005968 * "getwinpos({timeout})" function
5969 */
5970 static void
5971f_getwinpos(typval_T *argvars UNUSED, typval_T *rettv)
5972{
5973 int x = -1;
5974 int y = -1;
5975
5976 if (rettv_list_alloc(rettv) == FAIL)
5977 return;
5978#ifdef FEAT_GUI
5979 if (gui.in_use)
Bram Moolenaar295ac5a2018-03-22 23:04:02 +01005980 (void)gui_mch_get_winpos(&x, &y);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005981# if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5982 else
5983# endif
5984#endif
5985#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
5986 {
5987 varnumber_T timeout = 100;
5988
5989 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01005990 timeout = tv_get_number(&argvars[0]);
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01005991 term_get_winpos(&x, &y, timeout);
5992 }
5993#endif
5994 list_append_number(rettv->vval.v_list, (varnumber_T)x);
5995 list_append_number(rettv->vval.v_list, (varnumber_T)y);
5996}
5997
5998
5999/*
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006000 * "getwinposx()" function
6001 */
6002 static void
6003f_getwinposx(typval_T *argvars UNUSED, typval_T *rettv)
6004{
6005 rettv->vval.v_number = -1;
6006#ifdef FEAT_GUI
6007 if (gui.in_use)
6008 {
6009 int x, y;
6010
6011 if (gui_mch_get_winpos(&x, &y) == OK)
6012 rettv->vval.v_number = x;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02006013 return;
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006014 }
6015#endif
6016#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6017 {
6018 int x, y;
6019
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006020 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006021 rettv->vval.v_number = x;
6022 }
6023#endif
6024}
6025
6026/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006027 * "getwinposy()" function
6028 */
6029 static void
6030f_getwinposy(typval_T *argvars UNUSED, typval_T *rettv)
6031{
6032 rettv->vval.v_number = -1;
6033#ifdef FEAT_GUI
6034 if (gui.in_use)
6035 {
6036 int x, y;
6037
6038 if (gui_mch_get_winpos(&x, &y) == OK)
6039 rettv->vval.v_number = y;
Bram Moolenaar7860bac2017-04-09 15:03:15 +02006040 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006041 }
6042#endif
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006043#if defined(HAVE_TGETENT) && defined(FEAT_TERMRESPONSE)
6044 {
6045 int x, y;
6046
Bram Moolenaar3f54fd32018-03-03 21:29:55 +01006047 if (term_get_winpos(&x, &y, (varnumber_T)100) == OK)
Bram Moolenaarba6ec182017-04-04 22:41:10 +02006048 rettv->vval.v_number = y;
6049 }
6050#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006051}
6052
6053/*
6054 * "getwinvar()" function
6055 */
6056 static void
6057f_getwinvar(typval_T *argvars, typval_T *rettv)
6058{
6059 getwinvar(argvars, rettv, 0);
6060}
6061
6062/*
6063 * "glob()" function
6064 */
6065 static void
6066f_glob(typval_T *argvars, typval_T *rettv)
6067{
6068 int options = WILD_SILENT|WILD_USE_NL;
6069 expand_T xpc;
6070 int error = FALSE;
6071
6072 /* When the optional second argument is non-zero, don't remove matches
6073 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6074 rettv->v_type = VAR_STRING;
6075 if (argvars[1].v_type != VAR_UNKNOWN)
6076 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006077 if (tv_get_number_chk(&argvars[1], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006078 options |= WILD_KEEP_ALL;
6079 if (argvars[2].v_type != VAR_UNKNOWN)
6080 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006081 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006082 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006083 if (argvars[3].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006084 && tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006085 options |= WILD_ALLLINKS;
6086 }
6087 }
6088 if (!error)
6089 {
6090 ExpandInit(&xpc);
6091 xpc.xp_context = EXPAND_FILES;
6092 if (p_wic)
6093 options += WILD_ICASE;
6094 if (rettv->v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006095 rettv->vval.v_string = ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006096 NULL, options, WILD_ALL);
6097 else if (rettv_list_alloc(rettv) != FAIL)
6098 {
6099 int i;
6100
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006101 ExpandOne(&xpc, tv_get_string(&argvars[0]),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006102 NULL, options, WILD_ALL_KEEP);
6103 for (i = 0; i < xpc.xp_numfiles; i++)
6104 list_append_string(rettv->vval.v_list, xpc.xp_files[i], -1);
6105
6106 ExpandCleanup(&xpc);
6107 }
6108 }
6109 else
6110 rettv->vval.v_string = NULL;
6111}
6112
6113/*
6114 * "globpath()" function
6115 */
6116 static void
6117f_globpath(typval_T *argvars, typval_T *rettv)
6118{
6119 int flags = 0;
6120 char_u buf1[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006121 char_u *file = tv_get_string_buf_chk(&argvars[1], buf1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006122 int error = FALSE;
6123 garray_T ga;
6124 int i;
6125
6126 /* When the optional second argument is non-zero, don't remove matches
6127 * for 'wildignore' and don't put matches for 'suffixes' at the end. */
6128 rettv->v_type = VAR_STRING;
6129 if (argvars[2].v_type != VAR_UNKNOWN)
6130 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006131 if (tv_get_number_chk(&argvars[2], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006132 flags |= WILD_KEEP_ALL;
6133 if (argvars[3].v_type != VAR_UNKNOWN)
6134 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006135 if (tv_get_number_chk(&argvars[3], &error))
Bram Moolenaar45cf6e92017-04-30 20:25:19 +02006136 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006137 if (argvars[4].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006138 && tv_get_number_chk(&argvars[4], &error))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006139 flags |= WILD_ALLLINKS;
6140 }
6141 }
6142 if (file != NULL && !error)
6143 {
6144 ga_init2(&ga, (int)sizeof(char_u *), 10);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006145 globpath(tv_get_string(&argvars[0]), file, &ga, flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006146 if (rettv->v_type == VAR_STRING)
6147 rettv->vval.v_string = ga_concat_strings(&ga, "\n");
6148 else if (rettv_list_alloc(rettv) != FAIL)
6149 for (i = 0; i < ga.ga_len; ++i)
6150 list_append_string(rettv->vval.v_list,
6151 ((char_u **)(ga.ga_data))[i], -1);
6152 ga_clear_strings(&ga);
6153 }
6154 else
6155 rettv->vval.v_string = NULL;
6156}
6157
6158/*
6159 * "glob2regpat()" function
6160 */
6161 static void
6162f_glob2regpat(typval_T *argvars, typval_T *rettv)
6163{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006164 char_u *pat = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006165
6166 rettv->v_type = VAR_STRING;
6167 rettv->vval.v_string = (pat == NULL)
6168 ? NULL : file_pat_to_reg_pat(pat, NULL, NULL, FALSE);
6169}
6170
6171/* for VIM_VERSION_ defines */
6172#include "version.h"
6173
6174/*
6175 * "has()" function
6176 */
6177 static void
6178f_has(typval_T *argvars, typval_T *rettv)
6179{
6180 int i;
6181 char_u *name;
6182 int n = FALSE;
6183 static char *(has_list[]) =
6184 {
6185#ifdef AMIGA
6186 "amiga",
6187# ifdef FEAT_ARP
6188 "arp",
6189# endif
6190#endif
6191#ifdef __BEOS__
6192 "beos",
6193#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006194#if defined(BSD) && !defined(MACOS_X)
6195 "bsd",
6196#endif
6197#ifdef hpux
6198 "hpux",
6199#endif
6200#ifdef __linux__
6201 "linux",
6202#endif
Bram Moolenaard0573012017-10-28 21:11:06 +02006203#ifdef MACOS_X
Bram Moolenaar4f505882018-02-10 21:06:32 +01006204 "mac", /* Mac OS X (and, once, Mac OS Classic) */
6205 "osx", /* Mac OS X */
Bram Moolenaard0573012017-10-28 21:11:06 +02006206# ifdef MACOS_X_DARWIN
Bram Moolenaar4f505882018-02-10 21:06:32 +01006207 "macunix", /* Mac OS X, with the darwin feature */
6208 "osxdarwin", /* synonym for macunix */
Bram Moolenaard0573012017-10-28 21:11:06 +02006209# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006210#endif
6211#ifdef __QNX__
6212 "qnx",
6213#endif
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006214#ifdef SUN_SYSTEM
6215 "sun",
6216#else
6217 "moon",
6218#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006219#ifdef UNIX
6220 "unix",
6221#endif
6222#ifdef VMS
6223 "vms",
6224#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006225#ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006226 "win32",
6227#endif
Bram Moolenaar1eed5322019-02-26 17:03:54 +01006228#if defined(UNIX) && defined(__CYGWIN__)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006229 "win32unix",
6230#endif
Bram Moolenaar44b443c2019-02-18 22:14:18 +01006231#ifdef _WIN64
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006232 "win64",
6233#endif
6234#ifdef EBCDIC
6235 "ebcdic",
6236#endif
6237#ifndef CASE_INSENSITIVE_FILENAME
6238 "fname_case",
6239#endif
6240#ifdef HAVE_ACL
6241 "acl",
6242#endif
6243#ifdef FEAT_ARABIC
6244 "arabic",
6245#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006246 "autocmd",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006247#ifdef FEAT_AUTOCHDIR
Bram Moolenaar39536dd2019-01-29 22:58:21 +01006248 "autochdir",
Bram Moolenaar83ec2a72018-07-27 22:08:59 +02006249#endif
Bram Moolenaare42a6d22017-11-12 19:21:51 +01006250#ifdef FEAT_AUTOSERVERNAME
6251 "autoservername",
6252#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006253#ifdef FEAT_BEVAL_GUI
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006254 "balloon_eval",
Bram Moolenaar4f974752019-02-17 17:44:42 +01006255# ifndef FEAT_GUI_MSWIN /* other GUIs always have multiline balloons */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006256 "balloon_multiline",
6257# endif
6258#endif
Bram Moolenaarc3719bd2017-11-18 22:13:31 +01006259#ifdef FEAT_BEVAL_TERM
Bram Moolenaar51b0f372017-11-18 18:52:04 +01006260 "balloon_eval_term",
6261#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006262#if defined(SOME_BUILTIN_TCAPS) || defined(ALL_BUILTIN_TCAPS)
6263 "builtin_terms",
6264# ifdef ALL_BUILTIN_TCAPS
6265 "all_builtin_terms",
6266# endif
6267#endif
6268#if defined(FEAT_BROWSE) && (defined(USE_FILE_CHOOSER) \
Bram Moolenaar4f974752019-02-17 17:44:42 +01006269 || defined(FEAT_GUI_MSWIN) \
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006270 || defined(FEAT_GUI_MOTIF))
6271 "browsefilter",
6272#endif
6273#ifdef FEAT_BYTEOFF
6274 "byte_offset",
6275#endif
6276#ifdef FEAT_JOB_CHANNEL
6277 "channel",
6278#endif
6279#ifdef FEAT_CINDENT
6280 "cindent",
6281#endif
6282#ifdef FEAT_CLIENTSERVER
6283 "clientserver",
6284#endif
6285#ifdef FEAT_CLIPBOARD
6286 "clipboard",
6287#endif
6288#ifdef FEAT_CMDL_COMPL
6289 "cmdline_compl",
6290#endif
6291#ifdef FEAT_CMDHIST
6292 "cmdline_hist",
6293#endif
6294#ifdef FEAT_COMMENTS
6295 "comments",
6296#endif
6297#ifdef FEAT_CONCEAL
6298 "conceal",
6299#endif
6300#ifdef FEAT_CRYPT
6301 "cryptv",
6302 "crypt-blowfish",
6303 "crypt-blowfish2",
6304#endif
6305#ifdef FEAT_CSCOPE
6306 "cscope",
6307#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006308 "cursorbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006309#ifdef CURSOR_SHAPE
6310 "cursorshape",
6311#endif
6312#ifdef DEBUG
6313 "debug",
6314#endif
6315#ifdef FEAT_CON_DIALOG
6316 "dialog_con",
6317#endif
6318#ifdef FEAT_GUI_DIALOG
6319 "dialog_gui",
6320#endif
6321#ifdef FEAT_DIFF
6322 "diff",
6323#endif
6324#ifdef FEAT_DIGRAPHS
6325 "digraphs",
6326#endif
6327#ifdef FEAT_DIRECTX
6328 "directx",
6329#endif
6330#ifdef FEAT_DND
6331 "dnd",
6332#endif
6333#ifdef FEAT_EMACS_TAGS
6334 "emacs_tags",
6335#endif
6336 "eval", /* always present, of course! */
6337 "ex_extra", /* graduated feature */
6338#ifdef FEAT_SEARCH_EXTRA
6339 "extra_search",
6340#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006341#ifdef FEAT_SEARCHPATH
6342 "file_in_path",
6343#endif
6344#ifdef FEAT_FILTERPIPE
6345 "filterpipe",
6346#endif
6347#ifdef FEAT_FIND_ID
6348 "find_in_path",
6349#endif
6350#ifdef FEAT_FLOAT
6351 "float",
6352#endif
6353#ifdef FEAT_FOLDING
6354 "folding",
6355#endif
6356#ifdef FEAT_FOOTER
6357 "footer",
6358#endif
6359#if !defined(USE_SYSTEM) && defined(UNIX)
6360 "fork",
6361#endif
6362#ifdef FEAT_GETTEXT
6363 "gettext",
6364#endif
6365#ifdef FEAT_GUI
6366 "gui",
6367#endif
6368#ifdef FEAT_GUI_ATHENA
6369# ifdef FEAT_GUI_NEXTAW
6370 "gui_neXtaw",
6371# else
6372 "gui_athena",
6373# endif
6374#endif
6375#ifdef FEAT_GUI_GTK
6376 "gui_gtk",
6377# ifdef USE_GTK3
6378 "gui_gtk3",
6379# else
6380 "gui_gtk2",
6381# endif
6382#endif
6383#ifdef FEAT_GUI_GNOME
6384 "gui_gnome",
6385#endif
6386#ifdef FEAT_GUI_MAC
6387 "gui_mac",
6388#endif
6389#ifdef FEAT_GUI_MOTIF
6390 "gui_motif",
6391#endif
6392#ifdef FEAT_GUI_PHOTON
6393 "gui_photon",
6394#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006395#ifdef FEAT_GUI_MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006396 "gui_win32",
6397#endif
6398#ifdef FEAT_HANGULIN
6399 "hangul_input",
6400#endif
6401#if defined(HAVE_ICONV_H) && defined(USE_ICONV)
6402 "iconv",
6403#endif
6404#ifdef FEAT_INS_EXPAND
6405 "insert_expand",
6406#endif
6407#ifdef FEAT_JOB_CHANNEL
6408 "job",
6409#endif
6410#ifdef FEAT_JUMPLIST
6411 "jumplist",
6412#endif
6413#ifdef FEAT_KEYMAP
6414 "keymap",
6415#endif
Bram Moolenaar9532fe72016-07-29 22:50:35 +02006416 "lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006417#ifdef FEAT_LANGMAP
6418 "langmap",
6419#endif
6420#ifdef FEAT_LIBCALL
6421 "libcall",
6422#endif
6423#ifdef FEAT_LINEBREAK
6424 "linebreak",
6425#endif
6426#ifdef FEAT_LISP
6427 "lispindent",
6428#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006429 "listcmds",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006430#ifdef FEAT_LOCALMAP
6431 "localmap",
6432#endif
6433#ifdef FEAT_LUA
6434# ifndef DYNAMIC_LUA
6435 "lua",
6436# endif
6437#endif
6438#ifdef FEAT_MENU
6439 "menu",
6440#endif
6441#ifdef FEAT_SESSION
6442 "mksession",
6443#endif
6444#ifdef FEAT_MODIFY_FNAME
6445 "modify_fname",
6446#endif
6447#ifdef FEAT_MOUSE
6448 "mouse",
6449#endif
6450#ifdef FEAT_MOUSESHAPE
6451 "mouseshape",
6452#endif
6453#if defined(UNIX) || defined(VMS)
6454# ifdef FEAT_MOUSE_DEC
6455 "mouse_dec",
6456# endif
6457# ifdef FEAT_MOUSE_GPM
6458 "mouse_gpm",
6459# endif
6460# ifdef FEAT_MOUSE_JSB
6461 "mouse_jsbterm",
6462# endif
6463# ifdef FEAT_MOUSE_NET
6464 "mouse_netterm",
6465# endif
6466# ifdef FEAT_MOUSE_PTERM
6467 "mouse_pterm",
6468# endif
Bram Moolenaar2ace1bd2019-03-22 12:03:30 +01006469# ifdef FEAT_MOUSE_XTERM
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006470 "mouse_sgr",
6471# endif
6472# ifdef FEAT_SYSMOUSE
6473 "mouse_sysmouse",
6474# endif
6475# ifdef FEAT_MOUSE_URXVT
6476 "mouse_urxvt",
6477# endif
6478# ifdef FEAT_MOUSE_XTERM
6479 "mouse_xterm",
6480# endif
6481#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006482 "multi_byte",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006483#ifdef FEAT_MBYTE_IME
6484 "multi_byte_ime",
6485#endif
6486#ifdef FEAT_MULTI_LANG
6487 "multi_lang",
6488#endif
6489#ifdef FEAT_MZSCHEME
6490#ifndef DYNAMIC_MZSCHEME
6491 "mzscheme",
6492#endif
6493#endif
6494#ifdef FEAT_NUM64
6495 "num64",
6496#endif
6497#ifdef FEAT_OLE
6498 "ole",
6499#endif
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006500#ifdef FEAT_EVAL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006501 "packages",
Bram Moolenaar6183ccb2018-07-22 05:08:11 +02006502#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006503#ifdef FEAT_PATH_EXTRA
6504 "path_extra",
6505#endif
6506#ifdef FEAT_PERL
6507#ifndef DYNAMIC_PERL
6508 "perl",
6509#endif
6510#endif
6511#ifdef FEAT_PERSISTENT_UNDO
6512 "persistent_undo",
6513#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006514#if defined(FEAT_PYTHON)
6515 "python_compiled",
6516# if defined(DYNAMIC_PYTHON)
6517 "python_dynamic",
6518# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006519 "python",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006520 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006521# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006522#endif
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006523#if defined(FEAT_PYTHON3)
6524 "python3_compiled",
6525# if defined(DYNAMIC_PYTHON3)
6526 "python3_dynamic",
6527# else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006528 "python3",
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006529 "pythonx",
Bram Moolenaar84b242c2018-01-28 17:45:49 +01006530# endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006531#endif
6532#ifdef FEAT_POSTSCRIPT
6533 "postscript",
6534#endif
6535#ifdef FEAT_PRINTER
6536 "printer",
6537#endif
6538#ifdef FEAT_PROFILE
6539 "profile",
6540#endif
6541#ifdef FEAT_RELTIME
6542 "reltime",
6543#endif
6544#ifdef FEAT_QUICKFIX
6545 "quickfix",
6546#endif
6547#ifdef FEAT_RIGHTLEFT
6548 "rightleft",
6549#endif
6550#if defined(FEAT_RUBY) && !defined(DYNAMIC_RUBY)
6551 "ruby",
6552#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006553 "scrollbind",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006554#ifdef FEAT_CMDL_INFO
6555 "showcmd",
6556 "cmdline_info",
6557#endif
6558#ifdef FEAT_SIGNS
6559 "signs",
6560#endif
6561#ifdef FEAT_SMARTINDENT
6562 "smartindent",
6563#endif
6564#ifdef STARTUPTIME
6565 "startuptime",
6566#endif
6567#ifdef FEAT_STL_OPT
6568 "statusline",
6569#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006570#ifdef FEAT_NETBEANS_INTG
6571 "netbeans_intg",
6572#endif
6573#ifdef FEAT_SPELL
6574 "spell",
6575#endif
6576#ifdef FEAT_SYN_HL
6577 "syntax",
6578#endif
6579#if defined(USE_SYSTEM) || !defined(UNIX)
6580 "system",
6581#endif
6582#ifdef FEAT_TAG_BINS
6583 "tag_binary",
6584#endif
6585#ifdef FEAT_TAG_OLDSTATIC
6586 "tag_old_static",
6587#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006588#ifdef FEAT_TCL
6589# ifndef DYNAMIC_TCL
6590 "tcl",
6591# endif
6592#endif
6593#ifdef FEAT_TERMGUICOLORS
6594 "termguicolors",
6595#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006596#if defined(FEAT_TERMINAL) && !defined(MSWIN)
Bram Moolenaare4f25e42017-07-07 11:54:15 +02006597 "terminal",
6598#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006599#ifdef TERMINFO
6600 "terminfo",
6601#endif
6602#ifdef FEAT_TERMRESPONSE
6603 "termresponse",
6604#endif
6605#ifdef FEAT_TEXTOBJ
6606 "textobjects",
6607#endif
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006608#ifdef FEAT_TEXT_PROP
6609 "textprop",
6610#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006611#ifdef HAVE_TGETENT
6612 "tgetent",
6613#endif
6614#ifdef FEAT_TIMERS
6615 "timers",
6616#endif
6617#ifdef FEAT_TITLE
6618 "title",
6619#endif
6620#ifdef FEAT_TOOLBAR
6621 "toolbar",
6622#endif
6623#if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
6624 "unnamedplus",
6625#endif
6626#ifdef FEAT_USR_CMDS
6627 "user-commands", /* was accidentally included in 5.4 */
6628 "user_commands",
6629#endif
Bram Moolenaar04958cb2018-06-23 19:23:02 +02006630#ifdef FEAT_VARTABS
6631 "vartabs",
6632#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006633#ifdef FEAT_VIMINFO
6634 "viminfo",
6635#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006636 "vertsplit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006637 "virtualedit",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006638 "visual",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006639 "visualextra",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006640 "vreplace",
Bram Moolenaarff1e8792018-03-12 22:16:37 +01006641#ifdef FEAT_VTP
6642 "vtp",
6643#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006644#ifdef FEAT_WILDIGN
6645 "wildignore",
6646#endif
6647#ifdef FEAT_WILDMENU
6648 "wildmenu",
6649#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006650 "windows",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006651#ifdef FEAT_WAK
6652 "winaltkeys",
6653#endif
6654#ifdef FEAT_WRITEBACKUP
6655 "writebackup",
6656#endif
6657#ifdef FEAT_XIM
6658 "xim",
6659#endif
6660#ifdef FEAT_XFONTSET
6661 "xfontset",
6662#endif
6663#ifdef FEAT_XPM_W32
6664 "xpm",
6665 "xpm_w32", /* for backward compatibility */
6666#else
6667# if defined(HAVE_XPM)
6668 "xpm",
6669# endif
6670#endif
6671#ifdef USE_XSMP
6672 "xsmp",
6673#endif
6674#ifdef USE_XSMP_INTERACT
6675 "xsmp_interact",
6676#endif
6677#ifdef FEAT_XCLIPBOARD
6678 "xterm_clipboard",
6679#endif
6680#ifdef FEAT_XTERM_SAVE
6681 "xterm_save",
6682#endif
6683#if defined(UNIX) && defined(FEAT_X11)
6684 "X11",
6685#endif
6686 NULL
6687 };
6688
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006689 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006690 for (i = 0; has_list[i] != NULL; ++i)
6691 if (STRICMP(name, has_list[i]) == 0)
6692 {
6693 n = TRUE;
6694 break;
6695 }
6696
6697 if (n == FALSE)
6698 {
6699 if (STRNICMP(name, "patch", 5) == 0)
6700 {
6701 if (name[5] == '-'
6702 && STRLEN(name) >= 11
6703 && vim_isdigit(name[6])
6704 && vim_isdigit(name[8])
6705 && vim_isdigit(name[10]))
6706 {
6707 int major = atoi((char *)name + 6);
6708 int minor = atoi((char *)name + 8);
6709
6710 /* Expect "patch-9.9.01234". */
6711 n = (major < VIM_VERSION_MAJOR
6712 || (major == VIM_VERSION_MAJOR
6713 && (minor < VIM_VERSION_MINOR
6714 || (minor == VIM_VERSION_MINOR
6715 && has_patch(atoi((char *)name + 10))))));
6716 }
6717 else
6718 n = has_patch(atoi((char *)name + 5));
6719 }
6720 else if (STRICMP(name, "vim_starting") == 0)
6721 n = (starting != 0);
Bram Moolenaar2cab0e12016-11-24 15:09:07 +01006722 else if (STRICMP(name, "ttyin") == 0)
6723 n = mch_input_isatty();
6724 else if (STRICMP(name, "ttyout") == 0)
6725 n = stdout_isatty;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006726 else if (STRICMP(name, "multi_byte_encoding") == 0)
6727 n = has_mbyte;
Bram Moolenaar4f974752019-02-17 17:44:42 +01006728#if defined(FEAT_BEVAL) && defined(FEAT_GUI_MSWIN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006729 else if (STRICMP(name, "balloon_multiline") == 0)
6730 n = multiline_balloon_available();
6731#endif
6732#ifdef DYNAMIC_TCL
6733 else if (STRICMP(name, "tcl") == 0)
6734 n = tcl_enabled(FALSE);
6735#endif
6736#if defined(USE_ICONV) && defined(DYNAMIC_ICONV)
6737 else if (STRICMP(name, "iconv") == 0)
6738 n = iconv_enabled(FALSE);
6739#endif
6740#ifdef DYNAMIC_LUA
6741 else if (STRICMP(name, "lua") == 0)
6742 n = lua_enabled(FALSE);
6743#endif
6744#ifdef DYNAMIC_MZSCHEME
6745 else if (STRICMP(name, "mzscheme") == 0)
6746 n = mzscheme_enabled(FALSE);
6747#endif
6748#ifdef DYNAMIC_RUBY
6749 else if (STRICMP(name, "ruby") == 0)
6750 n = ruby_enabled(FALSE);
6751#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006752#ifdef DYNAMIC_PYTHON
6753 else if (STRICMP(name, "python") == 0)
6754 n = python_enabled(FALSE);
6755#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006756#ifdef DYNAMIC_PYTHON3
6757 else if (STRICMP(name, "python3") == 0)
6758 n = python3_enabled(FALSE);
6759#endif
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01006760#if defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3)
6761 else if (STRICMP(name, "pythonx") == 0)
6762 {
6763# if defined(DYNAMIC_PYTHON) && defined(DYNAMIC_PYTHON3)
6764 if (p_pyx == 0)
6765 n = python3_enabled(FALSE) || python_enabled(FALSE);
6766 else if (p_pyx == 3)
6767 n = python3_enabled(FALSE);
6768 else if (p_pyx == 2)
6769 n = python_enabled(FALSE);
6770# elif defined(DYNAMIC_PYTHON)
6771 n = python_enabled(FALSE);
6772# elif defined(DYNAMIC_PYTHON3)
6773 n = python3_enabled(FALSE);
6774# endif
6775 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006776#endif
6777#ifdef DYNAMIC_PERL
6778 else if (STRICMP(name, "perl") == 0)
6779 n = perl_enabled(FALSE);
6780#endif
6781#ifdef FEAT_GUI
6782 else if (STRICMP(name, "gui_running") == 0)
6783 n = (gui.in_use || gui.starting);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006784# ifdef FEAT_BROWSE
6785 else if (STRICMP(name, "browse") == 0)
6786 n = gui.in_use; /* gui_mch_browse() works when GUI is running */
6787# endif
6788#endif
6789#ifdef FEAT_SYN_HL
6790 else if (STRICMP(name, "syntax_items") == 0)
6791 n = syntax_present(curwin);
6792#endif
Bram Moolenaarcafafb32018-02-22 21:07:09 +01006793#ifdef FEAT_VTP
6794 else if (STRICMP(name, "vcon") == 0)
Bram Moolenaard8b37a52018-06-28 15:50:28 +02006795 n = is_term_win32() && has_vtp_working();
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006796#endif
6797#ifdef FEAT_NETBEANS_INTG
6798 else if (STRICMP(name, "netbeans_enabled") == 0)
6799 n = netbeans_active();
6800#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006801#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaara83e3962017-08-17 14:39:07 +02006802 else if (STRICMP(name, "terminal") == 0)
6803 n = terminal_enabled();
6804#endif
Bram Moolenaar4f974752019-02-17 17:44:42 +01006805#if defined(FEAT_TERMINAL) && defined(MSWIN)
Bram Moolenaaraa5df7e2019-02-03 14:53:10 +01006806 else if (STRICMP(name, "conpty") == 0)
6807 n = use_conpty();
6808#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006809 }
6810
6811 rettv->vval.v_number = n;
6812}
6813
6814/*
6815 * "has_key()" function
6816 */
6817 static void
6818f_has_key(typval_T *argvars, typval_T *rettv)
6819{
6820 if (argvars[0].v_type != VAR_DICT)
6821 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01006822 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006823 return;
6824 }
6825 if (argvars[0].vval.v_dict == NULL)
6826 return;
6827
6828 rettv->vval.v_number = dict_find(argvars[0].vval.v_dict,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006829 tv_get_string(&argvars[1]), -1) != NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006830}
6831
6832/*
6833 * "haslocaldir()" function
6834 */
6835 static void
6836f_haslocaldir(typval_T *argvars, typval_T *rettv)
6837{
6838 win_T *wp = NULL;
6839
6840 wp = find_tabwin(&argvars[0], &argvars[1]);
6841 rettv->vval.v_number = (wp != NULL && wp->w_localdir != NULL);
6842}
6843
6844/*
6845 * "hasmapto()" function
6846 */
6847 static void
6848f_hasmapto(typval_T *argvars, typval_T *rettv)
6849{
6850 char_u *name;
6851 char_u *mode;
6852 char_u buf[NUMBUFLEN];
6853 int abbr = FALSE;
6854
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006855 name = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006856 if (argvars[1].v_type == VAR_UNKNOWN)
6857 mode = (char_u *)"nvo";
6858 else
6859 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006860 mode = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006861 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006862 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006863 }
6864
6865 if (map_to_exists(name, mode, abbr))
6866 rettv->vval.v_number = TRUE;
6867 else
6868 rettv->vval.v_number = FALSE;
6869}
6870
6871/*
6872 * "histadd()" function
6873 */
6874 static void
6875f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
6876{
6877#ifdef FEAT_CMDHIST
6878 int histype;
6879 char_u *str;
6880 char_u buf[NUMBUFLEN];
6881#endif
6882
6883 rettv->vval.v_number = FALSE;
Bram Moolenaar8c62a082019-02-08 14:34:10 +01006884 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006885 return;
6886#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006887 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006888 histype = str != NULL ? get_histtype(str) : -1;
6889 if (histype >= 0)
6890 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006891 str = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006892 if (*str != NUL)
6893 {
6894 init_history();
6895 add_to_history(histype, str, FALSE, NUL);
6896 rettv->vval.v_number = TRUE;
6897 return;
6898 }
6899 }
6900#endif
6901}
6902
6903/*
6904 * "histdel()" function
6905 */
6906 static void
6907f_histdel(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
6908{
6909#ifdef FEAT_CMDHIST
6910 int n;
6911 char_u buf[NUMBUFLEN];
6912 char_u *str;
6913
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006914 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006915 if (str == NULL)
6916 n = 0;
6917 else if (argvars[1].v_type == VAR_UNKNOWN)
6918 /* only one argument: clear entire history */
6919 n = clr_history(get_histtype(str));
6920 else if (argvars[1].v_type == VAR_NUMBER)
6921 /* index given: remove that entry */
6922 n = del_history_idx(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006923 (int)tv_get_number(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006924 else
6925 /* string given: remove all matching entries */
6926 n = del_history_entry(get_histtype(str),
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006927 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006928 rettv->vval.v_number = n;
6929#endif
6930}
6931
6932/*
6933 * "histget()" function
6934 */
6935 static void
6936f_histget(typval_T *argvars UNUSED, typval_T *rettv)
6937{
6938#ifdef FEAT_CMDHIST
6939 int type;
6940 int idx;
6941 char_u *str;
6942
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006943 str = tv_get_string_chk(&argvars[0]); /* NULL on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006944 if (str == NULL)
6945 rettv->vval.v_string = NULL;
6946 else
6947 {
6948 type = get_histtype(str);
6949 if (argvars[1].v_type == VAR_UNKNOWN)
6950 idx = get_history_idx(type);
6951 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006952 idx = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006953 /* -1 on type error */
6954 rettv->vval.v_string = vim_strsave(get_history_entry(type, idx));
6955 }
6956#else
6957 rettv->vval.v_string = NULL;
6958#endif
6959 rettv->v_type = VAR_STRING;
6960}
6961
6962/*
6963 * "histnr()" function
6964 */
6965 static void
6966f_histnr(typval_T *argvars UNUSED, typval_T *rettv)
6967{
6968 int i;
6969
6970#ifdef FEAT_CMDHIST
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006971 char_u *history = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006972
6973 i = history == NULL ? HIST_CMD - 1 : get_histtype(history);
6974 if (i >= HIST_CMD && i < HIST_COUNT)
6975 i = get_history_idx(i);
6976 else
6977#endif
6978 i = -1;
6979 rettv->vval.v_number = i;
6980}
6981
6982/*
6983 * "highlightID(name)" function
6984 */
6985 static void
6986f_hlID(typval_T *argvars, typval_T *rettv)
6987{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006988 rettv->vval.v_number = syn_name2id(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006989}
6990
6991/*
6992 * "highlight_exists()" function
6993 */
6994 static void
6995f_hlexists(typval_T *argvars, typval_T *rettv)
6996{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01006997 rettv->vval.v_number = highlight_exists(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02006998}
6999
7000/*
7001 * "hostname()" function
7002 */
7003 static void
7004f_hostname(typval_T *argvars UNUSED, typval_T *rettv)
7005{
7006 char_u hostname[256];
7007
7008 mch_get_host_name(hostname, 256);
7009 rettv->v_type = VAR_STRING;
7010 rettv->vval.v_string = vim_strsave(hostname);
7011}
7012
7013/*
7014 * iconv() function
7015 */
7016 static void
7017f_iconv(typval_T *argvars UNUSED, typval_T *rettv)
7018{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007019 char_u buf1[NUMBUFLEN];
7020 char_u buf2[NUMBUFLEN];
7021 char_u *from, *to, *str;
7022 vimconv_T vimconv;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007023
7024 rettv->v_type = VAR_STRING;
7025 rettv->vval.v_string = NULL;
7026
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007027 str = tv_get_string(&argvars[0]);
7028 from = enc_canonize(enc_skip(tv_get_string_buf(&argvars[1], buf1)));
7029 to = enc_canonize(enc_skip(tv_get_string_buf(&argvars[2], buf2)));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007030 vimconv.vc_type = CONV_NONE;
7031 convert_setup(&vimconv, from, to);
7032
7033 /* If the encodings are equal, no conversion needed. */
7034 if (vimconv.vc_type == CONV_NONE)
7035 rettv->vval.v_string = vim_strsave(str);
7036 else
7037 rettv->vval.v_string = string_convert(&vimconv, str, NULL);
7038
7039 convert_setup(&vimconv, NULL, NULL);
7040 vim_free(from);
7041 vim_free(to);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007042}
7043
7044/*
7045 * "indent()" function
7046 */
7047 static void
7048f_indent(typval_T *argvars, typval_T *rettv)
7049{
7050 linenr_T lnum;
7051
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007052 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007053 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7054 rettv->vval.v_number = get_indent_lnum(lnum);
7055 else
7056 rettv->vval.v_number = -1;
7057}
7058
7059/*
7060 * "index()" function
7061 */
7062 static void
7063f_index(typval_T *argvars, typval_T *rettv)
7064{
7065 list_T *l;
7066 listitem_T *item;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007067 blob_T *b;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007068 long idx = 0;
7069 int ic = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007070 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007071
7072 rettv->vval.v_number = -1;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007073 if (argvars[0].v_type == VAR_BLOB)
7074 {
7075 typval_T tv;
7076 int start = 0;
7077
7078 if (argvars[2].v_type != VAR_UNKNOWN)
7079 {
7080 start = tv_get_number_chk(&argvars[2], &error);
7081 if (error)
7082 return;
7083 }
7084 b = argvars[0].vval.v_blob;
7085 if (b == NULL)
7086 return;
Bram Moolenaar05500ec2019-01-13 19:10:33 +01007087 if (start < 0)
7088 {
7089 start = blob_len(b) + start;
7090 if (start < 0)
7091 start = 0;
7092 }
7093
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007094 for (idx = start; idx < blob_len(b); ++idx)
7095 {
7096 tv.v_type = VAR_NUMBER;
7097 tv.vval.v_number = blob_get(b, idx);
7098 if (tv_equal(&tv, &argvars[1], ic, FALSE))
7099 {
7100 rettv->vval.v_number = idx;
7101 return;
7102 }
7103 }
7104 return;
7105 }
7106 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007107 {
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007108 emsg(_(e_listblobreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007109 return;
7110 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007111
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007112 l = argvars[0].vval.v_list;
7113 if (l != NULL)
7114 {
7115 item = l->lv_first;
7116 if (argvars[2].v_type != VAR_UNKNOWN)
7117 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007118 /* Start at specified item. Use the cached index that list_find()
7119 * sets, so that a negative number also works. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007120 item = list_find(l, (long)tv_get_number_chk(&argvars[2], &error));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007121 idx = l->lv_idx;
7122 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007123 ic = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007124 if (error)
7125 item = NULL;
7126 }
7127
7128 for ( ; item != NULL; item = item->li_next, ++idx)
7129 if (tv_equal(&item->li_tv, &argvars[1], ic, FALSE))
7130 {
7131 rettv->vval.v_number = idx;
7132 break;
7133 }
7134 }
7135}
7136
7137static int inputsecret_flag = 0;
7138
7139/*
7140 * "input()" function
7141 * Also handles inputsecret() when inputsecret is set.
7142 */
7143 static void
7144f_input(typval_T *argvars, typval_T *rettv)
7145{
7146 get_user_input(argvars, rettv, FALSE, inputsecret_flag);
7147}
7148
7149/*
7150 * "inputdialog()" function
7151 */
7152 static void
7153f_inputdialog(typval_T *argvars, typval_T *rettv)
7154{
7155#if defined(FEAT_GUI_TEXTDIALOG)
7156 /* Use a GUI dialog if the GUI is running and 'c' is not in 'guioptions' */
7157 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
7158 {
7159 char_u *message;
7160 char_u buf[NUMBUFLEN];
7161 char_u *defstr = (char_u *)"";
7162
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007163 message = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007164 if (argvars[1].v_type != VAR_UNKNOWN
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007165 && (defstr = tv_get_string_buf_chk(&argvars[1], buf)) != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007166 vim_strncpy(IObuff, defstr, IOSIZE - 1);
7167 else
7168 IObuff[0] = NUL;
7169 if (message != NULL && defstr != NULL
7170 && do_dialog(VIM_QUESTION, NULL, message,
7171 (char_u *)_("&OK\n&Cancel"), 1, IObuff, FALSE) == 1)
7172 rettv->vval.v_string = vim_strsave(IObuff);
7173 else
7174 {
7175 if (message != NULL && defstr != NULL
7176 && argvars[1].v_type != VAR_UNKNOWN
7177 && argvars[2].v_type != VAR_UNKNOWN)
7178 rettv->vval.v_string = vim_strsave(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007179 tv_get_string_buf(&argvars[2], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007180 else
7181 rettv->vval.v_string = NULL;
7182 }
7183 rettv->v_type = VAR_STRING;
7184 }
7185 else
7186#endif
7187 get_user_input(argvars, rettv, TRUE, inputsecret_flag);
7188}
7189
7190/*
7191 * "inputlist()" function
7192 */
7193 static void
7194f_inputlist(typval_T *argvars, typval_T *rettv)
7195{
7196 listitem_T *li;
7197 int selected;
7198 int mouse_used;
7199
7200#ifdef NO_CONSOLE_INPUT
Bram Moolenaar91d348a2017-07-29 20:16:03 +02007201 /* While starting up, there is no place to enter text. When running tests
7202 * with --not-a-term we assume feedkeys() will be used. */
7203 if (no_console_input() && !is_not_a_term())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007204 return;
7205#endif
7206 if (argvars[0].v_type != VAR_LIST || argvars[0].vval.v_list == NULL)
7207 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007208 semsg(_(e_listarg), "inputlist()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007209 return;
7210 }
7211
7212 msg_start();
7213 msg_row = Rows - 1; /* for when 'cmdheight' > 1 */
7214 lines_left = Rows; /* avoid more prompt */
7215 msg_scroll = TRUE;
7216 msg_clr_eos();
7217
7218 for (li = argvars[0].vval.v_list->lv_first; li != NULL; li = li->li_next)
7219 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007220 msg_puts((char *)tv_get_string(&li->li_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007221 msg_putchar('\n');
7222 }
7223
7224 /* Ask for choice. */
7225 selected = prompt_for_number(&mouse_used);
7226 if (mouse_used)
7227 selected -= lines_left;
7228
7229 rettv->vval.v_number = selected;
7230}
7231
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007232static garray_T ga_userinput = {0, 0, sizeof(tasave_T), 4, NULL};
7233
7234/*
7235 * "inputrestore()" function
7236 */
7237 static void
7238f_inputrestore(typval_T *argvars UNUSED, typval_T *rettv)
7239{
7240 if (ga_userinput.ga_len > 0)
7241 {
7242 --ga_userinput.ga_len;
7243 restore_typeahead((tasave_T *)(ga_userinput.ga_data)
7244 + ga_userinput.ga_len);
7245 /* default return is zero == OK */
7246 }
7247 else if (p_verbose > 1)
7248 {
Bram Moolenaar32526b32019-01-19 17:43:09 +01007249 verb_msg(_("called inputrestore() more often than inputsave()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007250 rettv->vval.v_number = 1; /* Failed */
7251 }
7252}
7253
7254/*
7255 * "inputsave()" function
7256 */
7257 static void
7258f_inputsave(typval_T *argvars UNUSED, typval_T *rettv)
7259{
7260 /* Add an entry to the stack of typeahead storage. */
7261 if (ga_grow(&ga_userinput, 1) == OK)
7262 {
7263 save_typeahead((tasave_T *)(ga_userinput.ga_data)
7264 + ga_userinput.ga_len);
7265 ++ga_userinput.ga_len;
7266 /* default return is zero == OK */
7267 }
7268 else
7269 rettv->vval.v_number = 1; /* Failed */
7270}
7271
7272/*
7273 * "inputsecret()" function
7274 */
7275 static void
7276f_inputsecret(typval_T *argvars, typval_T *rettv)
7277{
7278 ++cmdline_star;
7279 ++inputsecret_flag;
7280 f_input(argvars, rettv);
7281 --cmdline_star;
7282 --inputsecret_flag;
7283}
7284
7285/*
7286 * "insert()" function
7287 */
7288 static void
7289f_insert(typval_T *argvars, typval_T *rettv)
7290{
7291 long before = 0;
7292 listitem_T *item;
7293 list_T *l;
7294 int error = FALSE;
7295
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007296 if (argvars[0].v_type == VAR_BLOB)
7297 {
7298 int val, len;
7299 char_u *p;
7300
7301 len = blob_len(argvars[0].vval.v_blob);
7302 if (argvars[2].v_type != VAR_UNKNOWN)
7303 {
7304 before = (long)tv_get_number_chk(&argvars[2], &error);
7305 if (error)
7306 return; // type error; errmsg already given
7307 if (before < 0 || before > len)
7308 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007309 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007310 return;
7311 }
7312 }
7313 val = tv_get_number_chk(&argvars[1], &error);
7314 if (error)
7315 return;
7316 if (val < 0 || val > 255)
7317 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007318 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007319 return;
7320 }
7321
7322 if (ga_grow(&argvars[0].vval.v_blob->bv_ga, 1) == FAIL)
7323 return;
7324 p = (char_u *)argvars[0].vval.v_blob->bv_ga.ga_data;
7325 mch_memmove(p + before + 1, p + before, (size_t)len - before);
7326 *(p + before) = val;
7327 ++argvars[0].vval.v_blob->bv_ga.ga_len;
7328
7329 copy_tv(&argvars[0], rettv);
7330 }
7331 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01007332 semsg(_(e_listblobarg), "insert()");
Bram Moolenaar05c00c02019-02-11 22:00:11 +01007333 else if ((l = argvars[0].vval.v_list) != NULL
7334 && !var_check_lock(l->lv_lock,
7335 (char_u *)N_("insert() argument"), TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007336 {
7337 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007338 before = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007339 if (error)
7340 return; /* type error; errmsg already given */
7341
7342 if (before == l->lv_len)
7343 item = NULL;
7344 else
7345 {
7346 item = list_find(l, before);
7347 if (item == NULL)
7348 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007349 semsg(_(e_listidx), before);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007350 l = NULL;
7351 }
7352 }
7353 if (l != NULL)
7354 {
7355 list_insert_tv(l, &argvars[1], item);
7356 copy_tv(&argvars[0], rettv);
7357 }
7358 }
7359}
7360
7361/*
7362 * "invert(expr)" function
7363 */
7364 static void
7365f_invert(typval_T *argvars, typval_T *rettv)
7366{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007367 rettv->vval.v_number = ~tv_get_number_chk(&argvars[0], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007368}
7369
7370/*
7371 * "isdirectory()" function
7372 */
7373 static void
7374f_isdirectory(typval_T *argvars, typval_T *rettv)
7375{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007376 rettv->vval.v_number = mch_isdir(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007377}
7378
7379/*
7380 * Return TRUE if typeval "tv" is locked: Either that value is locked itself
7381 * or it refers to a List or Dictionary that is locked.
7382 */
7383 static int
7384tv_islocked(typval_T *tv)
7385{
7386 return (tv->v_lock & VAR_LOCKED)
7387 || (tv->v_type == VAR_LIST
7388 && tv->vval.v_list != NULL
7389 && (tv->vval.v_list->lv_lock & VAR_LOCKED))
7390 || (tv->v_type == VAR_DICT
7391 && tv->vval.v_dict != NULL
7392 && (tv->vval.v_dict->dv_lock & VAR_LOCKED));
7393}
7394
7395/*
7396 * "islocked()" function
7397 */
7398 static void
7399f_islocked(typval_T *argvars, typval_T *rettv)
7400{
7401 lval_T lv;
7402 char_u *end;
7403 dictitem_T *di;
7404
7405 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007406 end = get_lval(tv_get_string(&argvars[0]), NULL, &lv, FALSE, FALSE,
Bram Moolenaar3a257732017-02-21 20:47:13 +01007407 GLV_NO_AUTOLOAD | GLV_READ_ONLY, FNE_CHECK_START);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007408 if (end != NULL && lv.ll_name != NULL)
7409 {
7410 if (*end != NUL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007411 emsg(_(e_trailing));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007412 else
7413 {
7414 if (lv.ll_tv == NULL)
7415 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007416 di = find_var(lv.ll_name, NULL, TRUE);
7417 if (di != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007418 {
Bram Moolenaar79518e22017-02-17 16:31:35 +01007419 /* Consider a variable locked when:
7420 * 1. the variable itself is locked
7421 * 2. the value of the variable is locked.
7422 * 3. the List or Dict value is locked.
7423 */
7424 rettv->vval.v_number = ((di->di_flags & DI_FLAGS_LOCK)
7425 || tv_islocked(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007426 }
7427 }
7428 else if (lv.ll_range)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007429 emsg(_("E786: Range not allowed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007430 else if (lv.ll_newkey != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007431 semsg(_(e_dictkey), lv.ll_newkey);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007432 else if (lv.ll_list != NULL)
7433 /* List item. */
7434 rettv->vval.v_number = tv_islocked(&lv.ll_li->li_tv);
7435 else
7436 /* Dictionary item. */
7437 rettv->vval.v_number = tv_islocked(&lv.ll_di->di_tv);
7438 }
7439 }
7440
7441 clear_lval(&lv);
7442}
7443
7444#if defined(FEAT_FLOAT) && defined(HAVE_MATH_H)
7445/*
7446 * "isnan()" function
7447 */
7448 static void
7449f_isnan(typval_T *argvars, typval_T *rettv)
7450{
7451 rettv->vval.v_number = argvars[0].v_type == VAR_FLOAT
7452 && isnan(argvars[0].vval.v_float);
7453}
7454#endif
7455
7456/*
7457 * "items(dict)" function
7458 */
7459 static void
7460f_items(typval_T *argvars, typval_T *rettv)
7461{
7462 dict_list(argvars, rettv, 2);
7463}
7464
7465#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
7466/*
7467 * Get the job from the argument.
7468 * Returns NULL if the job is invalid.
7469 */
7470 static job_T *
7471get_job_arg(typval_T *tv)
7472{
7473 job_T *job;
7474
7475 if (tv->v_type != VAR_JOB)
7476 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007477 semsg(_(e_invarg2), tv_get_string(tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007478 return NULL;
7479 }
7480 job = tv->vval.v_job;
7481
7482 if (job == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007483 emsg(_("E916: not a valid job"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007484 return job;
7485}
7486
7487/*
7488 * "job_getchannel()" function
7489 */
7490 static void
7491f_job_getchannel(typval_T *argvars, typval_T *rettv)
7492{
7493 job_T *job = get_job_arg(&argvars[0]);
7494
7495 if (job != NULL)
7496 {
7497 rettv->v_type = VAR_CHANNEL;
7498 rettv->vval.v_channel = job->jv_channel;
7499 if (job->jv_channel != NULL)
7500 ++job->jv_channel->ch_refcount;
7501 }
7502}
7503
7504/*
7505 * "job_info()" function
7506 */
7507 static void
7508f_job_info(typval_T *argvars, typval_T *rettv)
7509{
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007510 if (argvars[0].v_type != VAR_UNKNOWN)
7511 {
7512 job_T *job = get_job_arg(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007513
Bram Moolenaare1fc5152018-04-21 19:49:08 +02007514 if (job != NULL && rettv_dict_alloc(rettv) != FAIL)
7515 job_info(job, rettv->vval.v_dict);
7516 }
7517 else if (rettv_list_alloc(rettv) == OK)
7518 job_info_all(rettv->vval.v_list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007519}
7520
7521/*
7522 * "job_setoptions()" function
7523 */
7524 static void
7525f_job_setoptions(typval_T *argvars, typval_T *rettv UNUSED)
7526{
7527 job_T *job = get_job_arg(&argvars[0]);
7528 jobopt_T opt;
7529
7530 if (job == NULL)
7531 return;
7532 clear_job_options(&opt);
Bram Moolenaar08d384f2017-08-11 21:51:23 +02007533 if (get_job_options(&argvars[1], &opt, JO_STOPONEXIT + JO_EXIT_CB, 0) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007534 job_set_options(job, &opt);
7535 free_job_options(&opt);
7536}
7537
7538/*
7539 * "job_start()" function
7540 */
7541 static void
7542f_job_start(typval_T *argvars, typval_T *rettv)
7543{
7544 rettv->v_type = VAR_JOB;
7545 if (check_restricted() || check_secure())
7546 return;
Bram Moolenaar493359e2018-06-12 20:25:52 +02007547 rettv->vval.v_job = job_start(argvars, NULL, NULL, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007548}
7549
7550/*
7551 * "job_status()" function
7552 */
7553 static void
7554f_job_status(typval_T *argvars, typval_T *rettv)
7555{
7556 job_T *job = get_job_arg(&argvars[0]);
7557
7558 if (job != NULL)
7559 {
7560 rettv->v_type = VAR_STRING;
7561 rettv->vval.v_string = vim_strsave((char_u *)job_status(job));
7562 }
7563}
7564
7565/*
7566 * "job_stop()" function
7567 */
7568 static void
7569f_job_stop(typval_T *argvars, typval_T *rettv)
7570{
7571 job_T *job = get_job_arg(&argvars[0]);
7572
7573 if (job != NULL)
Bram Moolenaar96ca27a2017-07-17 23:20:24 +02007574 rettv->vval.v_number = job_stop(job, argvars, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007575}
7576#endif
7577
7578/*
7579 * "join()" function
7580 */
7581 static void
7582f_join(typval_T *argvars, typval_T *rettv)
7583{
7584 garray_T ga;
7585 char_u *sep;
7586
7587 if (argvars[0].v_type != VAR_LIST)
7588 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007589 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007590 return;
7591 }
7592 if (argvars[0].vval.v_list == NULL)
7593 return;
7594 if (argvars[1].v_type == VAR_UNKNOWN)
7595 sep = (char_u *)" ";
7596 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007597 sep = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007598
7599 rettv->v_type = VAR_STRING;
7600
7601 if (sep != NULL)
7602 {
7603 ga_init2(&ga, (int)sizeof(char), 80);
7604 list_join(&ga, argvars[0].vval.v_list, sep, TRUE, FALSE, 0);
7605 ga_append(&ga, NUL);
7606 rettv->vval.v_string = (char_u *)ga.ga_data;
7607 }
7608 else
7609 rettv->vval.v_string = NULL;
7610}
7611
7612/*
7613 * "js_decode()" function
7614 */
7615 static void
7616f_js_decode(typval_T *argvars, typval_T *rettv)
7617{
7618 js_read_T reader;
7619
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007620 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007621 reader.js_fill = NULL;
7622 reader.js_used = 0;
7623 if (json_decode_all(&reader, rettv, JSON_JS) != OK)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007624 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007625}
7626
7627/*
7628 * "js_encode()" function
7629 */
7630 static void
7631f_js_encode(typval_T *argvars, typval_T *rettv)
7632{
7633 rettv->v_type = VAR_STRING;
7634 rettv->vval.v_string = json_encode(&argvars[0], JSON_JS);
7635}
7636
7637/*
7638 * "json_decode()" function
7639 */
7640 static void
7641f_json_decode(typval_T *argvars, typval_T *rettv)
7642{
7643 js_read_T reader;
7644
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007645 reader.js_buf = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007646 reader.js_fill = NULL;
7647 reader.js_used = 0;
Bram Moolenaar03c60c12017-01-10 15:15:37 +01007648 json_decode_all(&reader, rettv, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007649}
7650
7651/*
7652 * "json_encode()" function
7653 */
7654 static void
7655f_json_encode(typval_T *argvars, typval_T *rettv)
7656{
7657 rettv->v_type = VAR_STRING;
7658 rettv->vval.v_string = json_encode(&argvars[0], 0);
7659}
7660
7661/*
7662 * "keys()" function
7663 */
7664 static void
7665f_keys(typval_T *argvars, typval_T *rettv)
7666{
7667 dict_list(argvars, rettv, 0);
7668}
7669
7670/*
7671 * "last_buffer_nr()" function.
7672 */
7673 static void
7674f_last_buffer_nr(typval_T *argvars UNUSED, typval_T *rettv)
7675{
7676 int n = 0;
7677 buf_T *buf;
7678
Bram Moolenaar29323592016-07-24 22:04:11 +02007679 FOR_ALL_BUFFERS(buf)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007680 if (n < buf->b_fnum)
7681 n = buf->b_fnum;
7682
7683 rettv->vval.v_number = n;
7684}
7685
7686/*
7687 * "len()" function
7688 */
7689 static void
7690f_len(typval_T *argvars, typval_T *rettv)
7691{
7692 switch (argvars[0].v_type)
7693 {
7694 case VAR_STRING:
7695 case VAR_NUMBER:
7696 rettv->vval.v_number = (varnumber_T)STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007697 tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007698 break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01007699 case VAR_BLOB:
7700 rettv->vval.v_number = blob_len(argvars[0].vval.v_blob);
7701 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007702 case VAR_LIST:
7703 rettv->vval.v_number = list_len(argvars[0].vval.v_list);
7704 break;
7705 case VAR_DICT:
7706 rettv->vval.v_number = dict_len(argvars[0].vval.v_dict);
7707 break;
7708 case VAR_UNKNOWN:
7709 case VAR_SPECIAL:
7710 case VAR_FLOAT:
7711 case VAR_FUNC:
7712 case VAR_PARTIAL:
7713 case VAR_JOB:
7714 case VAR_CHANNEL:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01007715 emsg(_("E701: Invalid type for len()"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007716 break;
7717 }
7718}
7719
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007720 static void
Bram Moolenaar6d721c72017-01-17 16:56:28 +01007721libcall_common(typval_T *argvars UNUSED, typval_T *rettv, int type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007722{
7723#ifdef FEAT_LIBCALL
7724 char_u *string_in;
7725 char_u **string_result;
7726 int nr_result;
7727#endif
7728
7729 rettv->v_type = type;
7730 if (type != VAR_NUMBER)
7731 rettv->vval.v_string = NULL;
7732
7733 if (check_restricted() || check_secure())
7734 return;
7735
7736#ifdef FEAT_LIBCALL
Bram Moolenaar9af41842016-09-25 21:45:05 +02007737 /* The first two args must be strings, otherwise it's meaningless */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007738 if (argvars[0].v_type == VAR_STRING && argvars[1].v_type == VAR_STRING)
7739 {
7740 string_in = NULL;
7741 if (argvars[2].v_type == VAR_STRING)
7742 string_in = argvars[2].vval.v_string;
7743 if (type == VAR_NUMBER)
7744 string_result = NULL;
7745 else
7746 string_result = &rettv->vval.v_string;
7747 if (mch_libcall(argvars[0].vval.v_string,
7748 argvars[1].vval.v_string,
7749 string_in,
7750 argvars[2].vval.v_number,
7751 string_result,
7752 &nr_result) == OK
7753 && type == VAR_NUMBER)
7754 rettv->vval.v_number = nr_result;
7755 }
7756#endif
7757}
7758
7759/*
7760 * "libcall()" function
7761 */
7762 static void
7763f_libcall(typval_T *argvars, typval_T *rettv)
7764{
7765 libcall_common(argvars, rettv, VAR_STRING);
7766}
7767
7768/*
7769 * "libcallnr()" function
7770 */
7771 static void
7772f_libcallnr(typval_T *argvars, typval_T *rettv)
7773{
7774 libcall_common(argvars, rettv, VAR_NUMBER);
7775}
7776
7777/*
7778 * "line(string)" function
7779 */
7780 static void
7781f_line(typval_T *argvars, typval_T *rettv)
7782{
7783 linenr_T lnum = 0;
7784 pos_T *fp;
7785 int fnum;
7786
7787 fp = var2fpos(&argvars[0], TRUE, &fnum);
7788 if (fp != NULL)
7789 lnum = fp->lnum;
7790 rettv->vval.v_number = lnum;
7791}
7792
7793/*
7794 * "line2byte(lnum)" function
7795 */
7796 static void
7797f_line2byte(typval_T *argvars UNUSED, typval_T *rettv)
7798{
7799#ifndef FEAT_BYTEOFF
7800 rettv->vval.v_number = -1;
7801#else
7802 linenr_T lnum;
7803
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007804 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007805 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count + 1)
7806 rettv->vval.v_number = -1;
7807 else
7808 rettv->vval.v_number = ml_find_line_or_offset(curbuf, lnum, NULL);
7809 if (rettv->vval.v_number >= 0)
7810 ++rettv->vval.v_number;
7811#endif
7812}
7813
7814/*
7815 * "lispindent(lnum)" function
7816 */
7817 static void
7818f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
7819{
7820#ifdef FEAT_LISP
7821 pos_T pos;
7822 linenr_T lnum;
7823
7824 pos = curwin->w_cursor;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007825 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007826 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
7827 {
7828 curwin->w_cursor.lnum = lnum;
7829 rettv->vval.v_number = get_lisp_indent();
7830 curwin->w_cursor = pos;
7831 }
7832 else
7833#endif
7834 rettv->vval.v_number = -1;
7835}
7836
7837/*
7838 * "localtime()" function
7839 */
7840 static void
7841f_localtime(typval_T *argvars UNUSED, typval_T *rettv)
7842{
7843 rettv->vval.v_number = (varnumber_T)time(NULL);
7844}
7845
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007846 static void
7847get_maparg(typval_T *argvars, typval_T *rettv, int exact)
7848{
7849 char_u *keys;
7850 char_u *which;
7851 char_u buf[NUMBUFLEN];
7852 char_u *keys_buf = NULL;
7853 char_u *rhs;
7854 int mode;
7855 int abbr = FALSE;
7856 int get_dict = FALSE;
7857 mapblock_T *mp;
7858 int buffer_local;
7859
7860 /* return empty string for failure */
7861 rettv->v_type = VAR_STRING;
7862 rettv->vval.v_string = NULL;
7863
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007864 keys = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007865 if (*keys == NUL)
7866 return;
7867
7868 if (argvars[1].v_type != VAR_UNKNOWN)
7869 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007870 which = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007871 if (argvars[2].v_type != VAR_UNKNOWN)
7872 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007873 abbr = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007874 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007875 get_dict = (int)tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007876 }
7877 }
7878 else
7879 which = (char_u *)"";
7880 if (which == NULL)
7881 return;
7882
7883 mode = get_map_mode(&which, 0);
7884
7885 keys = replace_termcodes(keys, &keys_buf, TRUE, TRUE, FALSE);
7886 rhs = check_map(keys, mode, exact, FALSE, abbr, &mp, &buffer_local);
7887 vim_free(keys_buf);
7888
7889 if (!get_dict)
7890 {
7891 /* Return a string. */
7892 if (rhs != NULL)
Bram Moolenaarf88a5bc2018-05-21 13:28:44 +02007893 {
7894 if (*rhs == NUL)
7895 rettv->vval.v_string = vim_strsave((char_u *)"<Nop>");
7896 else
7897 rettv->vval.v_string = str2special_save(rhs, FALSE);
7898 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007899
7900 }
7901 else if (rettv_dict_alloc(rettv) != FAIL && rhs != NULL)
7902 {
7903 /* Return a dictionary. */
7904 char_u *lhs = str2special_save(mp->m_keys, TRUE);
7905 char_u *mapmode = map_mode_to_chars(mp->m_mode);
7906 dict_T *dict = rettv->vval.v_dict;
7907
Bram Moolenaare0be1672018-07-08 16:50:37 +02007908 dict_add_string(dict, "lhs", lhs);
7909 dict_add_string(dict, "rhs", mp->m_orig_str);
7910 dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
7911 dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
7912 dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
Bram Moolenaarf29c1c62018-09-10 21:05:02 +02007913 dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
7914 dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
Bram Moolenaare0be1672018-07-08 16:50:37 +02007915 dict_add_number(dict, "buffer", (long)buffer_local);
7916 dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
7917 dict_add_string(dict, "mode", mapmode);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007918
7919 vim_free(lhs);
7920 vim_free(mapmode);
7921 }
7922}
7923
7924#ifdef FEAT_FLOAT
7925/*
7926 * "log()" function
7927 */
7928 static void
7929f_log(typval_T *argvars, typval_T *rettv)
7930{
7931 float_T f = 0.0;
7932
7933 rettv->v_type = VAR_FLOAT;
7934 if (get_float_arg(argvars, &f) == OK)
7935 rettv->vval.v_float = log(f);
7936 else
7937 rettv->vval.v_float = 0.0;
7938}
7939
7940/*
7941 * "log10()" function
7942 */
7943 static void
7944f_log10(typval_T *argvars, typval_T *rettv)
7945{
7946 float_T f = 0.0;
7947
7948 rettv->v_type = VAR_FLOAT;
7949 if (get_float_arg(argvars, &f) == OK)
7950 rettv->vval.v_float = log10(f);
7951 else
7952 rettv->vval.v_float = 0.0;
7953}
7954#endif
7955
7956#ifdef FEAT_LUA
7957/*
7958 * "luaeval()" function
7959 */
7960 static void
7961f_luaeval(typval_T *argvars, typval_T *rettv)
7962{
7963 char_u *str;
7964 char_u buf[NUMBUFLEN];
7965
Bram Moolenaar8c62a082019-02-08 14:34:10 +01007966 if (check_restricted() || check_secure())
7967 return;
7968
Bram Moolenaard155d7a2018-12-21 16:04:21 +01007969 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02007970 do_luaeval(str, argvars + 1, rettv);
7971}
7972#endif
7973
7974/*
7975 * "map()" function
7976 */
7977 static void
7978f_map(typval_T *argvars, typval_T *rettv)
7979{
7980 filter_map(argvars, rettv, TRUE);
7981}
7982
7983/*
7984 * "maparg()" function
7985 */
7986 static void
7987f_maparg(typval_T *argvars, typval_T *rettv)
7988{
7989 get_maparg(argvars, rettv, TRUE);
7990}
7991
7992/*
7993 * "mapcheck()" function
7994 */
7995 static void
7996f_mapcheck(typval_T *argvars, typval_T *rettv)
7997{
7998 get_maparg(argvars, rettv, FALSE);
7999}
8000
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008001typedef enum
8002{
8003 MATCH_END, /* matchend() */
8004 MATCH_MATCH, /* match() */
8005 MATCH_STR, /* matchstr() */
8006 MATCH_LIST, /* matchlist() */
8007 MATCH_POS /* matchstrpos() */
8008} matchtype_T;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008009
8010 static void
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008011find_some_match(typval_T *argvars, typval_T *rettv, matchtype_T type)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008012{
8013 char_u *str = NULL;
8014 long len = 0;
8015 char_u *expr = NULL;
8016 char_u *pat;
8017 regmatch_T regmatch;
8018 char_u patbuf[NUMBUFLEN];
8019 char_u strbuf[NUMBUFLEN];
8020 char_u *save_cpo;
8021 long start = 0;
8022 long nth = 1;
8023 colnr_T startcol = 0;
8024 int match = 0;
8025 list_T *l = NULL;
8026 listitem_T *li = NULL;
8027 long idx = 0;
8028 char_u *tofree = NULL;
8029
8030 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
8031 save_cpo = p_cpo;
8032 p_cpo = (char_u *)"";
8033
8034 rettv->vval.v_number = -1;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008035 if (type == MATCH_LIST || type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008036 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008037 /* type MATCH_LIST: return empty list when there are no matches.
8038 * type MATCH_POS: return ["", -1, -1, -1] */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008039 if (rettv_list_alloc(rettv) == FAIL)
8040 goto theend;
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008041 if (type == MATCH_POS
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008042 && (list_append_string(rettv->vval.v_list,
8043 (char_u *)"", 0) == FAIL
8044 || list_append_number(rettv->vval.v_list,
8045 (varnumber_T)-1) == FAIL
8046 || list_append_number(rettv->vval.v_list,
8047 (varnumber_T)-1) == FAIL
8048 || list_append_number(rettv->vval.v_list,
8049 (varnumber_T)-1) == FAIL))
8050 {
8051 list_free(rettv->vval.v_list);
8052 rettv->vval.v_list = NULL;
8053 goto theend;
8054 }
8055 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008056 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008057 {
8058 rettv->v_type = VAR_STRING;
8059 rettv->vval.v_string = NULL;
8060 }
8061
8062 if (argvars[0].v_type == VAR_LIST)
8063 {
8064 if ((l = argvars[0].vval.v_list) == NULL)
8065 goto theend;
8066 li = l->lv_first;
8067 }
8068 else
8069 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008070 expr = str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008071 len = (long)STRLEN(str);
8072 }
8073
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008074 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008075 if (pat == NULL)
8076 goto theend;
8077
8078 if (argvars[2].v_type != VAR_UNKNOWN)
8079 {
8080 int error = FALSE;
8081
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008082 start = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008083 if (error)
8084 goto theend;
8085 if (l != NULL)
8086 {
8087 li = list_find(l, start);
8088 if (li == NULL)
8089 goto theend;
8090 idx = l->lv_idx; /* use the cached index */
8091 }
8092 else
8093 {
8094 if (start < 0)
8095 start = 0;
8096 if (start > len)
8097 goto theend;
8098 /* When "count" argument is there ignore matches before "start",
8099 * otherwise skip part of the string. Differs when pattern is "^"
8100 * or "\<". */
8101 if (argvars[3].v_type != VAR_UNKNOWN)
8102 startcol = start;
8103 else
8104 {
8105 str += start;
8106 len -= start;
8107 }
8108 }
8109
8110 if (argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008111 nth = (long)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008112 if (error)
8113 goto theend;
8114 }
8115
8116 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
8117 if (regmatch.regprog != NULL)
8118 {
8119 regmatch.rm_ic = p_ic;
8120
8121 for (;;)
8122 {
8123 if (l != NULL)
8124 {
8125 if (li == NULL)
8126 {
8127 match = FALSE;
8128 break;
8129 }
8130 vim_free(tofree);
8131 expr = str = echo_string(&li->li_tv, &tofree, strbuf, 0);
8132 if (str == NULL)
8133 break;
8134 }
8135
8136 match = vim_regexec_nl(&regmatch, str, (colnr_T)startcol);
8137
8138 if (match && --nth <= 0)
8139 break;
8140 if (l == NULL && !match)
8141 break;
8142
8143 /* Advance to just after the match. */
8144 if (l != NULL)
8145 {
8146 li = li->li_next;
8147 ++idx;
8148 }
8149 else
8150 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008151 startcol = (colnr_T)(regmatch.startp[0]
8152 + (*mb_ptr2len)(regmatch.startp[0]) - str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008153 if (startcol > (colnr_T)len
8154 || str + startcol <= regmatch.startp[0])
8155 {
8156 match = FALSE;
8157 break;
8158 }
8159 }
8160 }
8161
8162 if (match)
8163 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008164 if (type == MATCH_POS)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008165 {
8166 listitem_T *li1 = rettv->vval.v_list->lv_first;
8167 listitem_T *li2 = li1->li_next;
8168 listitem_T *li3 = li2->li_next;
8169 listitem_T *li4 = li3->li_next;
8170
8171 vim_free(li1->li_tv.vval.v_string);
8172 li1->li_tv.vval.v_string = vim_strnsave(regmatch.startp[0],
8173 (int)(regmatch.endp[0] - regmatch.startp[0]));
8174 li3->li_tv.vval.v_number =
8175 (varnumber_T)(regmatch.startp[0] - expr);
8176 li4->li_tv.vval.v_number =
8177 (varnumber_T)(regmatch.endp[0] - expr);
8178 if (l != NULL)
8179 li2->li_tv.vval.v_number = (varnumber_T)idx;
8180 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008181 else if (type == MATCH_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008182 {
8183 int i;
8184
8185 /* return list with matched string and submatches */
8186 for (i = 0; i < NSUBEXP; ++i)
8187 {
8188 if (regmatch.endp[i] == NULL)
8189 {
8190 if (list_append_string(rettv->vval.v_list,
8191 (char_u *)"", 0) == FAIL)
8192 break;
8193 }
8194 else if (list_append_string(rettv->vval.v_list,
8195 regmatch.startp[i],
8196 (int)(regmatch.endp[i] - regmatch.startp[i]))
8197 == FAIL)
8198 break;
8199 }
8200 }
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008201 else if (type == MATCH_STR)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008202 {
8203 /* return matched string */
8204 if (l != NULL)
8205 copy_tv(&li->li_tv, rettv);
8206 else
8207 rettv->vval.v_string = vim_strnsave(regmatch.startp[0],
8208 (int)(regmatch.endp[0] - regmatch.startp[0]));
8209 }
8210 else if (l != NULL)
8211 rettv->vval.v_number = idx;
8212 else
8213 {
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008214 if (type != MATCH_END)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008215 rettv->vval.v_number =
8216 (varnumber_T)(regmatch.startp[0] - str);
8217 else
8218 rettv->vval.v_number =
8219 (varnumber_T)(regmatch.endp[0] - str);
8220 rettv->vval.v_number += (varnumber_T)(str - expr);
8221 }
8222 }
8223 vim_regfree(regmatch.regprog);
8224 }
8225
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008226theend:
8227 if (type == MATCH_POS && l == NULL && rettv->vval.v_list != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008228 /* matchstrpos() without a list: drop the second item. */
8229 listitem_remove(rettv->vval.v_list,
8230 rettv->vval.v_list->lv_first->li_next);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008231 vim_free(tofree);
8232 p_cpo = save_cpo;
8233}
8234
8235/*
8236 * "match()" function
8237 */
8238 static void
8239f_match(typval_T *argvars, typval_T *rettv)
8240{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008241 find_some_match(argvars, rettv, MATCH_MATCH);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008242}
8243
Bram Moolenaar95e51472018-07-28 16:55:56 +02008244#ifdef FEAT_SEARCH_EXTRA
8245 static int
8246matchadd_dict_arg(typval_T *tv, char_u **conceal_char, win_T **win)
8247{
8248 dictitem_T *di;
8249
8250 if (tv->v_type != VAR_DICT)
8251 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008252 emsg(_(e_dictreq));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008253 return FAIL;
8254 }
8255
8256 if (dict_find(tv->vval.v_dict, (char_u *)"conceal", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +01008257 *conceal_char = dict_get_string(tv->vval.v_dict,
Bram Moolenaar95e51472018-07-28 16:55:56 +02008258 (char_u *)"conceal", FALSE);
8259
8260 if ((di = dict_find(tv->vval.v_dict, (char_u *)"window", -1)) != NULL)
8261 {
Bram Moolenaarbabfcf52018-10-25 13:11:16 +02008262 *win = find_win_by_nr_or_id(&di->di_tv);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008263 if (*win == NULL)
8264 {
Bram Moolenaaraff74912019-03-30 18:11:49 +01008265 emsg(_(e_invalwindow));
Bram Moolenaar95e51472018-07-28 16:55:56 +02008266 return FAIL;
8267 }
8268 }
8269
8270 return OK;
8271}
8272#endif
8273
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008274/*
8275 * "matchadd()" function
8276 */
8277 static void
8278f_matchadd(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8279{
8280#ifdef FEAT_SEARCH_EXTRA
8281 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008282 char_u *grp = tv_get_string_buf_chk(&argvars[0], buf); /* group */
8283 char_u *pat = tv_get_string_buf_chk(&argvars[1], buf); /* pattern */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008284 int prio = 10; /* default priority */
8285 int id = -1;
8286 int error = FALSE;
8287 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008288 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008289
8290 rettv->vval.v_number = -1;
8291
8292 if (grp == NULL || pat == NULL)
8293 return;
8294 if (argvars[2].v_type != VAR_UNKNOWN)
8295 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008296 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008297 if (argvars[3].v_type != VAR_UNKNOWN)
8298 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008299 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008300 if (argvars[4].v_type != VAR_UNKNOWN
8301 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8302 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008303 }
8304 }
8305 if (error == TRUE)
8306 return;
8307 if (id >= 1 && id <= 3)
8308 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008309 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008310 return;
8311 }
8312
Bram Moolenaar95e51472018-07-28 16:55:56 +02008313 rettv->vval.v_number = match_add(win, grp, pat, prio, id, NULL,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008314 conceal_char);
8315#endif
8316}
8317
8318/*
8319 * "matchaddpos()" function
8320 */
8321 static void
8322f_matchaddpos(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8323{
8324#ifdef FEAT_SEARCH_EXTRA
8325 char_u buf[NUMBUFLEN];
8326 char_u *group;
8327 int prio = 10;
8328 int id = -1;
8329 int error = FALSE;
8330 list_T *l;
8331 char_u *conceal_char = NULL;
Bram Moolenaar95e51472018-07-28 16:55:56 +02008332 win_T *win = curwin;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008333
8334 rettv->vval.v_number = -1;
8335
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008336 group = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008337 if (group == NULL)
8338 return;
8339
8340 if (argvars[1].v_type != VAR_LIST)
8341 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008342 semsg(_(e_listarg), "matchaddpos()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008343 return;
8344 }
8345 l = argvars[1].vval.v_list;
8346 if (l == NULL)
8347 return;
8348
8349 if (argvars[2].v_type != VAR_UNKNOWN)
8350 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008351 prio = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008352 if (argvars[3].v_type != VAR_UNKNOWN)
8353 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008354 id = (int)tv_get_number_chk(&argvars[3], &error);
Bram Moolenaar95e51472018-07-28 16:55:56 +02008355
8356 if (argvars[4].v_type != VAR_UNKNOWN
8357 && matchadd_dict_arg(&argvars[4], &conceal_char, &win) == FAIL)
8358 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008359 }
8360 }
8361 if (error == TRUE)
8362 return;
8363
8364 /* id == 3 is ok because matchaddpos() is supposed to substitute :3match */
8365 if (id == 1 || id == 2)
8366 {
Bram Moolenaarb5443cc2019-01-15 20:19:40 +01008367 semsg(_("E798: ID is reserved for \":match\": %d"), id);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008368 return;
8369 }
8370
Bram Moolenaar95e51472018-07-28 16:55:56 +02008371 rettv->vval.v_number = match_add(win, group, NULL, prio, id, l,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008372 conceal_char);
8373#endif
8374}
8375
8376/*
8377 * "matcharg()" function
8378 */
8379 static void
8380f_matcharg(typval_T *argvars UNUSED, typval_T *rettv)
8381{
8382 if (rettv_list_alloc(rettv) == OK)
8383 {
8384#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008385 int id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008386 matchitem_T *m;
8387
8388 if (id >= 1 && id <= 3)
8389 {
8390 if ((m = (matchitem_T *)get_match(curwin, id)) != NULL)
8391 {
8392 list_append_string(rettv->vval.v_list,
8393 syn_id2name(m->hlg_id), -1);
8394 list_append_string(rettv->vval.v_list, m->pattern, -1);
8395 }
8396 else
8397 {
8398 list_append_string(rettv->vval.v_list, NULL, -1);
8399 list_append_string(rettv->vval.v_list, NULL, -1);
8400 }
8401 }
8402#endif
8403 }
8404}
8405
8406/*
8407 * "matchdelete()" function
8408 */
8409 static void
8410f_matchdelete(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8411{
8412#ifdef FEAT_SEARCH_EXTRA
Bram Moolenaaraff74912019-03-30 18:11:49 +01008413 win_T *win = get_optional_window(argvars, 1);
8414
8415 if (win == NULL)
8416 rettv->vval.v_number = -1;
8417 else
8418 rettv->vval.v_number = match_delete(win,
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008419 (int)tv_get_number(&argvars[0]), TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008420#endif
8421}
8422
8423/*
8424 * "matchend()" function
8425 */
8426 static void
8427f_matchend(typval_T *argvars, typval_T *rettv)
8428{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008429 find_some_match(argvars, rettv, MATCH_END);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008430}
8431
8432/*
8433 * "matchlist()" function
8434 */
8435 static void
8436f_matchlist(typval_T *argvars, typval_T *rettv)
8437{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008438 find_some_match(argvars, rettv, MATCH_LIST);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008439}
8440
8441/*
8442 * "matchstr()" function
8443 */
8444 static void
8445f_matchstr(typval_T *argvars, typval_T *rettv)
8446{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008447 find_some_match(argvars, rettv, MATCH_STR);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008448}
8449
8450/*
8451 * "matchstrpos()" function
8452 */
8453 static void
8454f_matchstrpos(typval_T *argvars, typval_T *rettv)
8455{
Bram Moolenaar8d9f0ef2017-08-27 13:51:01 +02008456 find_some_match(argvars, rettv, MATCH_POS);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008457}
8458
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008459 static void
8460max_min(typval_T *argvars, typval_T *rettv, int domax)
8461{
8462 varnumber_T n = 0;
8463 varnumber_T i;
8464 int error = FALSE;
8465
8466 if (argvars[0].v_type == VAR_LIST)
8467 {
8468 list_T *l;
8469 listitem_T *li;
8470
8471 l = argvars[0].vval.v_list;
8472 if (l != NULL)
8473 {
8474 li = l->lv_first;
8475 if (li != NULL)
8476 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008477 n = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008478 for (;;)
8479 {
8480 li = li->li_next;
8481 if (li == NULL)
8482 break;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008483 i = tv_get_number_chk(&li->li_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008484 if (domax ? i > n : i < n)
8485 n = i;
8486 }
8487 }
8488 }
8489 }
8490 else if (argvars[0].v_type == VAR_DICT)
8491 {
8492 dict_T *d;
8493 int first = TRUE;
8494 hashitem_T *hi;
8495 int todo;
8496
8497 d = argvars[0].vval.v_dict;
8498 if (d != NULL)
8499 {
8500 todo = (int)d->dv_hashtab.ht_used;
8501 for (hi = d->dv_hashtab.ht_array; todo > 0; ++hi)
8502 {
8503 if (!HASHITEM_EMPTY(hi))
8504 {
8505 --todo;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008506 i = tv_get_number_chk(&HI2DI(hi)->di_tv, &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008507 if (first)
8508 {
8509 n = i;
8510 first = FALSE;
8511 }
8512 else if (domax ? i > n : i < n)
8513 n = i;
8514 }
8515 }
8516 }
8517 }
8518 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01008519 semsg(_(e_listdictarg), domax ? "max()" : "min()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008520 rettv->vval.v_number = error ? 0 : n;
8521}
8522
8523/*
8524 * "max()" function
8525 */
8526 static void
8527f_max(typval_T *argvars, typval_T *rettv)
8528{
8529 max_min(argvars, rettv, TRUE);
8530}
8531
8532/*
8533 * "min()" function
8534 */
8535 static void
8536f_min(typval_T *argvars, typval_T *rettv)
8537{
8538 max_min(argvars, rettv, FALSE);
8539}
8540
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008541/*
8542 * Create the directory in which "dir" is located, and higher levels when
8543 * needed.
Bram Moolenaar7860bac2017-04-09 15:03:15 +02008544 * Return OK or FAIL.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008545 */
8546 static int
8547mkdir_recurse(char_u *dir, int prot)
8548{
8549 char_u *p;
8550 char_u *updir;
8551 int r = FAIL;
8552
8553 /* Get end of directory name in "dir".
8554 * We're done when it's "/" or "c:/". */
8555 p = gettail_sep(dir);
8556 if (p <= get_past_head(dir))
8557 return OK;
8558
8559 /* If the directory exists we're done. Otherwise: create it.*/
8560 updir = vim_strnsave(dir, (int)(p - dir));
8561 if (updir == NULL)
8562 return FAIL;
8563 if (mch_isdir(updir))
8564 r = OK;
8565 else if (mkdir_recurse(updir, prot) == OK)
8566 r = vim_mkdir_emsg(updir, prot);
8567 vim_free(updir);
8568 return r;
8569}
8570
8571#ifdef vim_mkdir
8572/*
8573 * "mkdir()" function
8574 */
8575 static void
8576f_mkdir(typval_T *argvars, typval_T *rettv)
8577{
8578 char_u *dir;
8579 char_u buf[NUMBUFLEN];
8580 int prot = 0755;
8581
8582 rettv->vval.v_number = FAIL;
8583 if (check_restricted() || check_secure())
8584 return;
8585
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008586 dir = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008587 if (*dir == NUL)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008588 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008589
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008590 if (*gettail(dir) == NUL)
8591 /* remove trailing slashes */
8592 *gettail_sep(dir) = NUL;
8593
8594 if (argvars[1].v_type != VAR_UNKNOWN)
8595 {
8596 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008597 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008598 prot = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008599 if (prot == -1)
8600 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008601 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008602 if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008603 {
8604 if (mch_isdir(dir))
8605 {
8606 /* With the "p" flag it's OK if the dir already exists. */
8607 rettv->vval.v_number = OK;
8608 return;
8609 }
8610 mkdir_recurse(dir, prot);
8611 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008612 }
Bram Moolenaar78a16b02018-04-14 13:51:55 +02008613 rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008614}
8615#endif
8616
8617/*
8618 * "mode()" function
8619 */
8620 static void
8621f_mode(typval_T *argvars, typval_T *rettv)
8622{
Bram Moolenaar612cc382018-07-29 15:34:26 +02008623 char_u buf[4];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008624
Bram Moolenaar612cc382018-07-29 15:34:26 +02008625 vim_memset(buf, 0, sizeof(buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008626
8627 if (time_for_testing == 93784)
8628 {
8629 /* Testing the two-character code. */
8630 buf[0] = 'x';
8631 buf[1] = '!';
8632 }
Bram Moolenaar2bb7b6b2017-08-13 20:58:33 +02008633#ifdef FEAT_TERMINAL
8634 else if (term_use_loop())
8635 buf[0] = 't';
8636#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008637 else if (VIsual_active)
8638 {
8639 if (VIsual_select)
8640 buf[0] = VIsual_mode + 's' - 'v';
8641 else
8642 buf[0] = VIsual_mode;
8643 }
8644 else if (State == HITRETURN || State == ASKMORE || State == SETWSIZE
8645 || State == CONFIRM)
8646 {
8647 buf[0] = 'r';
8648 if (State == ASKMORE)
8649 buf[1] = 'm';
8650 else if (State == CONFIRM)
8651 buf[1] = '?';
8652 }
8653 else if (State == EXTERNCMD)
8654 buf[0] = '!';
8655 else if (State & INSERT)
8656 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008657 if (State & VREPLACE_FLAG)
8658 {
8659 buf[0] = 'R';
8660 buf[1] = 'v';
8661 }
8662 else
Bram Moolenaare90858d2017-02-01 17:24:34 +01008663 {
8664 if (State & REPLACE_FLAG)
8665 buf[0] = 'R';
8666 else
8667 buf[0] = 'i';
8668#ifdef FEAT_INS_EXPAND
8669 if (ins_compl_active())
8670 buf[1] = 'c';
Bram Moolenaar05625322018-02-09 12:28:00 +01008671 else if (ctrl_x_mode_not_defined_yet())
Bram Moolenaare90858d2017-02-01 17:24:34 +01008672 buf[1] = 'x';
8673#endif
8674 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008675 }
Bram Moolenaare90858d2017-02-01 17:24:34 +01008676 else if ((State & CMDLINE) || exmode_active)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008677 {
8678 buf[0] = 'c';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008679 if (exmode_active == EXMODE_VIM)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008680 buf[1] = 'v';
Bram Moolenaare90858d2017-02-01 17:24:34 +01008681 else if (exmode_active == EXMODE_NORMAL)
8682 buf[1] = 'e';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008683 }
8684 else
8685 {
8686 buf[0] = 'n';
8687 if (finish_op)
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008688 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008689 buf[1] = 'o';
Bram Moolenaar5976f8f2018-12-27 23:44:44 +01008690 // to be able to detect force-linewise/blockwise/characterwise operations
8691 buf[2] = motion_force;
8692 }
Bram Moolenaar612cc382018-07-29 15:34:26 +02008693 else if (restart_edit == 'I' || restart_edit == 'R'
8694 || restart_edit == 'V')
8695 {
8696 buf[1] = 'i';
8697 buf[2] = restart_edit;
8698 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008699 }
8700
8701 /* Clear out the minor mode when the argument is not a non-zero number or
8702 * non-empty string. */
8703 if (!non_zero_arg(&argvars[0]))
8704 buf[1] = NUL;
8705
8706 rettv->vval.v_string = vim_strsave(buf);
8707 rettv->v_type = VAR_STRING;
8708}
8709
8710#if defined(FEAT_MZSCHEME) || defined(PROTO)
8711/*
8712 * "mzeval()" function
8713 */
8714 static void
8715f_mzeval(typval_T *argvars, typval_T *rettv)
8716{
8717 char_u *str;
8718 char_u buf[NUMBUFLEN];
8719
Bram Moolenaar8c62a082019-02-08 14:34:10 +01008720 if (check_restricted() || check_secure())
8721 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008722 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008723 do_mzeval(str, rettv);
8724}
8725
8726 void
8727mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv)
8728{
8729 typval_T argvars[3];
8730
8731 argvars[0].v_type = VAR_STRING;
8732 argvars[0].vval.v_string = name;
8733 copy_tv(args, &argvars[1]);
8734 argvars[2].v_type = VAR_UNKNOWN;
8735 f_call(argvars, rettv);
8736 clear_tv(&argvars[1]);
8737}
8738#endif
8739
8740/*
8741 * "nextnonblank()" function
8742 */
8743 static void
8744f_nextnonblank(typval_T *argvars, typval_T *rettv)
8745{
8746 linenr_T lnum;
8747
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008748 for (lnum = tv_get_lnum(argvars); ; ++lnum)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008749 {
8750 if (lnum < 0 || lnum > curbuf->b_ml.ml_line_count)
8751 {
8752 lnum = 0;
8753 break;
8754 }
8755 if (*skipwhite(ml_get(lnum)) != NUL)
8756 break;
8757 }
8758 rettv->vval.v_number = lnum;
8759}
8760
8761/*
8762 * "nr2char()" function
8763 */
8764 static void
8765f_nr2char(typval_T *argvars, typval_T *rettv)
8766{
8767 char_u buf[NUMBUFLEN];
8768
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008769 if (has_mbyte)
8770 {
8771 int utf8 = 0;
8772
8773 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008774 utf8 = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008775 if (utf8)
Bram Moolenaarbdace832019-03-02 10:13:42 +01008776 buf[utf_char2bytes((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008777 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008778 buf[(*mb_char2bytes)((int)tv_get_number(&argvars[0]), buf)] = NUL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008779 }
8780 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008781 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008782 buf[0] = (char_u)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008783 buf[1] = NUL;
8784 }
8785 rettv->v_type = VAR_STRING;
8786 rettv->vval.v_string = vim_strsave(buf);
8787}
8788
8789/*
8790 * "or(expr, expr)" function
8791 */
8792 static void
8793f_or(typval_T *argvars, typval_T *rettv)
8794{
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008795 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
8796 | tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008797}
8798
8799/*
8800 * "pathshorten()" function
8801 */
8802 static void
8803f_pathshorten(typval_T *argvars, typval_T *rettv)
8804{
8805 char_u *p;
8806
8807 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008808 p = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008809 if (p == NULL)
8810 rettv->vval.v_string = NULL;
8811 else
8812 {
8813 p = vim_strsave(p);
8814 rettv->vval.v_string = p;
8815 if (p != NULL)
8816 shorten_dir(p);
8817 }
8818}
8819
8820#ifdef FEAT_PERL
8821/*
8822 * "perleval()" function
8823 */
8824 static void
8825f_perleval(typval_T *argvars, typval_T *rettv)
8826{
8827 char_u *str;
8828 char_u buf[NUMBUFLEN];
8829
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008830 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008831 do_perleval(str, rettv);
8832}
8833#endif
8834
8835#ifdef FEAT_FLOAT
8836/*
8837 * "pow()" function
8838 */
8839 static void
8840f_pow(typval_T *argvars, typval_T *rettv)
8841{
8842 float_T fx = 0.0, fy = 0.0;
8843
8844 rettv->v_type = VAR_FLOAT;
8845 if (get_float_arg(argvars, &fx) == OK
8846 && get_float_arg(&argvars[1], &fy) == OK)
8847 rettv->vval.v_float = pow(fx, fy);
8848 else
8849 rettv->vval.v_float = 0.0;
8850}
8851#endif
8852
8853/*
8854 * "prevnonblank()" function
8855 */
8856 static void
8857f_prevnonblank(typval_T *argvars, typval_T *rettv)
8858{
8859 linenr_T lnum;
8860
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008861 lnum = tv_get_lnum(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008862 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
8863 lnum = 0;
8864 else
8865 while (lnum >= 1 && *skipwhite(ml_get(lnum)) == NUL)
8866 --lnum;
8867 rettv->vval.v_number = lnum;
8868}
8869
8870/* This dummy va_list is here because:
8871 * - passing a NULL pointer doesn't work when va_list isn't a pointer
8872 * - locally in the function results in a "used before set" warning
8873 * - using va_start() to initialize it gives "function with fixed args" error */
8874static va_list ap;
8875
8876/*
8877 * "printf()" function
8878 */
8879 static void
8880f_printf(typval_T *argvars, typval_T *rettv)
8881{
8882 char_u buf[NUMBUFLEN];
8883 int len;
8884 char_u *s;
8885 int saved_did_emsg = did_emsg;
8886 char *fmt;
8887
8888 rettv->v_type = VAR_STRING;
8889 rettv->vval.v_string = NULL;
8890
8891 /* Get the required length, allocate the buffer and do it for real. */
8892 did_emsg = FALSE;
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008893 fmt = (char *)tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008894 len = vim_vsnprintf_typval(NULL, 0, fmt, ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008895 if (!did_emsg)
8896 {
8897 s = alloc(len + 1);
8898 if (s != NULL)
8899 {
8900 rettv->vval.v_string = s;
Bram Moolenaar8327d1d2017-07-11 22:34:51 +02008901 (void)vim_vsnprintf_typval((char *)s, len + 1, fmt,
8902 ap, argvars + 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008903 }
8904 }
8905 did_emsg |= saved_did_emsg;
8906}
8907
Bram Moolenaarf2732452018-06-03 14:47:35 +02008908#ifdef FEAT_JOB_CHANNEL
8909/*
8910 * "prompt_setcallback({buffer}, {callback})" function
8911 */
8912 static void
8913f_prompt_setcallback(typval_T *argvars, typval_T *rettv UNUSED)
8914{
8915 buf_T *buf;
8916 char_u *callback;
8917 partial_T *partial;
8918
8919 if (check_secure())
8920 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008921 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008922 if (buf == NULL)
8923 return;
8924
8925 callback = get_callback(&argvars[1], &partial);
8926 if (callback == NULL)
8927 return;
8928
8929 free_callback(buf->b_prompt_callback, buf->b_prompt_partial);
8930 if (partial == NULL)
8931 buf->b_prompt_callback = vim_strsave(callback);
8932 else
8933 /* pointer into the partial */
8934 buf->b_prompt_callback = callback;
8935 buf->b_prompt_partial = partial;
8936}
8937
8938/*
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008939 * "prompt_setinterrupt({buffer}, {callback})" function
8940 */
8941 static void
8942f_prompt_setinterrupt(typval_T *argvars, typval_T *rettv UNUSED)
8943{
8944 buf_T *buf;
8945 char_u *callback;
8946 partial_T *partial;
8947
8948 if (check_secure())
8949 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008950 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar0e5979a2018-06-17 19:36:33 +02008951 if (buf == NULL)
8952 return;
8953
8954 callback = get_callback(&argvars[1], &partial);
8955 if (callback == NULL)
8956 return;
8957
8958 free_callback(buf->b_prompt_interrupt, buf->b_prompt_int_partial);
8959 if (partial == NULL)
8960 buf->b_prompt_interrupt = vim_strsave(callback);
8961 else
8962 /* pointer into the partial */
8963 buf->b_prompt_interrupt = callback;
8964 buf->b_prompt_int_partial = partial;
8965}
8966
8967/*
Bram Moolenaarf2732452018-06-03 14:47:35 +02008968 * "prompt_setprompt({buffer}, {text})" function
8969 */
8970 static void
8971f_prompt_setprompt(typval_T *argvars, typval_T *rettv UNUSED)
8972{
8973 buf_T *buf;
8974 char_u *text;
8975
8976 if (check_secure())
8977 return;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +01008978 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008979 if (buf == NULL)
8980 return;
8981
Bram Moolenaard155d7a2018-12-21 16:04:21 +01008982 text = tv_get_string(&argvars[1]);
Bram Moolenaarf2732452018-06-03 14:47:35 +02008983 vim_free(buf->b_prompt_text);
8984 buf->b_prompt_text = vim_strsave(text);
8985}
8986#endif
8987
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02008988/*
8989 * "pumvisible()" function
8990 */
8991 static void
8992f_pumvisible(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8993{
8994#ifdef FEAT_INS_EXPAND
8995 if (pum_visible())
8996 rettv->vval.v_number = 1;
8997#endif
8998}
8999
9000#ifdef FEAT_PYTHON3
9001/*
9002 * "py3eval()" function
9003 */
9004 static void
9005f_py3eval(typval_T *argvars, typval_T *rettv)
9006{
9007 char_u *str;
9008 char_u buf[NUMBUFLEN];
9009
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009010 if (check_restricted() || check_secure())
9011 return;
9012
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009013 if (p_pyx == 0)
9014 p_pyx = 3;
9015
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009016 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009017 do_py3eval(str, rettv);
9018}
9019#endif
9020
9021#ifdef FEAT_PYTHON
9022/*
9023 * "pyeval()" function
9024 */
9025 static void
9026f_pyeval(typval_T *argvars, typval_T *rettv)
9027{
9028 char_u *str;
9029 char_u buf[NUMBUFLEN];
9030
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009031 if (check_restricted() || check_secure())
9032 return;
9033
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009034 if (p_pyx == 0)
9035 p_pyx = 2;
9036
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009037 str = tv_get_string_buf(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009038 do_pyeval(str, rettv);
9039}
9040#endif
9041
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009042#if defined(FEAT_PYTHON) || defined(FEAT_PYTHON3)
9043/*
9044 * "pyxeval()" function
9045 */
9046 static void
9047f_pyxeval(typval_T *argvars, typval_T *rettv)
9048{
Bram Moolenaar8c62a082019-02-08 14:34:10 +01009049 if (check_restricted() || check_secure())
9050 return;
9051
Bram Moolenaarf42dd3c2017-01-28 16:06:38 +01009052# if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
9053 init_pyxversion();
9054 if (p_pyx == 2)
9055 f_pyeval(argvars, rettv);
9056 else
9057 f_py3eval(argvars, rettv);
9058# elif defined(FEAT_PYTHON)
9059 f_pyeval(argvars, rettv);
9060# elif defined(FEAT_PYTHON3)
9061 f_py3eval(argvars, rettv);
9062# endif
9063}
9064#endif
9065
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009066/*
9067 * "range()" function
9068 */
9069 static void
9070f_range(typval_T *argvars, typval_T *rettv)
9071{
9072 varnumber_T start;
9073 varnumber_T end;
9074 varnumber_T stride = 1;
9075 varnumber_T i;
9076 int error = FALSE;
9077
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009078 start = tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009079 if (argvars[1].v_type == VAR_UNKNOWN)
9080 {
9081 end = start - 1;
9082 start = 0;
9083 }
9084 else
9085 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009086 end = tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009087 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009088 stride = tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009089 }
9090
9091 if (error)
9092 return; /* type error; errmsg already given */
9093 if (stride == 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009094 emsg(_("E726: Stride is zero"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009095 else if (stride > 0 ? end + 1 < start : end - 1 > start)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009096 emsg(_("E727: Start past end"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009097 else
9098 {
9099 if (rettv_list_alloc(rettv) == OK)
9100 for (i = start; stride > 0 ? i <= end : i >= end; i += stride)
9101 if (list_append_number(rettv->vval.v_list,
9102 (varnumber_T)i) == FAIL)
9103 break;
9104 }
9105}
9106
9107/*
9108 * "readfile()" function
9109 */
9110 static void
9111f_readfile(typval_T *argvars, typval_T *rettv)
9112{
9113 int binary = FALSE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009114 int blob = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009115 int failed = FALSE;
9116 char_u *fname;
9117 FILE *fd;
9118 char_u buf[(IOSIZE/256)*256]; /* rounded to avoid odd + 1 */
9119 int io_size = sizeof(buf);
9120 int readlen; /* size of last fread() */
9121 char_u *prev = NULL; /* previously read bytes, if any */
9122 long prevlen = 0; /* length of data in prev */
9123 long prevsize = 0; /* size of prev buffer */
9124 long maxline = MAXLNUM;
9125 long cnt = 0;
9126 char_u *p; /* position in buf */
9127 char_u *start; /* start of current line */
9128
9129 if (argvars[1].v_type != VAR_UNKNOWN)
9130 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009131 if (STRCMP(tv_get_string(&argvars[1]), "b") == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009132 binary = TRUE;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009133 if (STRCMP(tv_get_string(&argvars[1]), "B") == 0)
9134 blob = TRUE;
9135
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009136 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009137 maxline = (long)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009138 }
9139
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009140 if (blob)
9141 {
9142 if (rettv_blob_alloc(rettv) == FAIL)
9143 return;
9144 }
9145 else
9146 {
9147 if (rettv_list_alloc(rettv) == FAIL)
9148 return;
9149 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009150
9151 /* Always open the file in binary mode, library functions have a mind of
9152 * their own about CR-LF conversion. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009153 fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009154 if (*fname == NUL || (fd = mch_fopen((char *)fname, READBIN)) == NULL)
9155 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009156 semsg(_(e_notopen), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009157 return;
9158 }
9159
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009160 if (blob)
9161 {
9162 if (read_blob(fd, rettv->vval.v_blob) == FAIL)
9163 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009164 emsg("cannot read file");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009165 blob_free(rettv->vval.v_blob);
9166 }
9167 fclose(fd);
9168 return;
9169 }
9170
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009171 while (cnt < maxline || maxline < 0)
9172 {
9173 readlen = (int)fread(buf, 1, io_size, fd);
9174
9175 /* This for loop processes what was read, but is also entered at end
9176 * of file so that either:
9177 * - an incomplete line gets written
9178 * - a "binary" file gets an empty line at the end if it ends in a
9179 * newline. */
9180 for (p = buf, start = buf;
9181 p < buf + readlen || (readlen <= 0 && (prevlen > 0 || binary));
9182 ++p)
9183 {
9184 if (*p == '\n' || readlen <= 0)
9185 {
9186 listitem_T *li;
9187 char_u *s = NULL;
9188 long_u len = p - start;
9189
9190 /* Finished a line. Remove CRs before NL. */
9191 if (readlen > 0 && !binary)
9192 {
9193 while (len > 0 && start[len - 1] == '\r')
9194 --len;
9195 /* removal may cross back to the "prev" string */
9196 if (len == 0)
9197 while (prevlen > 0 && prev[prevlen - 1] == '\r')
9198 --prevlen;
9199 }
9200 if (prevlen == 0)
9201 s = vim_strnsave(start, (int)len);
9202 else
9203 {
9204 /* Change "prev" buffer to be the right size. This way
9205 * the bytes are only copied once, and very long lines are
9206 * allocated only once. */
9207 if ((s = vim_realloc(prev, prevlen + len + 1)) != NULL)
9208 {
9209 mch_memmove(s + prevlen, start, len);
9210 s[prevlen + len] = NUL;
9211 prev = NULL; /* the list will own the string */
9212 prevlen = prevsize = 0;
9213 }
9214 }
9215 if (s == NULL)
9216 {
9217 do_outofmem_msg((long_u) prevlen + len + 1);
9218 failed = TRUE;
9219 break;
9220 }
9221
9222 if ((li = listitem_alloc()) == NULL)
9223 {
9224 vim_free(s);
9225 failed = TRUE;
9226 break;
9227 }
9228 li->li_tv.v_type = VAR_STRING;
9229 li->li_tv.v_lock = 0;
9230 li->li_tv.vval.v_string = s;
9231 list_append(rettv->vval.v_list, li);
9232
9233 start = p + 1; /* step over newline */
9234 if ((++cnt >= maxline && maxline >= 0) || readlen <= 0)
9235 break;
9236 }
9237 else if (*p == NUL)
9238 *p = '\n';
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009239 /* Check for utf8 "bom"; U+FEFF is encoded as EF BB BF. Do this
9240 * when finding the BF and check the previous two bytes. */
9241 else if (*p == 0xbf && enc_utf8 && !binary)
9242 {
9243 /* Find the two bytes before the 0xbf. If p is at buf, or buf
9244 * + 1, these may be in the "prev" string. */
9245 char_u back1 = p >= buf + 1 ? p[-1]
9246 : prevlen >= 1 ? prev[prevlen - 1] : NUL;
9247 char_u back2 = p >= buf + 2 ? p[-2]
9248 : p == buf + 1 && prevlen >= 1 ? prev[prevlen - 1]
9249 : prevlen >= 2 ? prev[prevlen - 2] : NUL;
9250
9251 if (back2 == 0xef && back1 == 0xbb)
9252 {
9253 char_u *dest = p - 2;
9254
9255 /* Usually a BOM is at the beginning of a file, and so at
9256 * the beginning of a line; then we can just step over it.
9257 */
9258 if (start == dest)
9259 start = p + 1;
9260 else
9261 {
9262 /* have to shuffle buf to close gap */
9263 int adjust_prevlen = 0;
9264
9265 if (dest < buf)
9266 {
9267 adjust_prevlen = (int)(buf - dest); /* must be 1 or 2 */
9268 dest = buf;
9269 }
9270 if (readlen > p - buf + 1)
9271 mch_memmove(dest, p + 1, readlen - (p - buf) - 1);
9272 readlen -= 3 - adjust_prevlen;
9273 prevlen -= adjust_prevlen;
9274 p = dest - 1;
9275 }
9276 }
9277 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009278 } /* for */
9279
9280 if (failed || (cnt >= maxline && maxline >= 0) || readlen <= 0)
9281 break;
9282 if (start < p)
9283 {
9284 /* There's part of a line in buf, store it in "prev". */
9285 if (p - start + prevlen >= prevsize)
9286 {
9287 /* need bigger "prev" buffer */
9288 char_u *newprev;
9289
9290 /* A common use case is ordinary text files and "prev" gets a
9291 * fragment of a line, so the first allocation is made
9292 * small, to avoid repeatedly 'allocing' large and
9293 * 'reallocing' small. */
9294 if (prevsize == 0)
9295 prevsize = (long)(p - start);
9296 else
9297 {
9298 long grow50pc = (prevsize * 3) / 2;
9299 long growmin = (long)((p - start) * 2 + prevlen);
9300 prevsize = grow50pc > growmin ? grow50pc : growmin;
9301 }
9302 newprev = prev == NULL ? alloc(prevsize)
9303 : vim_realloc(prev, prevsize);
9304 if (newprev == NULL)
9305 {
9306 do_outofmem_msg((long_u)prevsize);
9307 failed = TRUE;
9308 break;
9309 }
9310 prev = newprev;
9311 }
9312 /* Add the line part to end of "prev". */
9313 mch_memmove(prev + prevlen, start, p - start);
9314 prevlen += (long)(p - start);
9315 }
9316 } /* while */
9317
9318 /*
9319 * For a negative line count use only the lines at the end of the file,
9320 * free the rest.
9321 */
9322 if (!failed && maxline < 0)
9323 while (cnt > -maxline)
9324 {
9325 listitem_remove(rettv->vval.v_list, rettv->vval.v_list->lv_first);
9326 --cnt;
9327 }
9328
9329 if (failed)
9330 {
9331 list_free(rettv->vval.v_list);
9332 /* readfile doc says an empty list is returned on error */
9333 rettv->vval.v_list = list_alloc();
9334 }
9335
9336 vim_free(prev);
9337 fclose(fd);
9338}
9339
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02009340 static void
9341return_register(int regname, typval_T *rettv)
9342{
9343 char_u buf[2] = {0, 0};
9344
9345 buf[0] = (char_u)regname;
9346 rettv->v_type = VAR_STRING;
9347 rettv->vval.v_string = vim_strsave(buf);
9348}
9349
9350/*
9351 * "reg_executing()" function
9352 */
9353 static void
9354f_reg_executing(typval_T *argvars UNUSED, typval_T *rettv)
9355{
9356 return_register(reg_executing, rettv);
9357}
9358
9359/*
9360 * "reg_recording()" function
9361 */
9362 static void
9363f_reg_recording(typval_T *argvars UNUSED, typval_T *rettv)
9364{
9365 return_register(reg_recording, rettv);
9366}
9367
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009368#if defined(FEAT_RELTIME)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009369/*
9370 * Convert a List to proftime_T.
9371 * Return FAIL when there is something wrong.
9372 */
9373 static int
9374list2proftime(typval_T *arg, proftime_T *tm)
9375{
9376 long n1, n2;
9377 int error = FALSE;
9378
9379 if (arg->v_type != VAR_LIST || arg->vval.v_list == NULL
9380 || arg->vval.v_list->lv_len != 2)
9381 return FAIL;
9382 n1 = list_find_nr(arg->vval.v_list, 0L, &error);
9383 n2 = list_find_nr(arg->vval.v_list, 1L, &error);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009384# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009385 tm->HighPart = n1;
9386 tm->LowPart = n2;
9387# else
9388 tm->tv_sec = n1;
9389 tm->tv_usec = n2;
9390# endif
9391 return error ? FAIL : OK;
9392}
9393#endif /* FEAT_RELTIME */
9394
9395/*
9396 * "reltime()" function
9397 */
9398 static void
9399f_reltime(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9400{
9401#ifdef FEAT_RELTIME
9402 proftime_T res;
9403 proftime_T start;
9404
9405 if (argvars[0].v_type == VAR_UNKNOWN)
9406 {
9407 /* No arguments: get current time. */
9408 profile_start(&res);
9409 }
9410 else if (argvars[1].v_type == VAR_UNKNOWN)
9411 {
9412 if (list2proftime(&argvars[0], &res) == FAIL)
9413 return;
9414 profile_end(&res);
9415 }
9416 else
9417 {
9418 /* Two arguments: compute the difference. */
9419 if (list2proftime(&argvars[0], &start) == FAIL
9420 || list2proftime(&argvars[1], &res) == FAIL)
9421 return;
9422 profile_sub(&res, &start);
9423 }
9424
9425 if (rettv_list_alloc(rettv) == OK)
9426 {
9427 long n1, n2;
9428
Bram Moolenaar4f974752019-02-17 17:44:42 +01009429# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009430 n1 = res.HighPart;
9431 n2 = res.LowPart;
9432# else
9433 n1 = res.tv_sec;
9434 n2 = res.tv_usec;
9435# endif
9436 list_append_number(rettv->vval.v_list, (varnumber_T)n1);
9437 list_append_number(rettv->vval.v_list, (varnumber_T)n2);
9438 }
9439#endif
9440}
9441
9442#ifdef FEAT_FLOAT
9443/*
9444 * "reltimefloat()" function
9445 */
9446 static void
9447f_reltimefloat(typval_T *argvars UNUSED, typval_T *rettv)
9448{
9449# ifdef FEAT_RELTIME
9450 proftime_T tm;
9451# endif
9452
9453 rettv->v_type = VAR_FLOAT;
9454 rettv->vval.v_float = 0;
9455# ifdef FEAT_RELTIME
9456 if (list2proftime(&argvars[0], &tm) == OK)
9457 rettv->vval.v_float = profile_float(&tm);
9458# endif
9459}
9460#endif
9461
9462/*
9463 * "reltimestr()" function
9464 */
9465 static void
9466f_reltimestr(typval_T *argvars UNUSED, typval_T *rettv)
9467{
9468#ifdef FEAT_RELTIME
9469 proftime_T tm;
9470#endif
9471
9472 rettv->v_type = VAR_STRING;
9473 rettv->vval.v_string = NULL;
9474#ifdef FEAT_RELTIME
9475 if (list2proftime(&argvars[0], &tm) == OK)
9476 rettv->vval.v_string = vim_strsave((char_u *)profile_msg(&tm));
9477#endif
9478}
9479
9480#if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009481 static void
9482make_connection(void)
9483{
9484 if (X_DISPLAY == NULL
9485# ifdef FEAT_GUI
9486 && !gui.in_use
9487# endif
9488 )
9489 {
9490 x_force_connect = TRUE;
9491 setup_term_clip();
9492 x_force_connect = FALSE;
9493 }
9494}
9495
9496 static int
9497check_connection(void)
9498{
9499 make_connection();
9500 if (X_DISPLAY == NULL)
9501 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009502 emsg(_("E240: No connection to the X server"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009503 return FAIL;
9504 }
9505 return OK;
9506}
9507#endif
9508
9509#ifdef FEAT_CLIENTSERVER
9510 static void
9511remote_common(typval_T *argvars, typval_T *rettv, int expr)
9512{
9513 char_u *server_name;
9514 char_u *keys;
9515 char_u *r = NULL;
9516 char_u buf[NUMBUFLEN];
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009517 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009518# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009519 HWND w;
9520# else
9521 Window w;
9522# endif
9523
9524 if (check_restricted() || check_secure())
9525 return;
9526
9527# ifdef FEAT_X11
9528 if (check_connection() == FAIL)
9529 return;
9530# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009531 if (argvars[2].v_type != VAR_UNKNOWN
9532 && argvars[3].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009533 timeout = tv_get_number(&argvars[3]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009534
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009535 server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009536 if (server_name == NULL)
9537 return; /* type error; errmsg already given */
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009538 keys = tv_get_string_buf(&argvars[1], buf);
Bram Moolenaar4f974752019-02-17 17:44:42 +01009539# ifdef MSWIN
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009540 if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009541# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009542 if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
9543 0, TRUE) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009544# endif
9545 {
9546 if (r != NULL)
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009547 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009548 emsg((char *)r); // sending worked but evaluation failed
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009549 vim_free(r);
9550 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009551 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009552 semsg(_("E241: Unable to send to %s"), server_name);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009553 return;
9554 }
9555
9556 rettv->vval.v_string = r;
9557
9558 if (argvars[2].v_type != VAR_UNKNOWN)
9559 {
9560 dictitem_T v;
9561 char_u str[30];
9562 char_u *idvar;
9563
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009564 idvar = tv_get_string_chk(&argvars[2]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009565 if (idvar != NULL && *idvar != NUL)
9566 {
9567 sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
9568 v.di_tv.v_type = VAR_STRING;
9569 v.di_tv.vval.v_string = vim_strsave(str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009570 set_var(idvar, &v.di_tv, FALSE);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009571 vim_free(v.di_tv.vval.v_string);
9572 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009573 }
9574}
9575#endif
9576
9577/*
9578 * "remote_expr()" function
9579 */
9580 static void
9581f_remote_expr(typval_T *argvars UNUSED, typval_T *rettv)
9582{
9583 rettv->v_type = VAR_STRING;
9584 rettv->vval.v_string = NULL;
9585#ifdef FEAT_CLIENTSERVER
9586 remote_common(argvars, rettv, TRUE);
9587#endif
9588}
9589
9590/*
9591 * "remote_foreground()" function
9592 */
9593 static void
9594f_remote_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9595{
9596#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +01009597# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009598 /* On Win32 it's done in this application. */
9599 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009600 char_u *server_name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009601
9602 if (server_name != NULL)
9603 serverForeground(server_name);
9604 }
9605# else
9606 /* Send a foreground() expression to the server. */
9607 argvars[1].v_type = VAR_STRING;
9608 argvars[1].vval.v_string = vim_strsave((char_u *)"foreground()");
9609 argvars[2].v_type = VAR_UNKNOWN;
Bram Moolenaar09d6c382017-09-09 16:25:54 +02009610 rettv->v_type = VAR_STRING;
9611 rettv->vval.v_string = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009612 remote_common(argvars, rettv, TRUE);
9613 vim_free(argvars[1].vval.v_string);
9614# endif
9615#endif
9616}
9617
9618 static void
9619f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
9620{
9621#ifdef FEAT_CLIENTSERVER
9622 dictitem_T v;
9623 char_u *s = NULL;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009624# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009625 long_u n = 0;
9626# endif
9627 char_u *serverid;
9628
9629 if (check_restricted() || check_secure())
9630 {
9631 rettv->vval.v_number = -1;
9632 return;
9633 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009634 serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009635 if (serverid == NULL)
9636 {
9637 rettv->vval.v_number = -1;
9638 return; /* type error; errmsg already given */
9639 }
Bram Moolenaar4f974752019-02-17 17:44:42 +01009640# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009641 sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
9642 if (n == 0)
9643 rettv->vval.v_number = -1;
9644 else
9645 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009646 s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009647 rettv->vval.v_number = (s != NULL);
9648 }
9649# else
9650 if (check_connection() == FAIL)
9651 return;
9652
9653 rettv->vval.v_number = serverPeekReply(X_DISPLAY,
9654 serverStrToWin(serverid), &s);
9655# endif
9656
9657 if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
9658 {
9659 char_u *retvar;
9660
9661 v.di_tv.v_type = VAR_STRING;
9662 v.di_tv.vval.v_string = vim_strsave(s);
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009663 retvar = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009664 if (retvar != NULL)
9665 set_var(retvar, &v.di_tv, FALSE);
9666 vim_free(v.di_tv.vval.v_string);
9667 }
9668#else
9669 rettv->vval.v_number = -1;
9670#endif
9671}
9672
9673 static void
9674f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
9675{
9676 char_u *r = NULL;
9677
9678#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009679 char_u *serverid = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009680
9681 if (serverid != NULL && !check_restricted() && !check_secure())
9682 {
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009683 int timeout = 0;
Bram Moolenaar4f974752019-02-17 17:44:42 +01009684# ifdef MSWIN
Bram Moolenaar1662ce12017-03-19 21:47:50 +01009685 /* The server's HWND is encoded in the 'id' parameter */
9686 long_u n = 0;
9687# endif
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009688
9689 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009690 timeout = tv_get_number(&argvars[1]);
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009691
Bram Moolenaar4f974752019-02-17 17:44:42 +01009692# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009693 sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
9694 if (n != 0)
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009695 r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009696 if (r == NULL)
9697# else
Bram Moolenaar81b9d0b2017-03-19 21:20:53 +01009698 if (check_connection() == FAIL
9699 || serverReadReply(X_DISPLAY, serverStrToWin(serverid),
9700 &r, FALSE, timeout) < 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009701# endif
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009702 emsg(_("E277: Unable to read a server reply"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009703 }
9704#endif
9705 rettv->v_type = VAR_STRING;
9706 rettv->vval.v_string = r;
9707}
9708
9709/*
9710 * "remote_send()" function
9711 */
9712 static void
9713f_remote_send(typval_T *argvars UNUSED, typval_T *rettv)
9714{
9715 rettv->v_type = VAR_STRING;
9716 rettv->vval.v_string = NULL;
9717#ifdef FEAT_CLIENTSERVER
9718 remote_common(argvars, rettv, FALSE);
9719#endif
9720}
9721
9722/*
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009723 * "remote_startserver()" function
9724 */
9725 static void
9726f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
9727{
9728#ifdef FEAT_CLIENTSERVER
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009729 char_u *server = tv_get_string_chk(&argvars[0]);
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009730
9731 if (server == NULL)
9732 return; /* type error; errmsg already given */
9733 if (serverName != NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009734 emsg(_("E941: already started a server"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009735 else
9736 {
9737# ifdef FEAT_X11
9738 if (check_connection() == OK)
9739 serverRegisterName(X_DISPLAY, server);
9740# else
9741 serverSetName(server);
9742# endif
9743 }
9744#else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009745 emsg(_("E942: +clientserver feature not available"));
Bram Moolenaar7416f3e2017-03-18 18:10:13 +01009746#endif
9747}
9748
9749/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009750 * "remove()" function
9751 */
9752 static void
9753f_remove(typval_T *argvars, typval_T *rettv)
9754{
9755 list_T *l;
9756 listitem_T *item, *item2;
9757 listitem_T *li;
9758 long idx;
9759 long end;
9760 char_u *key;
9761 dict_T *d;
9762 dictitem_T *di;
9763 char_u *arg_errmsg = (char_u *)N_("remove() argument");
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009764 int error = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009765
9766 if (argvars[0].v_type == VAR_DICT)
9767 {
9768 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009769 semsg(_(e_toomanyarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009770 else if ((d = argvars[0].vval.v_dict) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009771 && !var_check_lock(d->dv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009772 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009773 key = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009774 if (key != NULL)
9775 {
9776 di = dict_find(d, key, -1);
9777 if (di == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009778 semsg(_(e_dictkey), key);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009779 else if (!var_check_fixed(di->di_flags, arg_errmsg, TRUE)
9780 && !var_check_ro(di->di_flags, arg_errmsg, TRUE))
9781 {
9782 *rettv = di->di_tv;
9783 init_tv(&di->di_tv);
9784 dictitem_remove(d, di);
9785 }
9786 }
9787 }
9788 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009789 else if (argvars[0].v_type == VAR_BLOB)
9790 {
9791 idx = (long)tv_get_number_chk(&argvars[1], &error);
9792 if (!error)
9793 {
9794 blob_T *b = argvars[0].vval.v_blob;
9795 int len = blob_len(b);
9796 char_u *p;
9797
9798 if (idx < 0)
9799 // count from the end
9800 idx = len + idx;
9801 if (idx < 0 || idx >= len)
9802 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009803 semsg(_(e_blobidx), idx);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009804 return;
9805 }
9806 if (argvars[2].v_type == VAR_UNKNOWN)
9807 {
9808 // Remove one item, return its value.
9809 p = (char_u *)b->bv_ga.ga_data;
9810 rettv->vval.v_number = (varnumber_T) *(p + idx);
9811 mch_memmove(p + idx, p + idx + 1, (size_t)len - idx - 1);
9812 --b->bv_ga.ga_len;
9813 }
9814 else
9815 {
9816 blob_T *blob;
9817
9818 // Remove range of items, return list with values.
9819 end = (long)tv_get_number_chk(&argvars[2], &error);
9820 if (error)
9821 return;
9822 if (end < 0)
9823 // count from the end
9824 end = len + end;
9825 if (end >= len || idx > end)
9826 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009827 semsg(_(e_blobidx), end);
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009828 return;
9829 }
9830 blob = blob_alloc();
9831 if (blob == NULL)
9832 return;
9833 blob->bv_ga.ga_len = end - idx + 1;
9834 if (ga_grow(&blob->bv_ga, end - idx + 1) == FAIL)
9835 {
9836 vim_free(blob);
9837 return;
9838 }
9839 p = (char_u *)b->bv_ga.ga_data;
9840 mch_memmove((char_u *)blob->bv_ga.ga_data, p + idx,
9841 (size_t)(end - idx + 1));
9842 ++blob->bv_refcount;
9843 rettv->v_type = VAR_BLOB;
9844 rettv->vval.v_blob = blob;
9845
9846 mch_memmove(p + idx, p + end + 1, (size_t)(len - end));
9847 b->bv_ga.ga_len -= end - idx + 1;
9848 }
9849 }
9850 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009851 else if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +01009852 semsg(_(e_listdictblobarg), "remove()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009853 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +01009854 && !var_check_lock(l->lv_lock, arg_errmsg, TRUE))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009855 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009856 idx = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009857 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009858 ; // type error: do nothing, errmsg already given
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009859 else if ((item = list_find(l, idx)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009860 semsg(_(e_listidx), idx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009861 else
9862 {
9863 if (argvars[2].v_type == VAR_UNKNOWN)
9864 {
9865 /* Remove one item, return its value. */
9866 vimlist_remove(l, item, item);
9867 *rettv = item->li_tv;
9868 vim_free(item);
9869 }
9870 else
9871 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009872 // Remove range of items, return list with values.
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009873 end = (long)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009874 if (error)
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +01009875 ; // type error: do nothing
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009876 else if ((item2 = list_find(l, end)) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009877 semsg(_(e_listidx), end);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009878 else
9879 {
9880 int cnt = 0;
9881
9882 for (li = item; li != NULL; li = li->li_next)
9883 {
9884 ++cnt;
9885 if (li == item2)
9886 break;
9887 }
9888 if (li == NULL) /* didn't find "item2" after "item" */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01009889 emsg(_(e_invrange));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009890 else
9891 {
9892 vimlist_remove(l, item, item2);
9893 if (rettv_list_alloc(rettv) == OK)
9894 {
9895 l = rettv->vval.v_list;
9896 l->lv_first = item;
9897 l->lv_last = item2;
9898 item->li_prev = NULL;
9899 item2->li_next = NULL;
9900 l->lv_len = cnt;
9901 }
9902 }
9903 }
9904 }
9905 }
9906 }
9907}
9908
9909/*
9910 * "rename({from}, {to})" function
9911 */
9912 static void
9913f_rename(typval_T *argvars, typval_T *rettv)
9914{
9915 char_u buf[NUMBUFLEN];
9916
9917 if (check_restricted() || check_secure())
9918 rettv->vval.v_number = -1;
9919 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009920 rettv->vval.v_number = vim_rename(tv_get_string(&argvars[0]),
9921 tv_get_string_buf(&argvars[1], buf));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009922}
9923
9924/*
9925 * "repeat()" function
9926 */
9927 static void
9928f_repeat(typval_T *argvars, typval_T *rettv)
9929{
9930 char_u *p;
9931 int n;
9932 int slen;
9933 int len;
9934 char_u *r;
9935 int i;
9936
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009937 n = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009938 if (argvars[0].v_type == VAR_LIST)
9939 {
9940 if (rettv_list_alloc(rettv) == OK && argvars[0].vval.v_list != NULL)
9941 while (n-- > 0)
9942 if (list_extend(rettv->vval.v_list,
9943 argvars[0].vval.v_list, NULL) == FAIL)
9944 break;
9945 }
9946 else
9947 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009948 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009949 rettv->v_type = VAR_STRING;
9950 rettv->vval.v_string = NULL;
9951
9952 slen = (int)STRLEN(p);
9953 len = slen * n;
9954 if (len <= 0)
9955 return;
9956
9957 r = alloc(len + 1);
9958 if (r != NULL)
9959 {
9960 for (i = 0; i < n; i++)
9961 mch_memmove(r + i * slen, p, (size_t)slen);
9962 r[len] = NUL;
9963 }
9964
9965 rettv->vval.v_string = r;
9966 }
9967}
9968
9969/*
9970 * "resolve()" function
9971 */
9972 static void
9973f_resolve(typval_T *argvars, typval_T *rettv)
9974{
9975 char_u *p;
9976#ifdef HAVE_READLINK
9977 char_u *buf = NULL;
9978#endif
9979
Bram Moolenaard155d7a2018-12-21 16:04:21 +01009980 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009981#ifdef FEAT_SHORTCUT
9982 {
9983 char_u *v = NULL;
9984
Bram Moolenaardce1e892019-02-10 23:18:53 +01009985 v = mch_resolve_path(p, TRUE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +02009986 if (v != NULL)
9987 rettv->vval.v_string = v;
9988 else
9989 rettv->vval.v_string = vim_strsave(p);
9990 }
9991#else
9992# ifdef HAVE_READLINK
9993 {
9994 char_u *cpy;
9995 int len;
9996 char_u *remain = NULL;
9997 char_u *q;
9998 int is_relative_to_current = FALSE;
9999 int has_trailing_pathsep = FALSE;
10000 int limit = 100;
10001
10002 p = vim_strsave(p);
10003
10004 if (p[0] == '.' && (vim_ispathsep(p[1])
10005 || (p[1] == '.' && (vim_ispathsep(p[2])))))
10006 is_relative_to_current = TRUE;
10007
10008 len = STRLEN(p);
10009 if (len > 0 && after_pathsep(p, p + len))
10010 {
10011 has_trailing_pathsep = TRUE;
10012 p[len - 1] = NUL; /* the trailing slash breaks readlink() */
10013 }
10014
10015 q = getnextcomp(p);
10016 if (*q != NUL)
10017 {
10018 /* Separate the first path component in "p", and keep the
10019 * remainder (beginning with the path separator). */
10020 remain = vim_strsave(q - 1);
10021 q[-1] = NUL;
10022 }
10023
10024 buf = alloc(MAXPATHL + 1);
10025 if (buf == NULL)
10026 goto fail;
10027
10028 for (;;)
10029 {
10030 for (;;)
10031 {
10032 len = readlink((char *)p, (char *)buf, MAXPATHL);
10033 if (len <= 0)
10034 break;
10035 buf[len] = NUL;
10036
10037 if (limit-- == 0)
10038 {
10039 vim_free(p);
10040 vim_free(remain);
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010041 emsg(_("E655: Too many symbolic links (cycle?)"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010042 rettv->vval.v_string = NULL;
10043 goto fail;
10044 }
10045
10046 /* Ensure that the result will have a trailing path separator
10047 * if the argument has one. */
10048 if (remain == NULL && has_trailing_pathsep)
10049 add_pathsep(buf);
10050
10051 /* Separate the first path component in the link value and
10052 * concatenate the remainders. */
10053 q = getnextcomp(vim_ispathsep(*buf) ? buf + 1 : buf);
10054 if (*q != NUL)
10055 {
10056 if (remain == NULL)
10057 remain = vim_strsave(q - 1);
10058 else
10059 {
10060 cpy = concat_str(q - 1, remain);
10061 if (cpy != NULL)
10062 {
10063 vim_free(remain);
10064 remain = cpy;
10065 }
10066 }
10067 q[-1] = NUL;
10068 }
10069
10070 q = gettail(p);
10071 if (q > p && *q == NUL)
10072 {
10073 /* Ignore trailing path separator. */
10074 q[-1] = NUL;
10075 q = gettail(p);
10076 }
10077 if (q > p && !mch_isFullName(buf))
10078 {
10079 /* symlink is relative to directory of argument */
10080 cpy = alloc((unsigned)(STRLEN(p) + STRLEN(buf) + 1));
10081 if (cpy != NULL)
10082 {
10083 STRCPY(cpy, p);
10084 STRCPY(gettail(cpy), buf);
10085 vim_free(p);
10086 p = cpy;
10087 }
10088 }
10089 else
10090 {
10091 vim_free(p);
10092 p = vim_strsave(buf);
10093 }
10094 }
10095
10096 if (remain == NULL)
10097 break;
10098
10099 /* Append the first path component of "remain" to "p". */
10100 q = getnextcomp(remain + 1);
10101 len = q - remain - (*q != NUL);
10102 cpy = vim_strnsave(p, STRLEN(p) + len);
10103 if (cpy != NULL)
10104 {
10105 STRNCAT(cpy, remain, len);
10106 vim_free(p);
10107 p = cpy;
10108 }
10109 /* Shorten "remain". */
10110 if (*q != NUL)
10111 STRMOVE(remain, q - 1);
10112 else
Bram Moolenaard23a8232018-02-10 18:45:26 +010010113 VIM_CLEAR(remain);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010114 }
10115
10116 /* If the result is a relative path name, make it explicitly relative to
10117 * the current directory if and only if the argument had this form. */
10118 if (!vim_ispathsep(*p))
10119 {
10120 if (is_relative_to_current
10121 && *p != NUL
10122 && !(p[0] == '.'
10123 && (p[1] == NUL
10124 || vim_ispathsep(p[1])
10125 || (p[1] == '.'
10126 && (p[2] == NUL
10127 || vim_ispathsep(p[2]))))))
10128 {
10129 /* Prepend "./". */
10130 cpy = concat_str((char_u *)"./", p);
10131 if (cpy != NULL)
10132 {
10133 vim_free(p);
10134 p = cpy;
10135 }
10136 }
10137 else if (!is_relative_to_current)
10138 {
10139 /* Strip leading "./". */
10140 q = p;
10141 while (q[0] == '.' && vim_ispathsep(q[1]))
10142 q += 2;
10143 if (q > p)
10144 STRMOVE(p, p + 2);
10145 }
10146 }
10147
10148 /* Ensure that the result will have no trailing path separator
10149 * if the argument had none. But keep "/" or "//". */
10150 if (!has_trailing_pathsep)
10151 {
10152 q = p + STRLEN(p);
10153 if (after_pathsep(p, q))
10154 *gettail_sep(p) = NUL;
10155 }
10156
10157 rettv->vval.v_string = p;
10158 }
10159# else
10160 rettv->vval.v_string = vim_strsave(p);
10161# endif
10162#endif
10163
10164 simplify_filename(rettv->vval.v_string);
10165
10166#ifdef HAVE_READLINK
10167fail:
10168 vim_free(buf);
10169#endif
10170 rettv->v_type = VAR_STRING;
10171}
10172
10173/*
10174 * "reverse({list})" function
10175 */
10176 static void
10177f_reverse(typval_T *argvars, typval_T *rettv)
10178{
10179 list_T *l;
10180 listitem_T *li, *ni;
10181
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010010182 if (argvars[0].v_type == VAR_BLOB)
10183 {
10184 blob_T *b = argvars[0].vval.v_blob;
10185 int i, len = blob_len(b);
10186
10187 for (i = 0; i < len / 2; i++)
10188 {
10189 int tmp = blob_get(b, i);
10190
10191 blob_set(b, i, blob_get(b, len - i - 1));
10192 blob_set(b, len - i - 1, tmp);
10193 }
10194 rettv_blob_set(rettv, b);
10195 return;
10196 }
10197
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010198 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaar0d17f0d2019-01-22 22:20:38 +010010199 semsg(_(e_listblobarg), "reverse()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010200 else if ((l = argvars[0].vval.v_list) != NULL
Bram Moolenaar05c00c02019-02-11 22:00:11 +010010201 && !var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010202 (char_u *)N_("reverse() argument"), TRUE))
10203 {
10204 li = l->lv_last;
10205 l->lv_first = l->lv_last = NULL;
10206 l->lv_len = 0;
10207 while (li != NULL)
10208 {
10209 ni = li->li_prev;
10210 list_append(l, li);
10211 li = ni;
10212 }
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020010213 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010214 l->lv_idx = l->lv_len - l->lv_idx - 1;
10215 }
10216}
10217
10218#define SP_NOMOVE 0x01 /* don't move cursor */
10219#define SP_REPEAT 0x02 /* repeat to find outer pair */
10220#define SP_RETCOUNT 0x04 /* return matchcount */
10221#define SP_SETPCMARK 0x08 /* set previous context mark */
10222#define SP_START 0x10 /* accept match at start position */
10223#define SP_SUBPAT 0x20 /* return nr of matching sub-pattern */
10224#define SP_END 0x40 /* leave cursor at end of match */
10225#define SP_COLUMN 0x80 /* start at cursor column */
10226
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010227/*
10228 * Get flags for a search function.
10229 * Possibly sets "p_ws".
10230 * Returns BACKWARD, FORWARD or zero (for an error).
10231 */
10232 static int
10233get_search_arg(typval_T *varp, int *flagsp)
10234{
10235 int dir = FORWARD;
10236 char_u *flags;
10237 char_u nbuf[NUMBUFLEN];
10238 int mask;
10239
10240 if (varp->v_type != VAR_UNKNOWN)
10241 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010242 flags = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010243 if (flags == NULL)
10244 return 0; /* type error; errmsg already given */
10245 while (*flags != NUL)
10246 {
10247 switch (*flags)
10248 {
10249 case 'b': dir = BACKWARD; break;
10250 case 'w': p_ws = TRUE; break;
10251 case 'W': p_ws = FALSE; break;
10252 default: mask = 0;
10253 if (flagsp != NULL)
10254 switch (*flags)
10255 {
10256 case 'c': mask = SP_START; break;
10257 case 'e': mask = SP_END; break;
10258 case 'm': mask = SP_RETCOUNT; break;
10259 case 'n': mask = SP_NOMOVE; break;
10260 case 'p': mask = SP_SUBPAT; break;
10261 case 'r': mask = SP_REPEAT; break;
10262 case 's': mask = SP_SETPCMARK; break;
10263 case 'z': mask = SP_COLUMN; break;
10264 }
10265 if (mask == 0)
10266 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010267 semsg(_(e_invarg2), flags);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010268 dir = 0;
10269 }
10270 else
10271 *flagsp |= mask;
10272 }
10273 if (dir == 0)
10274 break;
10275 ++flags;
10276 }
10277 }
10278 return dir;
10279}
10280
10281/*
10282 * Shared by search() and searchpos() functions.
10283 */
10284 static int
10285search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
10286{
10287 int flags;
10288 char_u *pat;
10289 pos_T pos;
10290 pos_T save_cursor;
10291 int save_p_ws = p_ws;
10292 int dir;
10293 int retval = 0; /* default: FAIL */
10294 long lnum_stop = 0;
10295 proftime_T tm;
10296#ifdef FEAT_RELTIME
10297 long time_limit = 0;
10298#endif
10299 int options = SEARCH_KEEP;
10300 int subpatnum;
10301
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010302 pat = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010303 dir = get_search_arg(&argvars[1], flagsp); /* may set p_ws */
10304 if (dir == 0)
10305 goto theend;
10306 flags = *flagsp;
10307 if (flags & SP_START)
10308 options |= SEARCH_START;
10309 if (flags & SP_END)
10310 options |= SEARCH_END;
10311 if (flags & SP_COLUMN)
10312 options |= SEARCH_COL;
10313
10314 /* Optional arguments: line number to stop searching and timeout. */
10315 if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
10316 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010317 lnum_stop = (long)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010318 if (lnum_stop < 0)
10319 goto theend;
10320#ifdef FEAT_RELTIME
10321 if (argvars[3].v_type != VAR_UNKNOWN)
10322 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010323 time_limit = (long)tv_get_number_chk(&argvars[3], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010324 if (time_limit < 0)
10325 goto theend;
10326 }
10327#endif
10328 }
10329
10330#ifdef FEAT_RELTIME
10331 /* Set the time limit, if there is one. */
10332 profile_setlimit(time_limit, &tm);
10333#endif
10334
10335 /*
10336 * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
10337 * Check to make sure only those flags are set.
10338 * Also, Only the SP_NOMOVE or the SP_SETPCMARK flag can be set. Both
10339 * flags cannot be set. Check for that condition also.
10340 */
10341 if (((flags & (SP_REPEAT | SP_RETCOUNT)) != 0)
10342 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10343 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010344 semsg(_(e_invarg2), tv_get_string(&argvars[1]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010345 goto theend;
10346 }
10347
10348 pos = save_cursor = curwin->w_cursor;
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010349 subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010350 options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010351 if (subpatnum != FAIL)
10352 {
10353 if (flags & SP_SUBPAT)
10354 retval = subpatnum;
10355 else
10356 retval = pos.lnum;
10357 if (flags & SP_SETPCMARK)
10358 setpcmark();
10359 curwin->w_cursor = pos;
10360 if (match_pos != NULL)
10361 {
10362 /* Store the match cursor position */
10363 match_pos->lnum = pos.lnum;
10364 match_pos->col = pos.col + 1;
10365 }
10366 /* "/$" will put the cursor after the end of the line, may need to
10367 * correct that here */
10368 check_cursor();
10369 }
10370
10371 /* If 'n' flag is used: restore cursor position. */
10372 if (flags & SP_NOMOVE)
10373 curwin->w_cursor = save_cursor;
10374 else
10375 curwin->w_set_curswant = TRUE;
10376theend:
10377 p_ws = save_p_ws;
10378
10379 return retval;
10380}
10381
10382#ifdef FEAT_FLOAT
10383
10384/*
10385 * round() is not in C90, use ceil() or floor() instead.
10386 */
10387 float_T
10388vim_round(float_T f)
10389{
10390 return f > 0 ? floor(f + 0.5) : ceil(f - 0.5);
10391}
10392
10393/*
10394 * "round({float})" function
10395 */
10396 static void
10397f_round(typval_T *argvars, typval_T *rettv)
10398{
10399 float_T f = 0.0;
10400
10401 rettv->v_type = VAR_FLOAT;
10402 if (get_float_arg(argvars, &f) == OK)
10403 rettv->vval.v_float = vim_round(f);
10404 else
10405 rettv->vval.v_float = 0.0;
10406}
10407#endif
10408
Bram Moolenaare99be0e2019-03-26 22:51:09 +010010409#ifdef FEAT_RUBY
10410/*
10411 * "rubyeval()" function
10412 */
10413 static void
10414f_rubyeval(typval_T *argvars, typval_T *rettv)
10415{
10416 char_u *str;
10417 char_u buf[NUMBUFLEN];
10418
10419 str = tv_get_string_buf(&argvars[0], buf);
10420 do_rubyeval(str, rettv);
10421}
10422#endif
10423
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010424/*
10425 * "screenattr()" function
10426 */
10427 static void
10428f_screenattr(typval_T *argvars, typval_T *rettv)
10429{
10430 int row;
10431 int col;
10432 int c;
10433
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010434 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10435 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010436 if (row < 0 || row >= screen_Rows
10437 || col < 0 || col >= screen_Columns)
10438 c = -1;
10439 else
10440 c = ScreenAttrs[LineOffset[row] + col];
10441 rettv->vval.v_number = c;
10442}
10443
10444/*
10445 * "screenchar()" function
10446 */
10447 static void
10448f_screenchar(typval_T *argvars, typval_T *rettv)
10449{
10450 int row;
10451 int col;
10452 int off;
10453 int c;
10454
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010455 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10456 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010457 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010458 c = -1;
10459 else
10460 {
10461 off = LineOffset[row] + col;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010462 if (enc_utf8 && ScreenLinesUC[off] != 0)
10463 c = ScreenLinesUC[off];
10464 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010465 c = ScreenLines[off];
10466 }
10467 rettv->vval.v_number = c;
10468}
10469
10470/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010471 * "screenchars()" function
10472 */
10473 static void
10474f_screenchars(typval_T *argvars, typval_T *rettv)
10475{
10476 int row;
10477 int col;
10478 int off;
10479 int c;
10480 int i;
10481
10482 if (rettv_list_alloc(rettv) == FAIL)
10483 return;
10484 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10485 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10486 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10487 return;
10488
10489 off = LineOffset[row] + col;
10490 if (enc_utf8 && ScreenLinesUC[off] != 0)
10491 c = ScreenLinesUC[off];
10492 else
10493 c = ScreenLines[off];
10494 list_append_number(rettv->vval.v_list, (varnumber_T)c);
10495
10496 if (enc_utf8)
10497
10498 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10499 list_append_number(rettv->vval.v_list,
10500 (varnumber_T)ScreenLinesC[i][off]);
10501}
10502
10503/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010504 * "screencol()" function
10505 *
10506 * First column is 1 to be consistent with virtcol().
10507 */
10508 static void
10509f_screencol(typval_T *argvars UNUSED, typval_T *rettv)
10510{
10511 rettv->vval.v_number = screen_screencol() + 1;
10512}
10513
10514/*
10515 * "screenrow()" function
10516 */
10517 static void
10518f_screenrow(typval_T *argvars UNUSED, typval_T *rettv)
10519{
10520 rettv->vval.v_number = screen_screenrow() + 1;
10521}
10522
10523/*
Bram Moolenaar2912abb2019-03-29 14:16:42 +010010524 * "screenstring()" function
10525 */
10526 static void
10527f_screenstring(typval_T *argvars, typval_T *rettv)
10528{
10529 int row;
10530 int col;
10531 int off;
10532 int c;
10533 int i;
10534 char_u buf[MB_MAXBYTES + 1];
10535 int buflen = 0;
10536
10537 rettv->vval.v_string = NULL;
10538 rettv->v_type = VAR_STRING;
10539
10540 row = (int)tv_get_number_chk(&argvars[0], NULL) - 1;
10541 col = (int)tv_get_number_chk(&argvars[1], NULL) - 1;
10542 if (row < 0 || row >= screen_Rows || col < 0 || col >= screen_Columns)
10543 return;
10544
10545 off = LineOffset[row] + col;
10546 if (enc_utf8 && ScreenLinesUC[off] != 0)
10547 c = ScreenLinesUC[off];
10548 else
10549 c = ScreenLines[off];
10550 buflen += mb_char2bytes(c, buf);
10551
10552 if (enc_utf8)
10553 for (i = 0; i < Screen_mco && ScreenLinesC[i][off] != 0; ++i)
10554 buflen += mb_char2bytes(ScreenLinesC[i][off], buf + buflen);
10555
10556 buf[buflen] = NUL;
10557 rettv->vval.v_string = vim_strsave(buf);
10558}
10559
10560/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010561 * "search()" function
10562 */
10563 static void
10564f_search(typval_T *argvars, typval_T *rettv)
10565{
10566 int flags = 0;
10567
10568 rettv->vval.v_number = search_cmn(argvars, NULL, &flags);
10569}
10570
10571/*
10572 * "searchdecl()" function
10573 */
10574 static void
10575f_searchdecl(typval_T *argvars, typval_T *rettv)
10576{
10577 int locally = 1;
10578 int thisblock = 0;
10579 int error = FALSE;
10580 char_u *name;
10581
10582 rettv->vval.v_number = 1; /* default: FAIL */
10583
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010584 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010585 if (argvars[1].v_type != VAR_UNKNOWN)
10586 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010587 locally = (int)tv_get_number_chk(&argvars[1], &error) == 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010588 if (!error && argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010589 thisblock = (int)tv_get_number_chk(&argvars[2], &error) != 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010590 }
10591 if (!error && name != NULL)
10592 rettv->vval.v_number = find_decl(name, (int)STRLEN(name),
10593 locally, thisblock, SEARCH_KEEP) == FAIL;
10594}
10595
10596/*
10597 * Used by searchpair() and searchpairpos()
10598 */
10599 static int
10600searchpair_cmn(typval_T *argvars, pos_T *match_pos)
10601{
10602 char_u *spat, *mpat, *epat;
Bram Moolenaar48570482017-10-30 21:48:41 +010010603 typval_T *skip;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010604 int save_p_ws = p_ws;
10605 int dir;
10606 int flags = 0;
10607 char_u nbuf1[NUMBUFLEN];
10608 char_u nbuf2[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010609 int retval = 0; /* default: FAIL */
10610 long lnum_stop = 0;
10611 long time_limit = 0;
10612
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010613 /* Get the three pattern arguments: start, middle, end. Will result in an
10614 * error if not a valid argument. */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010615 spat = tv_get_string_chk(&argvars[0]);
10616 mpat = tv_get_string_buf_chk(&argvars[1], nbuf1);
10617 epat = tv_get_string_buf_chk(&argvars[2], nbuf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010618 if (spat == NULL || mpat == NULL || epat == NULL)
10619 goto theend; /* type error */
10620
10621 /* Handle the optional fourth argument: flags */
10622 dir = get_search_arg(&argvars[3], &flags); /* may set p_ws */
10623 if (dir == 0)
10624 goto theend;
10625
10626 /* Don't accept SP_END or SP_SUBPAT.
10627 * Only one of the SP_NOMOVE or SP_SETPCMARK flags can be set.
10628 */
10629 if ((flags & (SP_END | SP_SUBPAT)) != 0
10630 || ((flags & SP_NOMOVE) && (flags & SP_SETPCMARK)))
10631 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010632 semsg(_(e_invarg2), tv_get_string(&argvars[3]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010633 goto theend;
10634 }
10635
10636 /* Using 'r' implies 'W', otherwise it doesn't work. */
10637 if (flags & SP_REPEAT)
10638 p_ws = FALSE;
10639
10640 /* Optional fifth argument: skip expression */
10641 if (argvars[3].v_type == VAR_UNKNOWN
10642 || argvars[4].v_type == VAR_UNKNOWN)
Bram Moolenaar48570482017-10-30 21:48:41 +010010643 skip = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010644 else
10645 {
Bram Moolenaar48570482017-10-30 21:48:41 +010010646 skip = &argvars[4];
10647 if (skip->v_type != VAR_FUNC && skip->v_type != VAR_PARTIAL
10648 && skip->v_type != VAR_STRING)
10649 {
10650 /* Type error */
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010651 semsg(_(e_invarg2), tv_get_string(&argvars[4]));
Bram Moolenaar48570482017-10-30 21:48:41 +010010652 goto theend;
10653 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010654 if (argvars[5].v_type != VAR_UNKNOWN)
10655 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010656 lnum_stop = (long)tv_get_number_chk(&argvars[5], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010657 if (lnum_stop < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010658 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010659 semsg(_(e_invarg2), tv_get_string(&argvars[5]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010660 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010661 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010662#ifdef FEAT_RELTIME
10663 if (argvars[6].v_type != VAR_UNKNOWN)
10664 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010665 time_limit = (long)tv_get_number_chk(&argvars[6], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010666 if (time_limit < 0)
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010667 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010668 semsg(_(e_invarg2), tv_get_string(&argvars[6]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010669 goto theend;
Bram Moolenaar3dddb092018-06-24 19:01:59 +020010670 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010671 }
10672#endif
10673 }
10674 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010675
10676 retval = do_searchpair(spat, mpat, epat, dir, skip, flags,
10677 match_pos, lnum_stop, time_limit);
10678
10679theend:
10680 p_ws = save_p_ws;
10681
10682 return retval;
10683}
10684
10685/*
10686 * "searchpair()" function
10687 */
10688 static void
10689f_searchpair(typval_T *argvars, typval_T *rettv)
10690{
10691 rettv->vval.v_number = searchpair_cmn(argvars, NULL);
10692}
10693
10694/*
10695 * "searchpairpos()" function
10696 */
10697 static void
10698f_searchpairpos(typval_T *argvars, typval_T *rettv)
10699{
10700 pos_T match_pos;
10701 int lnum = 0;
10702 int col = 0;
10703
10704 if (rettv_list_alloc(rettv) == FAIL)
10705 return;
10706
10707 if (searchpair_cmn(argvars, &match_pos) > 0)
10708 {
10709 lnum = match_pos.lnum;
10710 col = match_pos.col;
10711 }
10712
10713 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10714 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10715}
10716
10717/*
10718 * Search for a start/middle/end thing.
10719 * Used by searchpair(), see its documentation for the details.
10720 * Returns 0 or -1 for no match,
10721 */
10722 long
10723do_searchpair(
10724 char_u *spat, /* start pattern */
10725 char_u *mpat, /* middle pattern */
10726 char_u *epat, /* end pattern */
10727 int dir, /* BACKWARD or FORWARD */
Bram Moolenaar48570482017-10-30 21:48:41 +010010728 typval_T *skip, /* skip expression */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010729 int flags, /* SP_SETPCMARK and other SP_ values */
10730 pos_T *match_pos,
10731 linenr_T lnum_stop, /* stop at this line if not zero */
10732 long time_limit UNUSED) /* stop after this many msec */
10733{
10734 char_u *save_cpo;
10735 char_u *pat, *pat2 = NULL, *pat3 = NULL;
10736 long retval = 0;
10737 pos_T pos;
10738 pos_T firstpos;
10739 pos_T foundpos;
10740 pos_T save_cursor;
10741 pos_T save_pos;
10742 int n;
10743 int r;
10744 int nest = 1;
Bram Moolenaar48570482017-10-30 21:48:41 +010010745 int use_skip = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010746 int err;
10747 int options = SEARCH_KEEP;
10748 proftime_T tm;
10749
10750 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
10751 save_cpo = p_cpo;
10752 p_cpo = empty_option;
10753
10754#ifdef FEAT_RELTIME
10755 /* Set the time limit, if there is one. */
10756 profile_setlimit(time_limit, &tm);
10757#endif
10758
10759 /* Make two search patterns: start/end (pat2, for in nested pairs) and
10760 * start/middle/end (pat3, for the top pair). */
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010761 pat2 = alloc((unsigned)(STRLEN(spat) + STRLEN(epat) + 17));
10762 pat3 = alloc((unsigned)(STRLEN(spat) + STRLEN(mpat) + STRLEN(epat) + 25));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010763 if (pat2 == NULL || pat3 == NULL)
10764 goto theend;
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010765 sprintf((char *)pat2, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010766 if (*mpat == NUL)
10767 STRCPY(pat3, pat2);
10768 else
Bram Moolenaar6e450a52017-01-06 20:03:58 +010010769 sprintf((char *)pat3, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)",
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010770 spat, epat, mpat);
10771 if (flags & SP_START)
10772 options |= SEARCH_START;
10773
Bram Moolenaar48570482017-10-30 21:48:41 +010010774 if (skip != NULL)
10775 {
10776 /* Empty string means to not use the skip expression. */
10777 if (skip->v_type == VAR_STRING || skip->v_type == VAR_FUNC)
10778 use_skip = skip->vval.v_string != NULL
10779 && *skip->vval.v_string != NUL;
10780 }
10781
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010782 save_cursor = curwin->w_cursor;
10783 pos = curwin->w_cursor;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010784 CLEAR_POS(&firstpos);
10785 CLEAR_POS(&foundpos);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010786 pat = pat3;
10787 for (;;)
10788 {
Bram Moolenaar5d24a222018-12-23 19:10:09 +010010789 n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
Bram Moolenaarfbd0b0a2017-06-17 18:44:21 +020010790 options, RE_SEARCH, lnum_stop, &tm, NULL);
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010791 if (n == FAIL || (firstpos.lnum != 0 && EQUAL_POS(pos, firstpos)))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010792 /* didn't find it or found the first match again: FAIL */
10793 break;
10794
10795 if (firstpos.lnum == 0)
10796 firstpos = pos;
Bram Moolenaarb5aedf32017-03-12 18:23:53 +010010797 if (EQUAL_POS(pos, foundpos))
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010798 {
10799 /* Found the same position again. Can happen with a pattern that
10800 * has "\zs" at the end and searching backwards. Advance one
10801 * character and try again. */
10802 if (dir == BACKWARD)
10803 decl(&pos);
10804 else
10805 incl(&pos);
10806 }
10807 foundpos = pos;
10808
10809 /* clear the start flag to avoid getting stuck here */
10810 options &= ~SEARCH_START;
10811
10812 /* If the skip pattern matches, ignore this match. */
Bram Moolenaar48570482017-10-30 21:48:41 +010010813 if (use_skip)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010814 {
10815 save_pos = curwin->w_cursor;
10816 curwin->w_cursor = pos;
Bram Moolenaar48570482017-10-30 21:48:41 +010010817 err = FALSE;
10818 r = eval_expr_to_bool(skip, &err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010819 curwin->w_cursor = save_pos;
10820 if (err)
10821 {
10822 /* Evaluating {skip} caused an error, break here. */
10823 curwin->w_cursor = save_cursor;
10824 retval = -1;
10825 break;
10826 }
10827 if (r)
10828 continue;
10829 }
10830
10831 if ((dir == BACKWARD && n == 3) || (dir == FORWARD && n == 2))
10832 {
10833 /* Found end when searching backwards or start when searching
10834 * forward: nested pair. */
10835 ++nest;
10836 pat = pat2; /* nested, don't search for middle */
10837 }
10838 else
10839 {
10840 /* Found end when searching forward or start when searching
10841 * backward: end of (nested) pair; or found middle in outer pair. */
10842 if (--nest == 1)
10843 pat = pat3; /* outer level, search for middle */
10844 }
10845
10846 if (nest == 0)
10847 {
10848 /* Found the match: return matchcount or line number. */
10849 if (flags & SP_RETCOUNT)
10850 ++retval;
10851 else
10852 retval = pos.lnum;
10853 if (flags & SP_SETPCMARK)
10854 setpcmark();
10855 curwin->w_cursor = pos;
10856 if (!(flags & SP_REPEAT))
10857 break;
10858 nest = 1; /* search for next unmatched */
10859 }
10860 }
10861
10862 if (match_pos != NULL)
10863 {
10864 /* Store the match cursor position */
10865 match_pos->lnum = curwin->w_cursor.lnum;
10866 match_pos->col = curwin->w_cursor.col + 1;
10867 }
10868
10869 /* If 'n' flag is used or search failed: restore cursor position. */
10870 if ((flags & SP_NOMOVE) || retval == 0)
10871 curwin->w_cursor = save_cursor;
10872
10873theend:
10874 vim_free(pat2);
10875 vim_free(pat3);
10876 if (p_cpo == empty_option)
10877 p_cpo = save_cpo;
10878 else
10879 /* Darn, evaluating the {skip} expression changed the value. */
10880 free_string_option(save_cpo);
10881
10882 return retval;
10883}
10884
10885/*
10886 * "searchpos()" function
10887 */
10888 static void
10889f_searchpos(typval_T *argvars, typval_T *rettv)
10890{
10891 pos_T match_pos;
10892 int lnum = 0;
10893 int col = 0;
10894 int n;
10895 int flags = 0;
10896
10897 if (rettv_list_alloc(rettv) == FAIL)
10898 return;
10899
10900 n = search_cmn(argvars, &match_pos, &flags);
10901 if (n > 0)
10902 {
10903 lnum = match_pos.lnum;
10904 col = match_pos.col;
10905 }
10906
10907 list_append_number(rettv->vval.v_list, (varnumber_T)lnum);
10908 list_append_number(rettv->vval.v_list, (varnumber_T)col);
10909 if (flags & SP_SUBPAT)
10910 list_append_number(rettv->vval.v_list, (varnumber_T)n);
10911}
10912
10913 static void
10914f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
10915{
10916#ifdef FEAT_CLIENTSERVER
10917 char_u buf[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010918 char_u *server = tv_get_string_chk(&argvars[0]);
10919 char_u *reply = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010920
10921 rettv->vval.v_number = -1;
10922 if (server == NULL || reply == NULL)
10923 return;
10924 if (check_restricted() || check_secure())
10925 return;
10926# ifdef FEAT_X11
10927 if (check_connection() == FAIL)
10928 return;
10929# endif
10930
10931 if (serverSendReply(server, reply) < 0)
10932 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010010933 emsg(_("E258: Unable to send to client"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010934 return;
10935 }
10936 rettv->vval.v_number = 0;
10937#else
10938 rettv->vval.v_number = -1;
10939#endif
10940}
10941
10942 static void
10943f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
10944{
10945 char_u *r = NULL;
10946
10947#ifdef FEAT_CLIENTSERVER
Bram Moolenaar4f974752019-02-17 17:44:42 +010010948# ifdef MSWIN
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010949 r = serverGetVimNames();
10950# else
10951 make_connection();
10952 if (X_DISPLAY != NULL)
10953 r = serverGetVimNames(X_DISPLAY);
10954# endif
10955#endif
10956 rettv->v_type = VAR_STRING;
10957 rettv->vval.v_string = r;
10958}
10959
10960/*
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010961 * "setbufline()" function
10962 */
10963 static void
Bram Moolenaar6f8d2ac2018-07-25 19:49:45 +020010964f_setbufline(typval_T *argvars, typval_T *rettv)
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010965{
10966 linenr_T lnum;
10967 buf_T *buf;
10968
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010969 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010970 if (buf == NULL)
10971 rettv->vval.v_number = 1; /* FAIL */
10972 else
10973 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010974 lnum = tv_get_lnum_buf(&argvars[1], buf);
Bram Moolenaarca851592018-06-06 21:04:07 +020010975 set_buffer_lines(buf, lnum, FALSE, &argvars[2], rettv);
Bram Moolenaarb31cf2b2017-09-02 19:45:19 +020010976 }
10977}
10978
10979/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010980 * "setbufvar()" function
10981 */
10982 static void
10983f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
10984{
10985 buf_T *buf;
10986 char_u *varname, *bufvarname;
10987 typval_T *varp;
10988 char_u nbuf[NUMBUFLEN];
10989
Bram Moolenaar8c62a082019-02-08 14:34:10 +010010990 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010991 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010010992 (void)tv_get_number(&argvars[0]); /* issue errmsg if type error */
10993 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010010994 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020010995 varp = &argvars[2];
10996
10997 if (buf != NULL && varname != NULL && varp != NULL)
10998 {
10999 if (*varname == '&')
11000 {
11001 long numval;
11002 char_u *strval;
11003 int error = FALSE;
11004 aco_save_T aco;
11005
11006 /* set curbuf to be our buf, temporarily */
11007 aucmd_prepbuf(&aco, buf);
11008
11009 ++varname;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011010 numval = (long)tv_get_number_chk(varp, &error);
11011 strval = tv_get_string_buf_chk(varp, nbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011012 if (!error && strval != NULL)
11013 set_option_value(varname, numval, strval, OPT_LOCAL);
11014
11015 /* reset notion of buffer */
11016 aucmd_restbuf(&aco);
11017 }
11018 else
11019 {
11020 buf_T *save_curbuf = curbuf;
11021
11022 bufvarname = alloc((unsigned)STRLEN(varname) + 3);
11023 if (bufvarname != NULL)
11024 {
11025 curbuf = buf;
11026 STRCPY(bufvarname, "b:");
11027 STRCPY(bufvarname + 2, varname);
11028 set_var(bufvarname, varp, TRUE);
11029 vim_free(bufvarname);
11030 curbuf = save_curbuf;
11031 }
11032 }
11033 }
11034}
11035
11036 static void
11037f_setcharsearch(typval_T *argvars, typval_T *rettv UNUSED)
11038{
11039 dict_T *d;
11040 dictitem_T *di;
11041 char_u *csearch;
11042
11043 if (argvars[0].v_type != VAR_DICT)
11044 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011045 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011046 return;
11047 }
11048
11049 if ((d = argvars[0].vval.v_dict) != NULL)
11050 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010011051 csearch = dict_get_string(d, (char_u *)"char", FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011052 if (csearch != NULL)
11053 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011054 if (enc_utf8)
11055 {
11056 int pcc[MAX_MCO];
11057 int c = utfc_ptr2char(csearch, pcc);
11058
11059 set_last_csearch(c, csearch, utfc_ptr2len(csearch));
11060 }
11061 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011062 set_last_csearch(PTR2CHAR(csearch),
11063 csearch, MB_PTR2LEN(csearch));
11064 }
11065
11066 di = dict_find(d, (char_u *)"forward", -1);
11067 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011068 set_csearch_direction((int)tv_get_number(&di->di_tv)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011069 ? FORWARD : BACKWARD);
11070
11071 di = dict_find(d, (char_u *)"until", -1);
11072 if (di != NULL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011073 set_csearch_until(!!tv_get_number(&di->di_tv));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011074 }
11075}
11076
11077/*
11078 * "setcmdpos()" function
11079 */
11080 static void
11081f_setcmdpos(typval_T *argvars, typval_T *rettv)
11082{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011083 int pos = (int)tv_get_number(&argvars[0]) - 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011084
11085 if (pos >= 0)
11086 rettv->vval.v_number = set_cmdline_pos(pos);
11087}
11088
11089/*
11090 * "setfperm({fname}, {mode})" function
11091 */
11092 static void
11093f_setfperm(typval_T *argvars, typval_T *rettv)
11094{
11095 char_u *fname;
11096 char_u modebuf[NUMBUFLEN];
11097 char_u *mode_str;
11098 int i;
11099 int mask;
11100 int mode = 0;
11101
11102 rettv->vval.v_number = 0;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011103 fname = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011104 if (fname == NULL)
11105 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011106 mode_str = tv_get_string_buf_chk(&argvars[1], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011107 if (mode_str == NULL)
11108 return;
11109 if (STRLEN(mode_str) != 9)
11110 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011111 semsg(_(e_invarg2), mode_str);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011112 return;
11113 }
11114
11115 mask = 1;
11116 for (i = 8; i >= 0; --i)
11117 {
11118 if (mode_str[i] != '-')
11119 mode |= mask;
11120 mask = mask << 1;
11121 }
11122 rettv->vval.v_number = mch_setperm(fname, mode) == OK;
11123}
11124
11125/*
11126 * "setline()" function
11127 */
11128 static void
11129f_setline(typval_T *argvars, typval_T *rettv)
11130{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011131 linenr_T lnum = tv_get_lnum(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011132
Bram Moolenaarca851592018-06-06 21:04:07 +020011133 set_buffer_lines(curbuf, lnum, FALSE, &argvars[1], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011134}
11135
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011136/*
11137 * Used by "setqflist()" and "setloclist()" functions
11138 */
11139 static void
11140set_qf_ll_list(
11141 win_T *wp UNUSED,
11142 typval_T *list_arg UNUSED,
11143 typval_T *action_arg UNUSED,
Bram Moolenaard823fa92016-08-12 16:29:27 +020011144 typval_T *what_arg UNUSED,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011145 typval_T *rettv)
11146{
11147#ifdef FEAT_QUICKFIX
11148 static char *e_invact = N_("E927: Invalid action: '%s'");
11149 char_u *act;
11150 int action = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011151 static int recursive = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011152#endif
11153
11154 rettv->vval.v_number = -1;
11155
11156#ifdef FEAT_QUICKFIX
11157 if (list_arg->v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011158 emsg(_(e_listreq));
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011159 else if (recursive != 0)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011160 emsg(_(e_au_recursive));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011161 else
11162 {
11163 list_T *l = list_arg->vval.v_list;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011164 dict_T *d = NULL;
11165 int valid_dict = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011166
11167 if (action_arg->v_type == VAR_STRING)
11168 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011169 act = tv_get_string_chk(action_arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011170 if (act == NULL)
11171 return; /* type error; errmsg already given */
Bram Moolenaarb6fa30c2017-03-29 14:19:25 +020011172 if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
11173 act[1] == NUL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011174 action = *act;
11175 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011176 semsg(_(e_invact), act);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011177 }
11178 else if (action_arg->v_type == VAR_UNKNOWN)
11179 action = ' ';
11180 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011181 emsg(_(e_stringreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011182
Bram Moolenaard823fa92016-08-12 16:29:27 +020011183 if (action_arg->v_type != VAR_UNKNOWN
11184 && what_arg->v_type != VAR_UNKNOWN)
11185 {
11186 if (what_arg->v_type == VAR_DICT)
11187 d = what_arg->vval.v_dict;
11188 else
11189 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011190 emsg(_(e_dictreq));
Bram Moolenaard823fa92016-08-12 16:29:27 +020011191 valid_dict = FALSE;
11192 }
11193 }
11194
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011195 ++recursive;
Bram Moolenaard823fa92016-08-12 16:29:27 +020011196 if (l != NULL && action && valid_dict && set_errorlist(wp, l, action,
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011197 (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
11198 d) == OK)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011199 rettv->vval.v_number = 0;
Bram Moolenaar2f82ca72018-06-17 19:22:52 +020011200 --recursive;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011201 }
11202#endif
11203}
11204
11205/*
11206 * "setloclist()" function
11207 */
11208 static void
11209f_setloclist(typval_T *argvars, typval_T *rettv)
11210{
11211 win_T *win;
11212
11213 rettv->vval.v_number = -1;
11214
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020011215 win = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011216 if (win != NULL)
Bram Moolenaard823fa92016-08-12 16:29:27 +020011217 set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011218}
11219
11220/*
11221 * "setmatches()" function
11222 */
11223 static void
11224f_setmatches(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
11225{
11226#ifdef FEAT_SEARCH_EXTRA
11227 list_T *l;
11228 listitem_T *li;
11229 dict_T *d;
11230 list_T *s = NULL;
Bram Moolenaaraff74912019-03-30 18:11:49 +010011231 win_T *win = get_optional_window(argvars, 1);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011232
11233 rettv->vval.v_number = -1;
11234 if (argvars[0].v_type != VAR_LIST)
11235 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011236 emsg(_(e_listreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011237 return;
11238 }
Bram Moolenaaraff74912019-03-30 18:11:49 +010011239 if (win == NULL)
11240 return;
11241
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011242 if ((l = argvars[0].vval.v_list) != NULL)
11243 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011244 /* To some extent make sure that we are dealing with a list from
11245 * "getmatches()". */
11246 li = l->lv_first;
11247 while (li != NULL)
11248 {
11249 if (li->li_tv.v_type != VAR_DICT
11250 || (d = li->li_tv.vval.v_dict) == NULL)
11251 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011252 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011253 return;
11254 }
11255 if (!(dict_find(d, (char_u *)"group", -1) != NULL
11256 && (dict_find(d, (char_u *)"pattern", -1) != NULL
11257 || dict_find(d, (char_u *)"pos1", -1) != NULL)
11258 && dict_find(d, (char_u *)"priority", -1) != NULL
11259 && dict_find(d, (char_u *)"id", -1) != NULL))
11260 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011261 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011262 return;
11263 }
11264 li = li->li_next;
11265 }
11266
Bram Moolenaaraff74912019-03-30 18:11:49 +010011267 clear_matches(win);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011268 li = l->lv_first;
11269 while (li != NULL)
11270 {
11271 int i = 0;
11272 char_u buf[5];
11273 dictitem_T *di;
11274 char_u *group;
11275 int priority;
11276 int id;
11277 char_u *conceal;
11278
11279 d = li->li_tv.vval.v_dict;
11280 if (dict_find(d, (char_u *)"pattern", -1) == NULL)
11281 {
11282 if (s == NULL)
11283 {
11284 s = list_alloc();
11285 if (s == NULL)
11286 return;
11287 }
11288
11289 /* match from matchaddpos() */
11290 for (i = 1; i < 9; i++)
11291 {
11292 sprintf((char *)buf, (char *)"pos%d", i);
11293 if ((di = dict_find(d, (char_u *)buf, -1)) != NULL)
11294 {
11295 if (di->di_tv.v_type != VAR_LIST)
11296 return;
11297
11298 list_append_tv(s, &di->di_tv);
11299 s->lv_refcount++;
11300 }
11301 else
11302 break;
11303 }
11304 }
11305
Bram Moolenaar8f667172018-12-14 15:38:31 +010011306 group = dict_get_string(d, (char_u *)"group", TRUE);
11307 priority = (int)dict_get_number(d, (char_u *)"priority");
11308 id = (int)dict_get_number(d, (char_u *)"id");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011309 conceal = dict_find(d, (char_u *)"conceal", -1) != NULL
Bram Moolenaar8f667172018-12-14 15:38:31 +010011310 ? dict_get_string(d, (char_u *)"conceal", TRUE)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011311 : NULL;
11312 if (i == 0)
11313 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011314 match_add(win, group,
Bram Moolenaar8f667172018-12-14 15:38:31 +010011315 dict_get_string(d, (char_u *)"pattern", FALSE),
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011316 priority, id, NULL, conceal);
11317 }
11318 else
11319 {
Bram Moolenaaraff74912019-03-30 18:11:49 +010011320 match_add(win, group, NULL, priority, id, s, conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011321 list_unref(s);
11322 s = NULL;
11323 }
Bram Moolenaar7dc5e2e2016-08-05 22:22:06 +020011324 vim_free(group);
11325 vim_free(conceal);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011326
11327 li = li->li_next;
11328 }
11329 rettv->vval.v_number = 0;
11330 }
11331#endif
11332}
11333
11334/*
11335 * "setpos()" function
11336 */
11337 static void
11338f_setpos(typval_T *argvars, typval_T *rettv)
11339{
11340 pos_T pos;
11341 int fnum;
11342 char_u *name;
11343 colnr_T curswant = -1;
11344
11345 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011346 name = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011347 if (name != NULL)
11348 {
11349 if (list2fpos(&argvars[1], &pos, &fnum, &curswant) == OK)
11350 {
11351 if (--pos.col < 0)
11352 pos.col = 0;
11353 if (name[0] == '.' && name[1] == NUL)
11354 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011355 /* set cursor; "fnum" is ignored */
11356 curwin->w_cursor = pos;
11357 if (curswant >= 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011358 {
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011359 curwin->w_curswant = curswant - 1;
11360 curwin->w_set_curswant = FALSE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011361 }
Bram Moolenaar3a29abc2017-01-28 18:31:41 +010011362 check_cursor();
11363 rettv->vval.v_number = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011364 }
11365 else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL)
11366 {
11367 /* set mark */
11368 if (setmark_pos(name[1], &pos, fnum) == OK)
11369 rettv->vval.v_number = 0;
11370 }
11371 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011372 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011373 }
11374 }
11375}
11376
11377/*
11378 * "setqflist()" function
11379 */
11380 static void
11381f_setqflist(typval_T *argvars, typval_T *rettv)
11382{
Bram Moolenaard823fa92016-08-12 16:29:27 +020011383 set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011384}
11385
11386/*
11387 * "setreg()" function
11388 */
11389 static void
11390f_setreg(typval_T *argvars, typval_T *rettv)
11391{
11392 int regname;
11393 char_u *strregname;
11394 char_u *stropt;
11395 char_u *strval;
11396 int append;
11397 char_u yank_type;
11398 long block_len;
11399
11400 block_len = -1;
11401 yank_type = MAUTO;
11402 append = FALSE;
11403
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011404 strregname = tv_get_string_chk(argvars);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011405 rettv->vval.v_number = 1; /* FAIL is default */
11406
11407 if (strregname == NULL)
11408 return; /* type error; errmsg already given */
11409 regname = *strregname;
11410 if (regname == 0 || regname == '@')
11411 regname = '"';
11412
11413 if (argvars[2].v_type != VAR_UNKNOWN)
11414 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011415 stropt = tv_get_string_chk(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011416 if (stropt == NULL)
11417 return; /* type error */
11418 for (; *stropt != NUL; ++stropt)
11419 switch (*stropt)
11420 {
11421 case 'a': case 'A': /* append */
11422 append = TRUE;
11423 break;
11424 case 'v': case 'c': /* character-wise selection */
11425 yank_type = MCHAR;
11426 break;
11427 case 'V': case 'l': /* line-wise selection */
11428 yank_type = MLINE;
11429 break;
11430 case 'b': case Ctrl_V: /* block-wise selection */
11431 yank_type = MBLOCK;
11432 if (VIM_ISDIGIT(stropt[1]))
11433 {
11434 ++stropt;
11435 block_len = getdigits(&stropt) - 1;
11436 --stropt;
11437 }
11438 break;
11439 }
11440 }
11441
11442 if (argvars[1].v_type == VAR_LIST)
11443 {
11444 char_u **lstval;
11445 char_u **allocval;
11446 char_u buf[NUMBUFLEN];
11447 char_u **curval;
11448 char_u **curallocval;
11449 list_T *ll = argvars[1].vval.v_list;
11450 listitem_T *li;
11451 int len;
11452
11453 /* If the list is NULL handle like an empty list. */
11454 len = ll == NULL ? 0 : ll->lv_len;
11455
11456 /* First half: use for pointers to result lines; second half: use for
11457 * pointers to allocated copies. */
11458 lstval = (char_u **)alloc(sizeof(char_u *) * ((len + 1) * 2));
11459 if (lstval == NULL)
11460 return;
11461 curval = lstval;
11462 allocval = lstval + len + 2;
11463 curallocval = allocval;
11464
11465 for (li = ll == NULL ? NULL : ll->lv_first; li != NULL;
11466 li = li->li_next)
11467 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011468 strval = tv_get_string_buf_chk(&li->li_tv, buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011469 if (strval == NULL)
11470 goto free_lstval;
11471 if (strval == buf)
11472 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011473 /* Need to make a copy, next tv_get_string_buf_chk() will
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011474 * overwrite the string. */
11475 strval = vim_strsave(buf);
11476 if (strval == NULL)
11477 goto free_lstval;
11478 *curallocval++ = strval;
11479 }
11480 *curval++ = strval;
11481 }
11482 *curval++ = NULL;
11483
11484 write_reg_contents_lst(regname, lstval, -1,
11485 append, yank_type, block_len);
11486free_lstval:
11487 while (curallocval > allocval)
11488 vim_free(*--curallocval);
11489 vim_free(lstval);
11490 }
11491 else
11492 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011493 strval = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011494 if (strval == NULL)
11495 return;
11496 write_reg_contents_ex(regname, strval, -1,
11497 append, yank_type, block_len);
11498 }
11499 rettv->vval.v_number = 0;
11500}
11501
11502/*
11503 * "settabvar()" function
11504 */
11505 static void
11506f_settabvar(typval_T *argvars, typval_T *rettv)
11507{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011508 tabpage_T *save_curtab;
11509 tabpage_T *tp;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011510 char_u *varname, *tabvarname;
11511 typval_T *varp;
11512
11513 rettv->vval.v_number = 0;
11514
Bram Moolenaar8c62a082019-02-08 14:34:10 +010011515 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011516 return;
11517
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011518 tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
11519 varname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011520 varp = &argvars[2];
11521
Bram Moolenaar4033c552017-09-16 20:54:51 +020011522 if (varname != NULL && varp != NULL && tp != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011523 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011524 save_curtab = curtab;
11525 goto_tabpage_tp(tp, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011526
11527 tabvarname = alloc((unsigned)STRLEN(varname) + 3);
11528 if (tabvarname != NULL)
11529 {
11530 STRCPY(tabvarname, "t:");
11531 STRCPY(tabvarname + 2, varname);
11532 set_var(tabvarname, varp, TRUE);
11533 vim_free(tabvarname);
11534 }
11535
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011536 /* Restore current tabpage */
11537 if (valid_tabpage(save_curtab))
11538 goto_tabpage_tp(save_curtab, FALSE, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011539 }
11540}
11541
11542/*
11543 * "settabwinvar()" function
11544 */
11545 static void
11546f_settabwinvar(typval_T *argvars, typval_T *rettv)
11547{
11548 setwinvar(argvars, rettv, 1);
11549}
11550
11551/*
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011552 * "settagstack()" function
11553 */
11554 static void
11555f_settagstack(typval_T *argvars, typval_T *rettv)
11556{
11557 static char *e_invact2 = N_("E962: Invalid action: '%s'");
11558 win_T *wp;
11559 dict_T *d;
11560 int action = 'r';
11561
11562 rettv->vval.v_number = -1;
11563
11564 // first argument: window number or id
11565 wp = find_win_by_nr_or_id(&argvars[0]);
11566 if (wp == NULL)
11567 return;
11568
11569 // second argument: dict with items to set in the tag stack
11570 if (argvars[1].v_type != VAR_DICT)
11571 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011572 emsg(_(e_dictreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011573 return;
11574 }
11575 d = argvars[1].vval.v_dict;
11576 if (d == NULL)
11577 return;
11578
11579 // third argument: action - 'a' for append and 'r' for replace.
11580 // default is to replace the stack.
11581 if (argvars[2].v_type == VAR_UNKNOWN)
11582 action = 'r';
11583 else if (argvars[2].v_type == VAR_STRING)
11584 {
11585 char_u *actstr;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011586 actstr = tv_get_string_chk(&argvars[2]);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011587 if (actstr == NULL)
11588 return;
11589 if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
11590 action = *actstr;
11591 else
11592 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011593 semsg(_(e_invact2), actstr);
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011594 return;
11595 }
11596 }
11597 else
11598 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011599 emsg(_(e_stringreq));
Bram Moolenaarf49cc602018-11-11 15:21:05 +010011600 return;
11601 }
11602
11603 if (set_tagstack(wp, d, action) == OK)
11604 rettv->vval.v_number = 0;
11605}
11606
11607/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011608 * "setwinvar()" function
11609 */
11610 static void
11611f_setwinvar(typval_T *argvars, typval_T *rettv)
11612{
11613 setwinvar(argvars, rettv, 0);
11614}
11615
11616#ifdef FEAT_CRYPT
11617/*
11618 * "sha256({string})" function
11619 */
11620 static void
11621f_sha256(typval_T *argvars, typval_T *rettv)
11622{
11623 char_u *p;
11624
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011625 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011626 rettv->vval.v_string = vim_strsave(
11627 sha256_bytes(p, (int)STRLEN(p), NULL, 0));
11628 rettv->v_type = VAR_STRING;
11629}
11630#endif /* FEAT_CRYPT */
11631
11632/*
11633 * "shellescape({string})" function
11634 */
11635 static void
11636f_shellescape(typval_T *argvars, typval_T *rettv)
11637{
Bram Moolenaar20615522017-06-05 18:46:26 +020011638 int do_special = non_zero_arg(&argvars[1]);
11639
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011640 rettv->vval.v_string = vim_strsave_shellescape(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011641 tv_get_string(&argvars[0]), do_special, do_special);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011642 rettv->v_type = VAR_STRING;
11643}
11644
11645/*
11646 * shiftwidth() function
11647 */
11648 static void
11649f_shiftwidth(typval_T *argvars UNUSED, typval_T *rettv)
11650{
Bram Moolenaarf9514162018-11-22 03:08:29 +010011651 rettv->vval.v_number = 0;
11652
11653 if (argvars[0].v_type != VAR_UNKNOWN)
11654 {
11655 long col;
11656
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011657 col = (long)tv_get_number_chk(argvars, NULL);
Bram Moolenaarf9514162018-11-22 03:08:29 +010011658 if (col < 0)
11659 return; // type error; errmsg already given
11660#ifdef FEAT_VARTABS
11661 rettv->vval.v_number = get_sw_value_col(curbuf, col);
11662 return;
11663#endif
11664 }
11665
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020011666 rettv->vval.v_number = get_sw_value(curbuf);
11667}
11668
Bram Moolenaar162b7142018-12-21 15:17:36 +010011669#ifdef FEAT_SIGNS
11670/*
11671 * "sign_define()" function
11672 */
11673 static void
11674f_sign_define(typval_T *argvars, typval_T *rettv)
11675{
11676 char_u *name;
11677 dict_T *dict;
11678 char_u *icon = NULL;
11679 char_u *linehl = NULL;
11680 char_u *text = NULL;
11681 char_u *texthl = NULL;
11682
11683 rettv->vval.v_number = -1;
11684
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011685 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011686 if (name == NULL)
11687 return;
11688
11689 if (argvars[1].v_type != VAR_UNKNOWN)
11690 {
11691 if (argvars[1].v_type != VAR_DICT)
11692 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011693 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011694 return;
11695 }
11696
11697 // sign attributes
11698 dict = argvars[1].vval.v_dict;
11699 if (dict_find(dict, (char_u *)"icon", -1) != NULL)
11700 icon = dict_get_string(dict, (char_u *)"icon", TRUE);
11701 if (dict_find(dict, (char_u *)"linehl", -1) != NULL)
11702 linehl = dict_get_string(dict, (char_u *)"linehl", TRUE);
11703 if (dict_find(dict, (char_u *)"text", -1) != NULL)
11704 text = dict_get_string(dict, (char_u *)"text", TRUE);
11705 if (dict_find(dict, (char_u *)"texthl", -1) != NULL)
11706 texthl = dict_get_string(dict, (char_u *)"texthl", TRUE);
11707 }
11708
11709 if (sign_define_by_name(name, icon, linehl, text, texthl) == OK)
11710 rettv->vval.v_number = 0;
11711
11712 vim_free(icon);
11713 vim_free(linehl);
11714 vim_free(text);
11715 vim_free(texthl);
11716}
11717
11718/*
11719 * "sign_getdefined()" function
11720 */
11721 static void
11722f_sign_getdefined(typval_T *argvars, typval_T *rettv)
11723{
11724 char_u *name = NULL;
11725
11726 if (rettv_list_alloc_id(rettv, aid_sign_getdefined) != OK)
11727 return;
11728
11729 if (argvars[0].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011730 name = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011731
11732 sign_getlist(name, rettv->vval.v_list);
11733}
11734
11735/*
11736 * "sign_getplaced()" function
11737 */
11738 static void
11739f_sign_getplaced(typval_T *argvars, typval_T *rettv)
11740{
11741 buf_T *buf = NULL;
11742 dict_T *dict;
11743 dictitem_T *di;
11744 linenr_T lnum = 0;
11745 int sign_id = 0;
11746 char_u *group = NULL;
11747 int notanum = FALSE;
11748
11749 if (rettv_list_alloc_id(rettv, aid_sign_getplaced) != OK)
11750 return;
11751
11752 if (argvars[0].v_type != VAR_UNKNOWN)
11753 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011754 // get signs placed in the specified buffer
11755 buf = get_buf_arg(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011756 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011757 return;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011758
11759 if (argvars[1].v_type != VAR_UNKNOWN)
11760 {
11761 if (argvars[1].v_type != VAR_DICT ||
11762 ((dict = argvars[1].vval.v_dict) == NULL))
11763 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011764 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011765 return;
11766 }
11767 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11768 {
11769 // get signs placed at this line
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011770 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011771 if (notanum)
11772 return;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011773 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011774 }
11775 if ((di = dict_find(dict, (char_u *)"id", -1)) != NULL)
11776 {
11777 // get sign placed with this identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011778 sign_id = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011779 if (notanum)
11780 return;
11781 }
11782 if ((di = dict_find(dict, (char_u *)"group", -1)) != NULL)
11783 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011784 group = tv_get_string_chk(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011785 if (group == NULL)
11786 return;
Bram Moolenaar6436cd82018-12-27 00:28:33 +010011787 if (*group == '\0') // empty string means global group
11788 group = NULL;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011789 }
11790 }
11791 }
11792
11793 sign_get_placed(buf, lnum, sign_id, group, rettv->vval.v_list);
11794}
11795
11796/*
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011797 * "sign_jump()" function
11798 */
11799 static void
11800f_sign_jump(typval_T *argvars, typval_T *rettv)
11801{
11802 int sign_id;
11803 char_u *sign_group = NULL;
11804 buf_T *buf;
11805 int notanum = FALSE;
11806
11807 rettv->vval.v_number = -1;
11808
Bram Moolenaarbdace832019-03-02 10:13:42 +010011809 // Sign identifier
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011810 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
11811 if (notanum)
11812 return;
11813 if (sign_id <= 0)
11814 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011815 emsg(_(e_invarg));
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011816 return;
11817 }
11818
11819 // Sign group
11820 sign_group = tv_get_string_chk(&argvars[1]);
11821 if (sign_group == NULL)
11822 return;
11823 if (sign_group[0] == '\0')
11824 sign_group = NULL; // global sign group
11825 else
11826 {
11827 sign_group = vim_strsave(sign_group);
11828 if (sign_group == NULL)
11829 return;
11830 }
11831
11832 // Buffer to place the sign
11833 buf = get_buf_arg(&argvars[2]);
11834 if (buf == NULL)
11835 goto cleanup;
11836
11837 rettv->vval.v_number = sign_jump(sign_id, sign_group, buf);
11838
11839cleanup:
11840 vim_free(sign_group);
11841}
11842
11843/*
Bram Moolenaar162b7142018-12-21 15:17:36 +010011844 * "sign_place()" function
11845 */
11846 static void
11847f_sign_place(typval_T *argvars, typval_T *rettv)
11848{
11849 int sign_id;
11850 char_u *group = NULL;
11851 char_u *sign_name;
11852 buf_T *buf;
11853 dict_T *dict;
11854 dictitem_T *di;
11855 linenr_T lnum = 0;
11856 int prio = SIGN_DEF_PRIO;
11857 int notanum = FALSE;
11858
11859 rettv->vval.v_number = -1;
11860
Bram Moolenaarbdace832019-03-02 10:13:42 +010011861 // Sign identifier
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011862 sign_id = (int)tv_get_number_chk(&argvars[0], &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011863 if (notanum)
11864 return;
11865 if (sign_id < 0)
11866 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011867 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011868 return;
11869 }
11870
11871 // Sign group
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011872 group = tv_get_string_chk(&argvars[1]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011873 if (group == NULL)
11874 return;
11875 if (group[0] == '\0')
11876 group = NULL; // global sign group
11877 else
11878 {
11879 group = vim_strsave(group);
11880 if (group == NULL)
11881 return;
11882 }
11883
11884 // Sign name
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011885 sign_name = tv_get_string_chk(&argvars[2]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011886 if (sign_name == NULL)
11887 goto cleanup;
11888
11889 // Buffer to place the sign
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011890 buf = get_buf_arg(&argvars[3]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011891 if (buf == NULL)
Bram Moolenaar162b7142018-12-21 15:17:36 +010011892 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011893
11894 if (argvars[4].v_type != VAR_UNKNOWN)
11895 {
11896 if (argvars[4].v_type != VAR_DICT ||
11897 ((dict = argvars[4].vval.v_dict) == NULL))
11898 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011899 emsg(_(e_dictreq));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011900 goto cleanup;
11901 }
11902
11903 // Line number where the sign is to be placed
11904 if ((di = dict_find(dict, (char_u *)"lnum", -1)) != NULL)
11905 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011906 (void)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011907 if (notanum)
11908 goto cleanup;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011909 lnum = tv_get_lnum(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011910 }
11911 if ((di = dict_find(dict, (char_u *)"priority", -1)) != NULL)
11912 {
11913 // Sign priority
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011914 prio = (int)tv_get_number_chk(&di->di_tv, &notanum);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011915 if (notanum)
11916 goto cleanup;
11917 }
11918 }
11919
11920 if (sign_place(&sign_id, group, sign_name, buf, lnum, prio) == OK)
11921 rettv->vval.v_number = sign_id;
11922
11923cleanup:
11924 vim_free(group);
11925}
11926
11927/*
11928 * "sign_undefine()" function
11929 */
11930 static void
11931f_sign_undefine(typval_T *argvars, typval_T *rettv)
11932{
11933 char_u *name;
11934
11935 rettv->vval.v_number = -1;
11936
11937 if (argvars[0].v_type == VAR_UNKNOWN)
11938 {
11939 // Free all the signs
11940 free_signs();
11941 rettv->vval.v_number = 0;
11942 }
11943 else
11944 {
11945 // Free only the specified sign
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011946 name = tv_get_string_chk(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011947 if (name == NULL)
11948 return;
11949
11950 if (sign_undefine_by_name(name) == OK)
11951 rettv->vval.v_number = 0;
11952 }
11953}
11954
11955/*
11956 * "sign_unplace()" function
11957 */
11958 static void
11959f_sign_unplace(typval_T *argvars, typval_T *rettv)
11960{
11961 dict_T *dict;
11962 dictitem_T *di;
11963 int sign_id = 0;
11964 buf_T *buf = NULL;
11965 char_u *group = NULL;
11966
11967 rettv->vval.v_number = -1;
11968
11969 if (argvars[0].v_type != VAR_STRING)
11970 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011971 emsg(_(e_invarg));
Bram Moolenaar162b7142018-12-21 15:17:36 +010011972 return;
11973 }
11974
Bram Moolenaard155d7a2018-12-21 16:04:21 +010011975 group = tv_get_string(&argvars[0]);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011976 if (group[0] == '\0')
11977 group = NULL; // global sign group
11978 else
11979 {
11980 group = vim_strsave(group);
11981 if (group == NULL)
11982 return;
11983 }
11984
11985 if (argvars[1].v_type != VAR_UNKNOWN)
11986 {
11987 if (argvars[1].v_type != VAR_DICT)
11988 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010011989 emsg(_(e_dictreq));
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011990 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011991 }
11992 dict = argvars[1].vval.v_dict;
11993
11994 if ((di = dict_find(dict, (char_u *)"buffer", -1)) != NULL)
11995 {
Bram Moolenaar6b7b7192019-01-11 13:42:41 +010011996 buf = get_buf_arg(&di->di_tv);
Bram Moolenaar162b7142018-12-21 15:17:36 +010011997 if (buf == NULL)
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010011998 goto cleanup;
Bram Moolenaar162b7142018-12-21 15:17:36 +010011999 }
12000 if (dict_find(dict, (char_u *)"id", -1) != NULL)
12001 sign_id = dict_get_number(dict, (char_u *)"id");
12002 }
12003
12004 if (buf == NULL)
12005 {
12006 // Delete the sign in all the buffers
12007 FOR_ALL_BUFFERS(buf)
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012008 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012009 rettv->vval.v_number = 0;
12010 }
12011 else
12012 {
Bram Moolenaar7d83bf42018-12-29 18:53:55 +010012013 if (sign_unplace(sign_id, group, buf, 0) == OK)
Bram Moolenaar162b7142018-12-21 15:17:36 +010012014 rettv->vval.v_number = 0;
12015 }
Bram Moolenaar1ea88a32018-12-29 21:00:27 +010012016
12017cleanup:
Bram Moolenaar162b7142018-12-21 15:17:36 +010012018 vim_free(group);
12019}
12020#endif
12021
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012022/*
12023 * "simplify()" function
12024 */
12025 static void
12026f_simplify(typval_T *argvars, typval_T *rettv)
12027{
12028 char_u *p;
12029
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012030 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012031 rettv->vval.v_string = vim_strsave(p);
12032 simplify_filename(rettv->vval.v_string); /* simplify in place */
12033 rettv->v_type = VAR_STRING;
12034}
12035
12036#ifdef FEAT_FLOAT
12037/*
12038 * "sin()" function
12039 */
12040 static void
12041f_sin(typval_T *argvars, typval_T *rettv)
12042{
12043 float_T f = 0.0;
12044
12045 rettv->v_type = VAR_FLOAT;
12046 if (get_float_arg(argvars, &f) == OK)
12047 rettv->vval.v_float = sin(f);
12048 else
12049 rettv->vval.v_float = 0.0;
12050}
12051
12052/*
12053 * "sinh()" function
12054 */
12055 static void
12056f_sinh(typval_T *argvars, typval_T *rettv)
12057{
12058 float_T f = 0.0;
12059
12060 rettv->v_type = VAR_FLOAT;
12061 if (get_float_arg(argvars, &f) == OK)
12062 rettv->vval.v_float = sinh(f);
12063 else
12064 rettv->vval.v_float = 0.0;
12065}
12066#endif
12067
12068static int
12069#ifdef __BORLANDC__
12070 _RTLENTRYF
12071#endif
12072 item_compare(const void *s1, const void *s2);
12073static int
12074#ifdef __BORLANDC__
12075 _RTLENTRYF
12076#endif
12077 item_compare2(const void *s1, const void *s2);
12078
12079/* struct used in the array that's given to qsort() */
12080typedef struct
12081{
12082 listitem_T *item;
12083 int idx;
12084} sortItem_T;
12085
12086/* struct storing information about current sort */
12087typedef struct
12088{
12089 int item_compare_ic;
12090 int item_compare_numeric;
12091 int item_compare_numbers;
12092#ifdef FEAT_FLOAT
12093 int item_compare_float;
12094#endif
12095 char_u *item_compare_func;
12096 partial_T *item_compare_partial;
12097 dict_T *item_compare_selfdict;
12098 int item_compare_func_err;
12099 int item_compare_keep_zero;
12100} sortinfo_T;
12101static sortinfo_T *sortinfo = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012102#define ITEM_COMPARE_FAIL 999
12103
12104/*
12105 * Compare functions for f_sort() and f_uniq() below.
12106 */
12107 static int
12108#ifdef __BORLANDC__
12109_RTLENTRYF
12110#endif
12111item_compare(const void *s1, const void *s2)
12112{
12113 sortItem_T *si1, *si2;
12114 typval_T *tv1, *tv2;
12115 char_u *p1, *p2;
12116 char_u *tofree1 = NULL, *tofree2 = NULL;
12117 int res;
12118 char_u numbuf1[NUMBUFLEN];
12119 char_u numbuf2[NUMBUFLEN];
12120
12121 si1 = (sortItem_T *)s1;
12122 si2 = (sortItem_T *)s2;
12123 tv1 = &si1->item->li_tv;
12124 tv2 = &si2->item->li_tv;
12125
12126 if (sortinfo->item_compare_numbers)
12127 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012128 varnumber_T v1 = tv_get_number(tv1);
12129 varnumber_T v2 = tv_get_number(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012130
12131 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12132 }
12133
12134#ifdef FEAT_FLOAT
12135 if (sortinfo->item_compare_float)
12136 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012137 float_T v1 = tv_get_float(tv1);
12138 float_T v2 = tv_get_float(tv2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012139
12140 return v1 == v2 ? 0 : v1 > v2 ? 1 : -1;
12141 }
12142#endif
12143
12144 /* tv2string() puts quotes around a string and allocates memory. Don't do
12145 * that for string variables. Use a single quote when comparing with a
12146 * non-string to do what the docs promise. */
12147 if (tv1->v_type == VAR_STRING)
12148 {
12149 if (tv2->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12150 p1 = (char_u *)"'";
12151 else
12152 p1 = tv1->vval.v_string;
12153 }
12154 else
12155 p1 = tv2string(tv1, &tofree1, numbuf1, 0);
12156 if (tv2->v_type == VAR_STRING)
12157 {
12158 if (tv1->v_type != VAR_STRING || sortinfo->item_compare_numeric)
12159 p2 = (char_u *)"'";
12160 else
12161 p2 = tv2->vval.v_string;
12162 }
12163 else
12164 p2 = tv2string(tv2, &tofree2, numbuf2, 0);
12165 if (p1 == NULL)
12166 p1 = (char_u *)"";
12167 if (p2 == NULL)
12168 p2 = (char_u *)"";
12169 if (!sortinfo->item_compare_numeric)
12170 {
12171 if (sortinfo->item_compare_ic)
12172 res = STRICMP(p1, p2);
12173 else
12174 res = STRCMP(p1, p2);
12175 }
12176 else
12177 {
12178 double n1, n2;
12179 n1 = strtod((char *)p1, (char **)&p1);
12180 n2 = strtod((char *)p2, (char **)&p2);
12181 res = n1 == n2 ? 0 : n1 > n2 ? 1 : -1;
12182 }
12183
12184 /* When the result would be zero, compare the item indexes. Makes the
12185 * sort stable. */
12186 if (res == 0 && !sortinfo->item_compare_keep_zero)
12187 res = si1->idx > si2->idx ? 1 : -1;
12188
12189 vim_free(tofree1);
12190 vim_free(tofree2);
12191 return res;
12192}
12193
12194 static int
12195#ifdef __BORLANDC__
12196_RTLENTRYF
12197#endif
12198item_compare2(const void *s1, const void *s2)
12199{
12200 sortItem_T *si1, *si2;
12201 int res;
12202 typval_T rettv;
12203 typval_T argv[3];
12204 int dummy;
12205 char_u *func_name;
12206 partial_T *partial = sortinfo->item_compare_partial;
12207
12208 /* shortcut after failure in previous call; compare all items equal */
12209 if (sortinfo->item_compare_func_err)
12210 return 0;
12211
12212 si1 = (sortItem_T *)s1;
12213 si2 = (sortItem_T *)s2;
12214
12215 if (partial == NULL)
12216 func_name = sortinfo->item_compare_func;
12217 else
Bram Moolenaar437bafe2016-08-01 15:40:54 +020012218 func_name = partial_name(partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012219
12220 /* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
12221 * in the copy without changing the original list items. */
12222 copy_tv(&si1->item->li_tv, &argv[0]);
12223 copy_tv(&si2->item->li_tv, &argv[1]);
12224
12225 rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
12226 res = call_func(func_name, (int)STRLEN(func_name),
Bram Moolenaardf48fb42016-07-22 21:50:18 +020012227 &rettv, 2, argv, NULL, 0L, 0L, &dummy, TRUE,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012228 partial, sortinfo->item_compare_selfdict);
12229 clear_tv(&argv[0]);
12230 clear_tv(&argv[1]);
12231
12232 if (res == FAIL)
12233 res = ITEM_COMPARE_FAIL;
12234 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012235 res = (int)tv_get_number_chk(&rettv, &sortinfo->item_compare_func_err);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012236 if (sortinfo->item_compare_func_err)
12237 res = ITEM_COMPARE_FAIL; /* return value has wrong type */
12238 clear_tv(&rettv);
12239
12240 /* When the result would be zero, compare the pointers themselves. Makes
12241 * the sort stable. */
12242 if (res == 0 && !sortinfo->item_compare_keep_zero)
12243 res = si1->idx > si2->idx ? 1 : -1;
12244
12245 return res;
12246}
12247
12248/*
12249 * "sort({list})" function
12250 */
12251 static void
12252do_sort_uniq(typval_T *argvars, typval_T *rettv, int sort)
12253{
12254 list_T *l;
12255 listitem_T *li;
12256 sortItem_T *ptrs;
12257 sortinfo_T *old_sortinfo;
12258 sortinfo_T info;
12259 long len;
12260 long i;
12261
12262 /* Pointer to current info struct used in compare function. Save and
12263 * restore the current one for nested calls. */
12264 old_sortinfo = sortinfo;
12265 sortinfo = &info;
12266
12267 if (argvars[0].v_type != VAR_LIST)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012268 semsg(_(e_listarg), sort ? "sort()" : "uniq()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012269 else
12270 {
12271 l = argvars[0].vval.v_list;
Bram Moolenaar05c00c02019-02-11 22:00:11 +010012272 if (l == NULL || var_check_lock(l->lv_lock,
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012273 (char_u *)(sort ? N_("sort() argument") : N_("uniq() argument")),
12274 TRUE))
12275 goto theend;
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020012276 rettv_list_set(rettv, l);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012277
12278 len = list_len(l);
12279 if (len <= 1)
12280 goto theend; /* short list sorts pretty quickly */
12281
12282 info.item_compare_ic = FALSE;
12283 info.item_compare_numeric = FALSE;
12284 info.item_compare_numbers = FALSE;
12285#ifdef FEAT_FLOAT
12286 info.item_compare_float = FALSE;
12287#endif
12288 info.item_compare_func = NULL;
12289 info.item_compare_partial = NULL;
12290 info.item_compare_selfdict = NULL;
12291 if (argvars[1].v_type != VAR_UNKNOWN)
12292 {
12293 /* optional second argument: {func} */
12294 if (argvars[1].v_type == VAR_FUNC)
12295 info.item_compare_func = argvars[1].vval.v_string;
12296 else if (argvars[1].v_type == VAR_PARTIAL)
12297 info.item_compare_partial = argvars[1].vval.v_partial;
12298 else
12299 {
12300 int error = FALSE;
12301
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012302 i = (long)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012303 if (error)
12304 goto theend; /* type error; errmsg already given */
12305 if (i == 1)
12306 info.item_compare_ic = TRUE;
12307 else if (argvars[1].v_type != VAR_NUMBER)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012308 info.item_compare_func = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012309 else if (i != 0)
12310 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012311 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012312 goto theend;
12313 }
12314 if (info.item_compare_func != NULL)
12315 {
12316 if (*info.item_compare_func == NUL)
12317 {
12318 /* empty string means default sort */
12319 info.item_compare_func = NULL;
12320 }
12321 else if (STRCMP(info.item_compare_func, "n") == 0)
12322 {
12323 info.item_compare_func = NULL;
12324 info.item_compare_numeric = TRUE;
12325 }
12326 else if (STRCMP(info.item_compare_func, "N") == 0)
12327 {
12328 info.item_compare_func = NULL;
12329 info.item_compare_numbers = TRUE;
12330 }
12331#ifdef FEAT_FLOAT
12332 else if (STRCMP(info.item_compare_func, "f") == 0)
12333 {
12334 info.item_compare_func = NULL;
12335 info.item_compare_float = TRUE;
12336 }
12337#endif
12338 else if (STRCMP(info.item_compare_func, "i") == 0)
12339 {
12340 info.item_compare_func = NULL;
12341 info.item_compare_ic = TRUE;
12342 }
12343 }
12344 }
12345
12346 if (argvars[2].v_type != VAR_UNKNOWN)
12347 {
12348 /* optional third argument: {dict} */
12349 if (argvars[2].v_type != VAR_DICT)
12350 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012351 emsg(_(e_dictreq));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012352 goto theend;
12353 }
12354 info.item_compare_selfdict = argvars[2].vval.v_dict;
12355 }
12356 }
12357
12358 /* Make an array with each entry pointing to an item in the List. */
12359 ptrs = (sortItem_T *)alloc((int)(len * sizeof(sortItem_T)));
12360 if (ptrs == NULL)
12361 goto theend;
12362
12363 i = 0;
12364 if (sort)
12365 {
12366 /* sort(): ptrs will be the list to sort */
12367 for (li = l->lv_first; li != NULL; li = li->li_next)
12368 {
12369 ptrs[i].item = li;
12370 ptrs[i].idx = i;
12371 ++i;
12372 }
12373
12374 info.item_compare_func_err = FALSE;
12375 info.item_compare_keep_zero = FALSE;
12376 /* test the compare function */
12377 if ((info.item_compare_func != NULL
12378 || info.item_compare_partial != NULL)
12379 && item_compare2((void *)&ptrs[0], (void *)&ptrs[1])
12380 == ITEM_COMPARE_FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012381 emsg(_("E702: Sort compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012382 else
12383 {
12384 /* Sort the array with item pointers. */
12385 qsort((void *)ptrs, (size_t)len, sizeof(sortItem_T),
12386 info.item_compare_func == NULL
12387 && info.item_compare_partial == NULL
12388 ? item_compare : item_compare2);
12389
12390 if (!info.item_compare_func_err)
12391 {
12392 /* Clear the List and append the items in sorted order. */
12393 l->lv_first = l->lv_last = l->lv_idx_item = NULL;
12394 l->lv_len = 0;
12395 for (i = 0; i < len; ++i)
12396 list_append(l, ptrs[i].item);
12397 }
12398 }
12399 }
12400 else
12401 {
12402 int (*item_compare_func_ptr)(const void *, const void *);
12403
12404 /* f_uniq(): ptrs will be a stack of items to remove */
12405 info.item_compare_func_err = FALSE;
12406 info.item_compare_keep_zero = TRUE;
12407 item_compare_func_ptr = info.item_compare_func != NULL
12408 || info.item_compare_partial != NULL
12409 ? item_compare2 : item_compare;
12410
12411 for (li = l->lv_first; li != NULL && li->li_next != NULL;
12412 li = li->li_next)
12413 {
12414 if (item_compare_func_ptr((void *)&li, (void *)&li->li_next)
12415 == 0)
12416 ptrs[i++].item = li;
12417 if (info.item_compare_func_err)
12418 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012419 emsg(_("E882: Uniq compare function failed"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012420 break;
12421 }
12422 }
12423
12424 if (!info.item_compare_func_err)
12425 {
12426 while (--i >= 0)
12427 {
12428 li = ptrs[i].item->li_next;
12429 ptrs[i].item->li_next = li->li_next;
12430 if (li->li_next != NULL)
12431 li->li_next->li_prev = ptrs[i].item;
12432 else
12433 l->lv_last = ptrs[i].item;
12434 list_fix_watch(l, li);
12435 listitem_free(li);
12436 l->lv_len--;
12437 }
12438 }
12439 }
12440
12441 vim_free(ptrs);
12442 }
12443theend:
12444 sortinfo = old_sortinfo;
12445}
12446
12447/*
12448 * "sort({list})" function
12449 */
12450 static void
12451f_sort(typval_T *argvars, typval_T *rettv)
12452{
12453 do_sort_uniq(argvars, rettv, TRUE);
12454}
12455
12456/*
12457 * "uniq({list})" function
12458 */
12459 static void
12460f_uniq(typval_T *argvars, typval_T *rettv)
12461{
12462 do_sort_uniq(argvars, rettv, FALSE);
12463}
12464
12465/*
12466 * "soundfold({word})" function
12467 */
12468 static void
12469f_soundfold(typval_T *argvars, typval_T *rettv)
12470{
12471 char_u *s;
12472
12473 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012474 s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012475#ifdef FEAT_SPELL
12476 rettv->vval.v_string = eval_soundfold(s);
12477#else
12478 rettv->vval.v_string = vim_strsave(s);
12479#endif
12480}
12481
12482/*
12483 * "spellbadword()" function
12484 */
12485 static void
12486f_spellbadword(typval_T *argvars UNUSED, typval_T *rettv)
12487{
12488 char_u *word = (char_u *)"";
12489 hlf_T attr = HLF_COUNT;
12490 int len = 0;
12491
12492 if (rettv_list_alloc(rettv) == FAIL)
12493 return;
12494
12495#ifdef FEAT_SPELL
12496 if (argvars[0].v_type == VAR_UNKNOWN)
12497 {
12498 /* Find the start and length of the badly spelled word. */
12499 len = spell_move_to(curwin, FORWARD, TRUE, TRUE, &attr);
12500 if (len != 0)
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012501 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012502 word = ml_get_cursor();
Bram Moolenaarb73fa622017-12-21 20:27:47 +010012503 curwin->w_set_curswant = TRUE;
12504 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012505 }
12506 else if (curwin->w_p_spell && *curbuf->b_s.b_p_spl != NUL)
12507 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012508 char_u *str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012509 int capcol = -1;
12510
12511 if (str != NULL)
12512 {
12513 /* Check the argument for spelling. */
12514 while (*str != NUL)
12515 {
12516 len = spell_check(curwin, str, &attr, &capcol, FALSE);
12517 if (attr != HLF_COUNT)
12518 {
12519 word = str;
12520 break;
12521 }
12522 str += len;
Bram Moolenaar66ab9162018-07-20 20:28:48 +020012523 capcol -= len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012524 }
12525 }
12526 }
12527#endif
12528
12529 list_append_string(rettv->vval.v_list, word, len);
12530 list_append_string(rettv->vval.v_list, (char_u *)(
12531 attr == HLF_SPB ? "bad" :
12532 attr == HLF_SPR ? "rare" :
12533 attr == HLF_SPL ? "local" :
12534 attr == HLF_SPC ? "caps" :
12535 ""), -1);
12536}
12537
12538/*
12539 * "spellsuggest()" function
12540 */
12541 static void
12542f_spellsuggest(typval_T *argvars UNUSED, typval_T *rettv)
12543{
12544#ifdef FEAT_SPELL
12545 char_u *str;
12546 int typeerr = FALSE;
12547 int maxcount;
12548 garray_T ga;
12549 int i;
12550 listitem_T *li;
12551 int need_capital = FALSE;
12552#endif
12553
12554 if (rettv_list_alloc(rettv) == FAIL)
12555 return;
12556
12557#ifdef FEAT_SPELL
12558 if (curwin->w_p_spell && *curwin->w_s->b_p_spl != NUL)
12559 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012560 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012561 if (argvars[1].v_type != VAR_UNKNOWN)
12562 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012563 maxcount = (int)tv_get_number_chk(&argvars[1], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012564 if (maxcount <= 0)
12565 return;
12566 if (argvars[2].v_type != VAR_UNKNOWN)
12567 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012568 need_capital = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012569 if (typeerr)
12570 return;
12571 }
12572 }
12573 else
12574 maxcount = 25;
12575
12576 spell_suggest_list(&ga, str, maxcount, need_capital, FALSE);
12577
12578 for (i = 0; i < ga.ga_len; ++i)
12579 {
12580 str = ((char_u **)ga.ga_data)[i];
12581
12582 li = listitem_alloc();
12583 if (li == NULL)
12584 vim_free(str);
12585 else
12586 {
12587 li->li_tv.v_type = VAR_STRING;
12588 li->li_tv.v_lock = 0;
12589 li->li_tv.vval.v_string = str;
12590 list_append(rettv->vval.v_list, li);
12591 }
12592 }
12593 ga_clear(&ga);
12594 }
12595#endif
12596}
12597
12598 static void
12599f_split(typval_T *argvars, typval_T *rettv)
12600{
12601 char_u *str;
12602 char_u *end;
12603 char_u *pat = NULL;
12604 regmatch_T regmatch;
12605 char_u patbuf[NUMBUFLEN];
12606 char_u *save_cpo;
12607 int match;
12608 colnr_T col = 0;
12609 int keepempty = FALSE;
12610 int typeerr = FALSE;
12611
12612 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
12613 save_cpo = p_cpo;
12614 p_cpo = (char_u *)"";
12615
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012616 str = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012617 if (argvars[1].v_type != VAR_UNKNOWN)
12618 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012619 pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012620 if (pat == NULL)
12621 typeerr = TRUE;
12622 if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012623 keepempty = (int)tv_get_number_chk(&argvars[2], &typeerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012624 }
12625 if (pat == NULL || *pat == NUL)
12626 pat = (char_u *)"[\\x01- ]\\+";
12627
12628 if (rettv_list_alloc(rettv) == FAIL)
12629 return;
12630 if (typeerr)
12631 return;
12632
12633 regmatch.regprog = vim_regcomp(pat, RE_MAGIC + RE_STRING);
12634 if (regmatch.regprog != NULL)
12635 {
12636 regmatch.rm_ic = FALSE;
12637 while (*str != NUL || keepempty)
12638 {
12639 if (*str == NUL)
12640 match = FALSE; /* empty item at the end */
12641 else
12642 match = vim_regexec_nl(&regmatch, str, col);
12643 if (match)
12644 end = regmatch.startp[0];
12645 else
12646 end = str + STRLEN(str);
12647 if (keepempty || end > str || (rettv->vval.v_list->lv_len > 0
12648 && *str != NUL && match && end < regmatch.endp[0]))
12649 {
12650 if (list_append_string(rettv->vval.v_list, str,
12651 (int)(end - str)) == FAIL)
12652 break;
12653 }
12654 if (!match)
12655 break;
Bram Moolenaar13505972019-01-24 15:04:48 +010012656 // Advance to just after the match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012657 if (regmatch.endp[0] > str)
12658 col = 0;
12659 else
Bram Moolenaar13505972019-01-24 15:04:48 +010012660 // Don't get stuck at the same match.
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012661 col = (*mb_ptr2len)(regmatch.endp[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012662 str = regmatch.endp[0];
12663 }
12664
12665 vim_regfree(regmatch.regprog);
12666 }
12667
12668 p_cpo = save_cpo;
12669}
12670
12671#ifdef FEAT_FLOAT
12672/*
12673 * "sqrt()" function
12674 */
12675 static void
12676f_sqrt(typval_T *argvars, typval_T *rettv)
12677{
12678 float_T f = 0.0;
12679
12680 rettv->v_type = VAR_FLOAT;
12681 if (get_float_arg(argvars, &f) == OK)
12682 rettv->vval.v_float = sqrt(f);
12683 else
12684 rettv->vval.v_float = 0.0;
12685}
12686
12687/*
12688 * "str2float()" function
12689 */
12690 static void
12691f_str2float(typval_T *argvars, typval_T *rettv)
12692{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012693 char_u *p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012694 int isneg = (*p == '-');
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012695
Bram Moolenaar08243d22017-01-10 16:12:29 +010012696 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012697 p = skipwhite(p + 1);
12698 (void)string2float(p, &rettv->vval.v_float);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012699 if (isneg)
12700 rettv->vval.v_float *= -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012701 rettv->v_type = VAR_FLOAT;
12702}
12703#endif
12704
12705/*
12706 * "str2nr()" function
12707 */
12708 static void
12709f_str2nr(typval_T *argvars, typval_T *rettv)
12710{
12711 int base = 10;
12712 char_u *p;
12713 varnumber_T n;
12714 int what;
Bram Moolenaar08243d22017-01-10 16:12:29 +010012715 int isneg;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012716
12717 if (argvars[1].v_type != VAR_UNKNOWN)
12718 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012719 base = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012720 if (base != 2 && base != 8 && base != 10 && base != 16)
12721 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012722 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012723 return;
12724 }
12725 }
12726
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012727 p = skipwhite(tv_get_string(&argvars[0]));
Bram Moolenaar08243d22017-01-10 16:12:29 +010012728 isneg = (*p == '-');
12729 if (*p == '+' || *p == '-')
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012730 p = skipwhite(p + 1);
12731 switch (base)
12732 {
12733 case 2: what = STR2NR_BIN + STR2NR_FORCE; break;
12734 case 8: what = STR2NR_OCT + STR2NR_FORCE; break;
12735 case 16: what = STR2NR_HEX + STR2NR_FORCE; break;
12736 default: what = 0;
12737 }
12738 vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
Bram Moolenaar08243d22017-01-10 16:12:29 +010012739 if (isneg)
12740 rettv->vval.v_number = -n;
12741 else
12742 rettv->vval.v_number = n;
12743
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012744}
12745
12746#ifdef HAVE_STRFTIME
12747/*
12748 * "strftime({format}[, {time}])" function
12749 */
12750 static void
12751f_strftime(typval_T *argvars, typval_T *rettv)
12752{
12753 char_u result_buf[256];
12754 struct tm *curtime;
12755 time_t seconds;
12756 char_u *p;
12757
12758 rettv->v_type = VAR_STRING;
12759
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012760 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012761 if (argvars[1].v_type == VAR_UNKNOWN)
12762 seconds = time(NULL);
12763 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012764 seconds = (time_t)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012765 curtime = localtime(&seconds);
12766 /* MSVC returns NULL for an invalid value of seconds. */
12767 if (curtime == NULL)
12768 rettv->vval.v_string = vim_strsave((char_u *)_("(Invalid)"));
12769 else
12770 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012771 vimconv_T conv;
12772 char_u *enc;
12773
12774 conv.vc_type = CONV_NONE;
12775 enc = enc_locale();
12776 convert_setup(&conv, p_enc, enc);
12777 if (conv.vc_type != CONV_NONE)
12778 p = string_convert(&conv, p, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012779 if (p != NULL)
12780 (void)strftime((char *)result_buf, sizeof(result_buf),
12781 (char *)p, curtime);
12782 else
12783 result_buf[0] = NUL;
12784
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012785 if (conv.vc_type != CONV_NONE)
12786 vim_free(p);
12787 convert_setup(&conv, enc, p_enc);
12788 if (conv.vc_type != CONV_NONE)
12789 rettv->vval.v_string = string_convert(&conv, result_buf, NULL);
12790 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012791 rettv->vval.v_string = vim_strsave(result_buf);
12792
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012793 /* Release conversion descriptors */
12794 convert_setup(&conv, NULL, NULL);
12795 vim_free(enc);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012796 }
12797}
12798#endif
12799
12800/*
12801 * "strgetchar()" function
12802 */
12803 static void
12804f_strgetchar(typval_T *argvars, typval_T *rettv)
12805{
12806 char_u *str;
12807 int len;
12808 int error = FALSE;
12809 int charidx;
Bram Moolenaar13505972019-01-24 15:04:48 +010012810 int byteidx = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012811
12812 rettv->vval.v_number = -1;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012813 str = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012814 if (str == NULL)
12815 return;
12816 len = (int)STRLEN(str);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012817 charidx = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012818 if (error)
12819 return;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012820
Bram Moolenaar13505972019-01-24 15:04:48 +010012821 while (charidx >= 0 && byteidx < len)
12822 {
12823 if (charidx == 0)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012824 {
Bram Moolenaar13505972019-01-24 15:04:48 +010012825 rettv->vval.v_number = mb_ptr2char(str + byteidx);
12826 break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012827 }
Bram Moolenaar13505972019-01-24 15:04:48 +010012828 --charidx;
12829 byteidx += MB_CPTR2LEN(str + byteidx);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012830 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012831}
12832
12833/*
12834 * "stridx()" function
12835 */
12836 static void
12837f_stridx(typval_T *argvars, typval_T *rettv)
12838{
12839 char_u buf[NUMBUFLEN];
12840 char_u *needle;
12841 char_u *haystack;
12842 char_u *save_haystack;
12843 char_u *pos;
12844 int start_idx;
12845
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012846 needle = tv_get_string_chk(&argvars[1]);
12847 save_haystack = haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012848 rettv->vval.v_number = -1;
12849 if (needle == NULL || haystack == NULL)
12850 return; /* type error; errmsg already given */
12851
12852 if (argvars[2].v_type != VAR_UNKNOWN)
12853 {
12854 int error = FALSE;
12855
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012856 start_idx = (int)tv_get_number_chk(&argvars[2], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012857 if (error || start_idx >= (int)STRLEN(haystack))
12858 return;
12859 if (start_idx >= 0)
12860 haystack += start_idx;
12861 }
12862
12863 pos = (char_u *)strstr((char *)haystack, (char *)needle);
12864 if (pos != NULL)
12865 rettv->vval.v_number = (varnumber_T)(pos - save_haystack);
12866}
12867
12868/*
12869 * "string()" function
12870 */
Bram Moolenaar461a7fc2018-12-22 13:28:07 +010012871 void
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012872f_string(typval_T *argvars, typval_T *rettv)
12873{
12874 char_u *tofree;
12875 char_u numbuf[NUMBUFLEN];
12876
12877 rettv->v_type = VAR_STRING;
12878 rettv->vval.v_string = tv2string(&argvars[0], &tofree, numbuf,
12879 get_copyID());
12880 /* Make a copy if we have a value but it's not in allocated memory. */
12881 if (rettv->vval.v_string != NULL && tofree == NULL)
12882 rettv->vval.v_string = vim_strsave(rettv->vval.v_string);
12883}
12884
12885/*
12886 * "strlen()" function
12887 */
12888 static void
12889f_strlen(typval_T *argvars, typval_T *rettv)
12890{
12891 rettv->vval.v_number = (varnumber_T)(STRLEN(
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012892 tv_get_string(&argvars[0])));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012893}
12894
12895/*
12896 * "strchars()" function
12897 */
12898 static void
12899f_strchars(typval_T *argvars, typval_T *rettv)
12900{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012901 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012902 int skipcc = 0;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012903 varnumber_T len = 0;
12904 int (*func_mb_ptr2char_adv)(char_u **pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012905
12906 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012907 skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012908 if (skipcc < 0 || skipcc > 1)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010012909 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012910 else
12911 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012912 func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
12913 while (*s != NUL)
12914 {
12915 func_mb_ptr2char_adv(&s);
12916 ++len;
12917 }
12918 rettv->vval.v_number = len;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012919 }
12920}
12921
12922/*
12923 * "strdisplaywidth()" function
12924 */
12925 static void
12926f_strdisplaywidth(typval_T *argvars, typval_T *rettv)
12927{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012928 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012929 int col = 0;
12930
12931 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012932 col = (int)tv_get_number(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012933
12934 rettv->vval.v_number = (varnumber_T)(linetabsize_col(col, s) - col);
12935}
12936
12937/*
12938 * "strwidth()" function
12939 */
12940 static void
12941f_strwidth(typval_T *argvars, typval_T *rettv)
12942{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012943 char_u *s = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012944
Bram Moolenaar13505972019-01-24 15:04:48 +010012945 rettv->vval.v_number = (varnumber_T)(mb_string2cells(s, -1));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012946}
12947
12948/*
12949 * "strcharpart()" function
12950 */
12951 static void
12952f_strcharpart(typval_T *argvars, typval_T *rettv)
12953{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012954 char_u *p;
12955 int nchar;
12956 int nbyte = 0;
12957 int charlen;
12958 int len = 0;
12959 int slen;
12960 int error = FALSE;
12961
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012962 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012963 slen = (int)STRLEN(p);
12964
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012965 nchar = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012966 if (!error)
12967 {
12968 if (nchar > 0)
12969 while (nchar > 0 && nbyte < slen)
12970 {
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012971 nbyte += MB_CPTR2LEN(p + nbyte);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012972 --nchar;
12973 }
12974 else
12975 nbyte = nchar;
12976 if (argvars[2].v_type != VAR_UNKNOWN)
12977 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010012978 charlen = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012979 while (charlen > 0 && nbyte + len < slen)
12980 {
12981 int off = nbyte + len;
12982
12983 if (off < 0)
12984 len += 1;
12985 else
Bram Moolenaard3c907b2016-08-17 21:32:09 +020012986 len += MB_CPTR2LEN(p + off);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020012987 --charlen;
12988 }
12989 }
12990 else
12991 len = slen - nbyte; /* default: all bytes that are available. */
12992 }
12993
12994 /*
12995 * Only return the overlap between the specified part and the actual
12996 * string.
12997 */
12998 if (nbyte < 0)
12999 {
13000 len += nbyte;
13001 nbyte = 0;
13002 }
13003 else if (nbyte > slen)
13004 nbyte = slen;
13005 if (len < 0)
13006 len = 0;
13007 else if (nbyte + len > slen)
13008 len = slen - nbyte;
13009
13010 rettv->v_type = VAR_STRING;
13011 rettv->vval.v_string = vim_strnsave(p + nbyte, len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013012}
13013
13014/*
13015 * "strpart()" function
13016 */
13017 static void
13018f_strpart(typval_T *argvars, typval_T *rettv)
13019{
13020 char_u *p;
13021 int n;
13022 int len;
13023 int slen;
13024 int error = FALSE;
13025
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013026 p = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013027 slen = (int)STRLEN(p);
13028
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013029 n = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013030 if (error)
13031 len = 0;
13032 else if (argvars[2].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013033 len = (int)tv_get_number(&argvars[2]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013034 else
13035 len = slen - n; /* default len: all bytes that are available. */
13036
13037 /*
13038 * Only return the overlap between the specified part and the actual
13039 * string.
13040 */
13041 if (n < 0)
13042 {
13043 len += n;
13044 n = 0;
13045 }
13046 else if (n > slen)
13047 n = slen;
13048 if (len < 0)
13049 len = 0;
13050 else if (n + len > slen)
13051 len = slen - n;
13052
13053 rettv->v_type = VAR_STRING;
13054 rettv->vval.v_string = vim_strnsave(p + n, len);
13055}
13056
13057/*
13058 * "strridx()" function
13059 */
13060 static void
13061f_strridx(typval_T *argvars, typval_T *rettv)
13062{
13063 char_u buf[NUMBUFLEN];
13064 char_u *needle;
13065 char_u *haystack;
13066 char_u *rest;
13067 char_u *lastmatch = NULL;
13068 int haystack_len, end_idx;
13069
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013070 needle = tv_get_string_chk(&argvars[1]);
13071 haystack = tv_get_string_buf_chk(&argvars[0], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013072
13073 rettv->vval.v_number = -1;
13074 if (needle == NULL || haystack == NULL)
13075 return; /* type error; errmsg already given */
13076
13077 haystack_len = (int)STRLEN(haystack);
13078 if (argvars[2].v_type != VAR_UNKNOWN)
13079 {
13080 /* Third argument: upper limit for index */
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013081 end_idx = (int)tv_get_number_chk(&argvars[2], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013082 if (end_idx < 0)
13083 return; /* can never find a match */
13084 }
13085 else
13086 end_idx = haystack_len;
13087
13088 if (*needle == NUL)
13089 {
13090 /* Empty string matches past the end. */
13091 lastmatch = haystack + end_idx;
13092 }
13093 else
13094 {
13095 for (rest = haystack; *rest != '\0'; ++rest)
13096 {
13097 rest = (char_u *)strstr((char *)rest, (char *)needle);
13098 if (rest == NULL || rest > haystack + end_idx)
13099 break;
13100 lastmatch = rest;
13101 }
13102 }
13103
13104 if (lastmatch == NULL)
13105 rettv->vval.v_number = -1;
13106 else
13107 rettv->vval.v_number = (varnumber_T)(lastmatch - haystack);
13108}
13109
13110/*
13111 * "strtrans()" function
13112 */
13113 static void
13114f_strtrans(typval_T *argvars, typval_T *rettv)
13115{
13116 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013117 rettv->vval.v_string = transstr(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013118}
13119
13120/*
13121 * "submatch()" function
13122 */
13123 static void
13124f_submatch(typval_T *argvars, typval_T *rettv)
13125{
13126 int error = FALSE;
13127 int no;
13128 int retList = 0;
13129
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013130 no = (int)tv_get_number_chk(&argvars[0], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013131 if (error)
13132 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013133 if (no < 0 || no >= NSUBEXP)
13134 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013135 semsg(_("E935: invalid submatch number: %d"), no);
Bram Moolenaar79518e22017-02-17 16:31:35 +010013136 return;
Bram Moolenaar989f5922016-08-21 15:26:54 +020013137 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013138 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013139 retList = (int)tv_get_number_chk(&argvars[1], &error);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013140 if (error)
13141 return;
13142
13143 if (retList == 0)
13144 {
13145 rettv->v_type = VAR_STRING;
13146 rettv->vval.v_string = reg_submatch(no);
13147 }
13148 else
13149 {
13150 rettv->v_type = VAR_LIST;
13151 rettv->vval.v_list = reg_submatch_list(no);
13152 }
13153}
13154
13155/*
13156 * "substitute()" function
13157 */
13158 static void
13159f_substitute(typval_T *argvars, typval_T *rettv)
13160{
13161 char_u patbuf[NUMBUFLEN];
13162 char_u subbuf[NUMBUFLEN];
13163 char_u flagsbuf[NUMBUFLEN];
13164
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013165 char_u *str = tv_get_string_chk(&argvars[0]);
13166 char_u *pat = tv_get_string_buf_chk(&argvars[1], patbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013167 char_u *sub = NULL;
13168 typval_T *expr = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013169 char_u *flg = tv_get_string_buf_chk(&argvars[3], flagsbuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013170
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013171 if (argvars[2].v_type == VAR_FUNC || argvars[2].v_type == VAR_PARTIAL)
13172 expr = &argvars[2];
13173 else
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013174 sub = tv_get_string_buf_chk(&argvars[2], subbuf);
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013175
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013176 rettv->v_type = VAR_STRING;
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013177 if (str == NULL || pat == NULL || (sub == NULL && expr == NULL)
13178 || flg == NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013179 rettv->vval.v_string = NULL;
13180 else
Bram Moolenaar72ab7292016-07-19 19:10:51 +020013181 rettv->vval.v_string = do_string_sub(str, pat, sub, expr, flg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013182}
13183
13184/*
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013185 * "swapinfo(swap_filename)" function
13186 */
13187 static void
13188f_swapinfo(typval_T *argvars, typval_T *rettv)
13189{
13190 if (rettv_dict_alloc(rettv) == OK)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013191 get_b0_dict(tv_get_string(argvars), rettv->vval.v_dict);
Bram Moolenaar00f123a2018-08-21 20:28:54 +020013192}
13193
13194/*
Bram Moolenaar110bd602018-09-16 18:46:59 +020013195 * "swapname(expr)" function
13196 */
13197 static void
13198f_swapname(typval_T *argvars, typval_T *rettv)
13199{
13200 buf_T *buf;
13201
13202 rettv->v_type = VAR_STRING;
Bram Moolenaarf2d79fa2019-01-03 22:19:27 +010013203 buf = tv_get_buf(&argvars[0], FALSE);
Bram Moolenaar110bd602018-09-16 18:46:59 +020013204 if (buf == NULL || buf->b_ml.ml_mfp == NULL
13205 || buf->b_ml.ml_mfp->mf_fname == NULL)
13206 rettv->vval.v_string = NULL;
13207 else
13208 rettv->vval.v_string = vim_strsave(buf->b_ml.ml_mfp->mf_fname);
13209}
13210
13211/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013212 * "synID(lnum, col, trans)" function
13213 */
13214 static void
13215f_synID(typval_T *argvars UNUSED, typval_T *rettv)
13216{
13217 int id = 0;
13218#ifdef FEAT_SYN_HL
13219 linenr_T lnum;
13220 colnr_T col;
13221 int trans;
13222 int transerr = FALSE;
13223
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013224 lnum = tv_get_lnum(argvars); /* -1 on type error */
13225 col = (linenr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
13226 trans = (int)tv_get_number_chk(&argvars[2], &transerr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013227
13228 if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13229 && col >= 0 && col < (long)STRLEN(ml_get(lnum)))
13230 id = syn_get_id(curwin, lnum, (colnr_T)col, trans, NULL, FALSE);
13231#endif
13232
13233 rettv->vval.v_number = id;
13234}
13235
13236/*
13237 * "synIDattr(id, what [, mode])" function
13238 */
13239 static void
13240f_synIDattr(typval_T *argvars UNUSED, typval_T *rettv)
13241{
13242 char_u *p = NULL;
13243#ifdef FEAT_SYN_HL
13244 int id;
13245 char_u *what;
13246 char_u *mode;
13247 char_u modebuf[NUMBUFLEN];
13248 int modec;
13249
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013250 id = (int)tv_get_number(&argvars[0]);
13251 what = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013252 if (argvars[2].v_type != VAR_UNKNOWN)
13253 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013254 mode = tv_get_string_buf(&argvars[2], modebuf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013255 modec = TOLOWER_ASC(mode[0]);
13256 if (modec != 't' && modec != 'c' && modec != 'g')
13257 modec = 0; /* replace invalid with current */
13258 }
13259 else
13260 {
13261#if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
13262 if (USE_24BIT)
13263 modec = 'g';
13264 else
13265#endif
13266 if (t_colors > 1)
13267 modec = 'c';
13268 else
13269 modec = 't';
13270 }
13271
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013272 switch (TOLOWER_ASC(what[0]))
13273 {
13274 case 'b':
13275 if (TOLOWER_ASC(what[1]) == 'g') /* bg[#] */
13276 p = highlight_color(id, what, modec);
13277 else /* bold */
13278 p = highlight_has_attr(id, HL_BOLD, modec);
13279 break;
13280
13281 case 'f': /* fg[#] or font */
13282 p = highlight_color(id, what, modec);
13283 break;
13284
13285 case 'i':
13286 if (TOLOWER_ASC(what[1]) == 'n') /* inverse */
13287 p = highlight_has_attr(id, HL_INVERSE, modec);
13288 else /* italic */
13289 p = highlight_has_attr(id, HL_ITALIC, modec);
13290 break;
13291
13292 case 'n': /* name */
Bram Moolenaarc96272e2017-03-26 13:50:09 +020013293 p = get_highlight_name_ext(NULL, id - 1, FALSE);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013294 break;
13295
13296 case 'r': /* reverse */
13297 p = highlight_has_attr(id, HL_INVERSE, modec);
13298 break;
13299
13300 case 's':
13301 if (TOLOWER_ASC(what[1]) == 'p') /* sp[#] */
13302 p = highlight_color(id, what, modec);
Bram Moolenaarcf4b00c2017-09-02 18:33:56 +020013303 /* strikeout */
13304 else if (TOLOWER_ASC(what[1]) == 't' &&
13305 TOLOWER_ASC(what[2]) == 'r')
13306 p = highlight_has_attr(id, HL_STRIKETHROUGH, modec);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013307 else /* standout */
13308 p = highlight_has_attr(id, HL_STANDOUT, modec);
13309 break;
13310
13311 case 'u':
13312 if (STRLEN(what) <= 5 || TOLOWER_ASC(what[5]) != 'c')
13313 /* underline */
13314 p = highlight_has_attr(id, HL_UNDERLINE, modec);
13315 else
13316 /* undercurl */
13317 p = highlight_has_attr(id, HL_UNDERCURL, modec);
13318 break;
13319 }
13320
13321 if (p != NULL)
13322 p = vim_strsave(p);
13323#endif
13324 rettv->v_type = VAR_STRING;
13325 rettv->vval.v_string = p;
13326}
13327
13328/*
13329 * "synIDtrans(id)" function
13330 */
13331 static void
13332f_synIDtrans(typval_T *argvars UNUSED, typval_T *rettv)
13333{
13334 int id;
13335
13336#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013337 id = (int)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013338
13339 if (id > 0)
13340 id = syn_get_final_id(id);
13341 else
13342#endif
13343 id = 0;
13344
13345 rettv->vval.v_number = id;
13346}
13347
13348/*
13349 * "synconcealed(lnum, col)" function
13350 */
13351 static void
13352f_synconcealed(typval_T *argvars UNUSED, typval_T *rettv)
13353{
13354#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
13355 linenr_T lnum;
13356 colnr_T col;
13357 int syntax_flags = 0;
13358 int cchar;
13359 int matchid = 0;
13360 char_u str[NUMBUFLEN];
13361#endif
13362
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013363 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013364
13365#if defined(FEAT_SYN_HL) && defined(FEAT_CONCEAL)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013366 lnum = tv_get_lnum(argvars); /* -1 on type error */
13367 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013368
13369 vim_memset(str, NUL, sizeof(str));
13370
13371 if (rettv_list_alloc(rettv) != FAIL)
13372 {
13373 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13374 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13375 && curwin->w_p_cole > 0)
13376 {
13377 (void)syn_get_id(curwin, lnum, col, FALSE, NULL, FALSE);
13378 syntax_flags = get_syntax_info(&matchid);
13379
13380 /* get the conceal character */
13381 if ((syntax_flags & HL_CONCEAL) && curwin->w_p_cole < 3)
13382 {
13383 cchar = syn_get_sub_char();
Bram Moolenaar4d785892017-06-22 22:00:50 +020013384 if (cchar == NUL && curwin->w_p_cole == 1)
13385 cchar = (lcs_conceal == NUL) ? ' ' : lcs_conceal;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013386 if (cchar != NUL)
13387 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013388 if (has_mbyte)
13389 (*mb_char2bytes)(cchar, str);
13390 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013391 str[0] = cchar;
13392 }
13393 }
13394 }
13395
13396 list_append_number(rettv->vval.v_list,
13397 (syntax_flags & HL_CONCEAL) != 0);
13398 /* -1 to auto-determine strlen */
13399 list_append_string(rettv->vval.v_list, str, -1);
13400 list_append_number(rettv->vval.v_list, matchid);
13401 }
13402#endif
13403}
13404
13405/*
13406 * "synstack(lnum, col)" function
13407 */
13408 static void
13409f_synstack(typval_T *argvars UNUSED, typval_T *rettv)
13410{
13411#ifdef FEAT_SYN_HL
13412 linenr_T lnum;
13413 colnr_T col;
13414 int i;
13415 int id;
13416#endif
13417
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013418 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013419
13420#ifdef FEAT_SYN_HL
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013421 lnum = tv_get_lnum(argvars); /* -1 on type error */
13422 col = (colnr_T)tv_get_number(&argvars[1]) - 1; /* -1 on type error */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013423
13424 if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count
13425 && col >= 0 && col <= (long)STRLEN(ml_get(lnum))
13426 && rettv_list_alloc(rettv) != FAIL)
13427 {
13428 (void)syn_get_id(curwin, lnum, (colnr_T)col, FALSE, NULL, TRUE);
13429 for (i = 0; ; ++i)
13430 {
13431 id = syn_get_stack_item(i);
13432 if (id < 0)
13433 break;
13434 if (list_append_number(rettv->vval.v_list, id) == FAIL)
13435 break;
13436 }
13437 }
13438#endif
13439}
13440
13441 static void
13442get_cmd_output_as_rettv(
13443 typval_T *argvars,
13444 typval_T *rettv,
13445 int retlist)
13446{
13447 char_u *res = NULL;
13448 char_u *p;
13449 char_u *infile = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013450 int err = FALSE;
13451 FILE *fd;
13452 list_T *list = NULL;
13453 int flags = SHELL_SILENT;
13454
13455 rettv->v_type = VAR_STRING;
13456 rettv->vval.v_string = NULL;
13457 if (check_restricted() || check_secure())
13458 goto errret;
13459
13460 if (argvars[1].v_type != VAR_UNKNOWN)
13461 {
13462 /*
Bram Moolenaar12c44922017-01-08 13:26:03 +010013463 * Write the text to a temp file, to be used for input of the shell
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013464 * command.
13465 */
13466 if ((infile = vim_tempname('i', TRUE)) == NULL)
13467 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013468 emsg(_(e_notmp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013469 goto errret;
13470 }
13471
13472 fd = mch_fopen((char *)infile, WRITEBIN);
13473 if (fd == NULL)
13474 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013475 semsg(_(e_notopen), infile);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013476 goto errret;
13477 }
Bram Moolenaar12c44922017-01-08 13:26:03 +010013478 if (argvars[1].v_type == VAR_NUMBER)
13479 {
13480 linenr_T lnum;
13481 buf_T *buf;
13482
13483 buf = buflist_findnr(argvars[1].vval.v_number);
13484 if (buf == NULL)
13485 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013486 semsg(_(e_nobufnr), argvars[1].vval.v_number);
Bram Moolenaar23c9e8b2017-01-20 19:59:54 +010013487 fclose(fd);
Bram Moolenaar12c44922017-01-08 13:26:03 +010013488 goto errret;
13489 }
13490
13491 for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++)
13492 {
13493 for (p = ml_get_buf(buf, lnum, FALSE); *p != NUL; ++p)
13494 if (putc(*p == '\n' ? NUL : *p, fd) == EOF)
13495 {
13496 err = TRUE;
13497 break;
13498 }
13499 if (putc(NL, fd) == EOF)
13500 {
13501 err = TRUE;
13502 break;
13503 }
13504 }
13505 }
13506 else if (argvars[1].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013507 {
13508 if (write_list(fd, argvars[1].vval.v_list, TRUE) == FAIL)
13509 err = TRUE;
13510 }
13511 else
13512 {
Bram Moolenaar12c44922017-01-08 13:26:03 +010013513 size_t len;
13514 char_u buf[NUMBUFLEN];
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013515
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013516 p = tv_get_string_buf_chk(&argvars[1], buf);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013517 if (p == NULL)
13518 {
13519 fclose(fd);
13520 goto errret; /* type error; errmsg already given */
13521 }
13522 len = STRLEN(p);
13523 if (len > 0 && fwrite(p, len, 1, fd) != 1)
13524 err = TRUE;
13525 }
13526 if (fclose(fd) != 0)
13527 err = TRUE;
13528 if (err)
13529 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013530 emsg(_("E677: Error writing temp file"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013531 goto errret;
13532 }
13533 }
13534
13535 /* Omit SHELL_COOKED when invoked with ":silent". Avoids that the shell
13536 * echoes typeahead, that messes up the display. */
13537 if (!msg_silent)
13538 flags += SHELL_COOKED;
13539
13540 if (retlist)
13541 {
13542 int len;
13543 listitem_T *li;
13544 char_u *s = NULL;
13545 char_u *start;
13546 char_u *end;
13547 int i;
13548
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013549 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, &len);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013550 if (res == NULL)
13551 goto errret;
13552
13553 list = list_alloc();
13554 if (list == NULL)
13555 goto errret;
13556
13557 for (i = 0; i < len; ++i)
13558 {
13559 start = res + i;
13560 while (i < len && res[i] != NL)
13561 ++i;
13562 end = res + i;
13563
13564 s = alloc((unsigned)(end - start + 1));
13565 if (s == NULL)
13566 goto errret;
13567
13568 for (p = s; start < end; ++p, ++start)
13569 *p = *start == NUL ? NL : *start;
13570 *p = NUL;
13571
13572 li = listitem_alloc();
13573 if (li == NULL)
13574 {
13575 vim_free(s);
13576 goto errret;
13577 }
13578 li->li_tv.v_type = VAR_STRING;
13579 li->li_tv.v_lock = 0;
13580 li->li_tv.vval.v_string = s;
13581 list_append(list, li);
13582 }
13583
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020013584 rettv_list_set(rettv, list);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013585 list = NULL;
13586 }
13587 else
13588 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013589 res = get_cmd_output(tv_get_string(&argvars[0]), infile, flags, NULL);
Bram Moolenaar00590742019-02-15 21:06:09 +010013590#ifdef USE_CRNL
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013591 /* translate <CR><NL> into <NL> */
13592 if (res != NULL)
13593 {
13594 char_u *s, *d;
13595
13596 d = res;
13597 for (s = res; *s; ++s)
13598 {
13599 if (s[0] == CAR && s[1] == NL)
13600 ++s;
13601 *d++ = *s;
13602 }
13603 *d = NUL;
13604 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013605#endif
13606 rettv->vval.v_string = res;
13607 res = NULL;
13608 }
13609
13610errret:
13611 if (infile != NULL)
13612 {
13613 mch_remove(infile);
13614 vim_free(infile);
13615 }
13616 if (res != NULL)
13617 vim_free(res);
13618 if (list != NULL)
13619 list_free(list);
13620}
13621
13622/*
13623 * "system()" function
13624 */
13625 static void
13626f_system(typval_T *argvars, typval_T *rettv)
13627{
13628 get_cmd_output_as_rettv(argvars, rettv, FALSE);
13629}
13630
13631/*
13632 * "systemlist()" function
13633 */
13634 static void
13635f_systemlist(typval_T *argvars, typval_T *rettv)
13636{
13637 get_cmd_output_as_rettv(argvars, rettv, TRUE);
13638}
13639
13640/*
13641 * "tabpagebuflist()" function
13642 */
13643 static void
13644f_tabpagebuflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13645{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013646 tabpage_T *tp;
13647 win_T *wp = NULL;
13648
13649 if (argvars[0].v_type == VAR_UNKNOWN)
13650 wp = firstwin;
13651 else
13652 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013653 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013654 if (tp != NULL)
13655 wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13656 }
13657 if (wp != NULL && rettv_list_alloc(rettv) != FAIL)
13658 {
13659 for (; wp != NULL; wp = wp->w_next)
13660 if (list_append_number(rettv->vval.v_list,
13661 wp->w_buffer->b_fnum) == FAIL)
13662 break;
13663 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013664}
13665
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013666/*
13667 * "tabpagenr()" function
13668 */
13669 static void
13670f_tabpagenr(typval_T *argvars UNUSED, typval_T *rettv)
13671{
13672 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013673 char_u *arg;
13674
13675 if (argvars[0].v_type != VAR_UNKNOWN)
13676 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013677 arg = tv_get_string_chk(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013678 nr = 0;
13679 if (arg != NULL)
13680 {
13681 if (STRCMP(arg, "$") == 0)
13682 nr = tabpage_index(NULL) - 1;
13683 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013684 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013685 }
13686 }
13687 else
13688 nr = tabpage_index(curtab);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013689 rettv->vval.v_number = nr;
13690}
13691
13692
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013693/*
13694 * Common code for tabpagewinnr() and winnr().
13695 */
13696 static int
13697get_winnr(tabpage_T *tp, typval_T *argvar)
13698{
13699 win_T *twin;
13700 int nr = 1;
13701 win_T *wp;
13702 char_u *arg;
13703
13704 twin = (tp == curtab) ? curwin : tp->tp_curwin;
13705 if (argvar->v_type != VAR_UNKNOWN)
13706 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013707 arg = tv_get_string_chk(argvar);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013708 if (arg == NULL)
13709 nr = 0; /* type error; errmsg already given */
13710 else if (STRCMP(arg, "$") == 0)
13711 twin = (tp == curtab) ? lastwin : tp->tp_lastwin;
13712 else if (STRCMP(arg, "#") == 0)
13713 {
13714 twin = (tp == curtab) ? prevwin : tp->tp_prevwin;
13715 if (twin == NULL)
13716 nr = 0;
13717 }
13718 else
13719 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013720 semsg(_(e_invexpr2), arg);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013721 nr = 0;
13722 }
13723 }
13724
13725 if (nr > 0)
13726 for (wp = (tp == curtab) ? firstwin : tp->tp_firstwin;
13727 wp != twin; wp = wp->w_next)
13728 {
13729 if (wp == NULL)
13730 {
13731 /* didn't find it in this tabpage */
13732 nr = 0;
13733 break;
13734 }
13735 ++nr;
13736 }
13737 return nr;
13738}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013739
13740/*
13741 * "tabpagewinnr()" function
13742 */
13743 static void
13744f_tabpagewinnr(typval_T *argvars UNUSED, typval_T *rettv)
13745{
13746 int nr = 1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013747 tabpage_T *tp;
13748
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013749 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013750 if (tp == NULL)
13751 nr = 0;
13752 else
13753 nr = get_winnr(tp, &argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013754 rettv->vval.v_number = nr;
13755}
13756
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013757/*
13758 * "tagfiles()" function
13759 */
13760 static void
13761f_tagfiles(typval_T *argvars UNUSED, typval_T *rettv)
13762{
13763 char_u *fname;
13764 tagname_T tn;
13765 int first;
13766
13767 if (rettv_list_alloc(rettv) == FAIL)
13768 return;
13769 fname = alloc(MAXPATHL);
13770 if (fname == NULL)
13771 return;
13772
13773 for (first = TRUE; ; first = FALSE)
13774 if (get_tagfname(&tn, first, fname) == FAIL
13775 || list_append_string(rettv->vval.v_list, fname, -1) == FAIL)
13776 break;
13777 tagname_free(&tn);
13778 vim_free(fname);
13779}
13780
13781/*
13782 * "taglist()" function
13783 */
13784 static void
13785f_taglist(typval_T *argvars, typval_T *rettv)
13786{
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013787 char_u *fname = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013788 char_u *tag_pattern;
13789
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013790 tag_pattern = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013791
13792 rettv->vval.v_number = FALSE;
13793 if (*tag_pattern == NUL)
13794 return;
13795
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013796 if (argvars[1].v_type != VAR_UNKNOWN)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013797 fname = tv_get_string(&argvars[1]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013798 if (rettv_list_alloc(rettv) == OK)
Bram Moolenaarc6aafba2017-03-21 17:09:10 +010013799 (void)get_tags(rettv->vval.v_list, tag_pattern, fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013800}
13801
13802/*
13803 * "tempname()" function
13804 */
13805 static void
13806f_tempname(typval_T *argvars UNUSED, typval_T *rettv)
13807{
13808 static int x = 'A';
13809
13810 rettv->v_type = VAR_STRING;
13811 rettv->vval.v_string = vim_tempname(x, FALSE);
13812
13813 /* Advance 'x' to use A-Z and 0-9, so that there are at least 34 different
13814 * names. Skip 'I' and 'O', they are used for shell redirection. */
13815 do
13816 {
13817 if (x == 'Z')
13818 x = '0';
13819 else if (x == '9')
13820 x = 'A';
13821 else
13822 {
13823#ifdef EBCDIC
13824 if (x == 'I')
13825 x = 'J';
13826 else if (x == 'R')
13827 x = 'S';
13828 else
13829#endif
13830 ++x;
13831 }
13832 } while (x == 'I' || x == 'O');
13833}
13834
13835#ifdef FEAT_FLOAT
13836/*
13837 * "tan()" function
13838 */
13839 static void
13840f_tan(typval_T *argvars, typval_T *rettv)
13841{
13842 float_T f = 0.0;
13843
13844 rettv->v_type = VAR_FLOAT;
13845 if (get_float_arg(argvars, &f) == OK)
13846 rettv->vval.v_float = tan(f);
13847 else
13848 rettv->vval.v_float = 0.0;
13849}
13850
13851/*
13852 * "tanh()" function
13853 */
13854 static void
13855f_tanh(typval_T *argvars, typval_T *rettv)
13856{
13857 float_T f = 0.0;
13858
13859 rettv->v_type = VAR_FLOAT;
13860 if (get_float_arg(argvars, &f) == OK)
13861 rettv->vval.v_float = tanh(f);
13862 else
13863 rettv->vval.v_float = 0.0;
13864}
13865#endif
13866
13867/*
13868 * "test_alloc_fail(id, countdown, repeat)" function
13869 */
13870 static void
13871f_test_alloc_fail(typval_T *argvars, typval_T *rettv UNUSED)
13872{
13873 if (argvars[0].v_type != VAR_NUMBER
13874 || argvars[0].vval.v_number <= 0
13875 || argvars[1].v_type != VAR_NUMBER
13876 || argvars[1].vval.v_number < 0
13877 || argvars[2].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013878 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013879 else
13880 {
13881 alloc_fail_id = argvars[0].vval.v_number;
13882 if (alloc_fail_id >= aid_last)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013883 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013884 alloc_fail_countdown = argvars[1].vval.v_number;
13885 alloc_fail_repeat = argvars[2].vval.v_number;
13886 did_outofmem_msg = FALSE;
13887 }
13888}
13889
13890/*
13891 * "test_autochdir()"
13892 */
13893 static void
13894f_test_autochdir(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
13895{
13896#if defined(FEAT_AUTOCHDIR)
13897 test_autochdir = TRUE;
13898#endif
13899}
13900
13901/*
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013902 * "test_feedinput()"
13903 */
13904 static void
13905f_test_feedinput(typval_T *argvars, typval_T *rettv UNUSED)
13906{
13907#ifdef USE_INPUT_BUF
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013908 char_u *val = tv_get_string_chk(&argvars[0]);
Bram Moolenaar5e80de32017-09-03 15:48:12 +020013909
13910 if (val != NULL)
13911 {
13912 trash_input_buf();
13913 add_to_input_buf_csi(val, (int)STRLEN(val));
13914 }
13915#endif
13916}
13917
13918/*
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013919 * "test_option_not_set({name})" function
13920 */
13921 static void
13922f_test_option_not_set(typval_T *argvars, typval_T *rettv UNUSED)
13923{
13924 char_u *name = (char_u *)"";
13925
13926 if (argvars[0].v_type != VAR_STRING)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013927 emsg(_(e_invarg));
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013928 else
13929 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013930 name = tv_get_string(&argvars[0]);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013931 if (reset_option_was_set(name) == FAIL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013932 semsg(_(e_invarg2), name);
Bram Moolenaarfe8ef982018-09-13 20:31:54 +020013933 }
13934}
13935
13936/*
13937 * "test_override({name}, {val})" function
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013938 */
13939 static void
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013940f_test_override(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013941{
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013942 char_u *name = (char_u *)"";
13943 int val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013944 static int save_starting = -1;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013945
13946 if (argvars[0].v_type != VAR_STRING
13947 || (argvars[1].v_type) != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013948 emsg(_(e_invarg));
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013949 else
13950 {
Bram Moolenaare38197d2018-12-24 23:35:13 +010013951 name = tv_get_string(&argvars[0]);
Bram Moolenaard155d7a2018-12-21 16:04:21 +010013952 val = (int)tv_get_number(&argvars[1]);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013953
13954 if (STRCMP(name, (char_u *)"redraw") == 0)
13955 disable_redraw_for_testing = val;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013956 else if (STRCMP(name, (char_u *)"redraw_flag") == 0)
13957 ignore_redraw_flag_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013958 else if (STRCMP(name, (char_u *)"char_avail") == 0)
13959 disable_char_avail_for_testing = val;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013960 else if (STRCMP(name, (char_u *)"starting") == 0)
13961 {
13962 if (val)
13963 {
13964 if (save_starting < 0)
13965 save_starting = starting;
13966 starting = 0;
13967 }
13968 else
13969 {
13970 starting = save_starting;
13971 save_starting = -1;
13972 }
13973 }
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013974 else if (STRCMP(name, (char_u *)"nfa_fail") == 0)
13975 nfa_fail_for_testing = val;
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013976 else if (STRCMP(name, (char_u *)"ALL") == 0)
13977 {
13978 disable_char_avail_for_testing = FALSE;
13979 disable_redraw_for_testing = FALSE;
Bram Moolenaared5a9d62018-09-06 13:14:43 +020013980 ignore_redraw_flag_for_testing = FALSE;
Bram Moolenaarbcf94422018-06-23 14:21:42 +020013981 nfa_fail_for_testing = FALSE;
Bram Moolenaar182a17b2017-06-25 20:57:18 +020013982 if (save_starting >= 0)
13983 {
13984 starting = save_starting;
13985 save_starting = -1;
13986 }
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013987 }
13988 else
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010013989 semsg(_(e_invarg2), name);
Bram Moolenaareb992cb2017-03-09 18:20:16 +010013990 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020013991}
13992
13993/*
Bram Moolenaarc3e92c12019-03-23 14:23:07 +010013994 * "test_refcount({expr})" function
13995 */
13996 static void
13997f_test_refcount(typval_T *argvars, typval_T *rettv)
13998{
13999 int retval = -1;
14000
14001 switch (argvars[0].v_type)
14002 {
14003 case VAR_UNKNOWN:
14004 case VAR_NUMBER:
14005 case VAR_FLOAT:
14006 case VAR_SPECIAL:
14007 case VAR_STRING:
14008 break;
14009 case VAR_JOB:
14010#ifdef FEAT_JOB_CHANNEL
14011 if (argvars[0].vval.v_job != NULL)
14012 retval = argvars[0].vval.v_job->jv_refcount - 1;
14013#endif
14014 break;
14015 case VAR_CHANNEL:
14016#ifdef FEAT_JOB_CHANNEL
14017 if (argvars[0].vval.v_channel != NULL)
14018 retval = argvars[0].vval.v_channel->ch_refcount - 1;
14019#endif
14020 break;
14021 case VAR_FUNC:
14022 if (argvars[0].vval.v_string != NULL)
14023 {
14024 ufunc_T *fp;
14025
14026 fp = find_func(argvars[0].vval.v_string);
14027 if (fp != NULL)
14028 retval = fp->uf_refcount;
14029 }
14030 break;
14031 case VAR_PARTIAL:
14032 if (argvars[0].vval.v_partial != NULL)
14033 retval = argvars[0].vval.v_partial->pt_refcount - 1;
14034 break;
14035 case VAR_BLOB:
14036 if (argvars[0].vval.v_blob != NULL)
14037 retval = argvars[0].vval.v_blob->bv_refcount - 1;
14038 break;
14039 case VAR_LIST:
14040 if (argvars[0].vval.v_list != NULL)
14041 retval = argvars[0].vval.v_list->lv_refcount - 1;
14042 break;
14043 case VAR_DICT:
14044 if (argvars[0].vval.v_dict != NULL)
14045 retval = argvars[0].vval.v_dict->dv_refcount - 1;
14046 break;
14047 }
14048
14049 rettv->v_type = VAR_NUMBER;
14050 rettv->vval.v_number = retval;
14051
14052}
14053
14054/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014055 * "test_garbagecollect_now()" function
14056 */
14057 static void
14058f_test_garbagecollect_now(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14059{
14060 /* This is dangerous, any Lists and Dicts used internally may be freed
14061 * while still in use. */
14062 garbage_collect(TRUE);
14063}
14064
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014065/*
14066 * "test_ignore_error()" function
14067 */
14068 static void
14069f_test_ignore_error(typval_T *argvars, typval_T *rettv UNUSED)
14070{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014071 ignore_error_for_testing(tv_get_string(&argvars[0]));
Bram Moolenaare0c31f62017-03-01 15:07:05 +010014072}
14073
Bram Moolenaarc0f5a782019-01-13 15:16:13 +010014074 static void
14075f_test_null_blob(typval_T *argvars UNUSED, typval_T *rettv)
14076{
14077 rettv->v_type = VAR_BLOB;
14078 rettv->vval.v_blob = NULL;
14079}
14080
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014081#ifdef FEAT_JOB_CHANNEL
14082 static void
14083f_test_null_channel(typval_T *argvars UNUSED, typval_T *rettv)
14084{
14085 rettv->v_type = VAR_CHANNEL;
14086 rettv->vval.v_channel = NULL;
14087}
14088#endif
14089
14090 static void
14091f_test_null_dict(typval_T *argvars UNUSED, typval_T *rettv)
14092{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014093 rettv_dict_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014094}
14095
14096#ifdef FEAT_JOB_CHANNEL
14097 static void
14098f_test_null_job(typval_T *argvars UNUSED, typval_T *rettv)
14099{
14100 rettv->v_type = VAR_JOB;
14101 rettv->vval.v_job = NULL;
14102}
14103#endif
14104
14105 static void
14106f_test_null_list(typval_T *argvars UNUSED, typval_T *rettv)
14107{
Bram Moolenaar45cf6e92017-04-30 20:25:19 +020014108 rettv_list_set(rettv, NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014109}
14110
14111 static void
14112f_test_null_partial(typval_T *argvars UNUSED, typval_T *rettv)
14113{
14114 rettv->v_type = VAR_PARTIAL;
14115 rettv->vval.v_partial = NULL;
14116}
14117
14118 static void
14119f_test_null_string(typval_T *argvars UNUSED, typval_T *rettv)
14120{
14121 rettv->v_type = VAR_STRING;
14122 rettv->vval.v_string = NULL;
14123}
14124
Bram Moolenaarab186732018-09-14 21:27:06 +020014125#ifdef FEAT_GUI
14126 static void
14127f_test_scrollbar(typval_T *argvars, typval_T *rettv UNUSED)
14128{
14129 char_u *which;
14130 long value;
14131 int dragging;
14132 scrollbar_T *sb = NULL;
14133
14134 if (argvars[0].v_type != VAR_STRING
14135 || (argvars[1].v_type) != VAR_NUMBER
14136 || (argvars[2].v_type) != VAR_NUMBER)
14137 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014138 emsg(_(e_invarg));
Bram Moolenaarab186732018-09-14 21:27:06 +020014139 return;
14140 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014141 which = tv_get_string(&argvars[0]);
14142 value = tv_get_number(&argvars[1]);
14143 dragging = tv_get_number(&argvars[2]);
Bram Moolenaarab186732018-09-14 21:27:06 +020014144
14145 if (STRCMP(which, "left") == 0)
14146 sb = &curwin->w_scrollbars[SBAR_LEFT];
14147 else if (STRCMP(which, "right") == 0)
14148 sb = &curwin->w_scrollbars[SBAR_RIGHT];
14149 else if (STRCMP(which, "hor") == 0)
14150 sb = &gui.bottom_sbar;
14151 if (sb == NULL)
14152 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014153 semsg(_(e_invarg2), which);
Bram Moolenaarab186732018-09-14 21:27:06 +020014154 return;
14155 }
14156 gui_drag_scrollbar(sb, value, dragging);
Bram Moolenaar586c70c2018-10-02 16:23:58 +020014157# ifndef USE_ON_FLY_SCROLL
14158 // need to loop through normal_cmd() to handle the scroll events
14159 exec_normal(FALSE, TRUE, FALSE);
14160# endif
Bram Moolenaarab186732018-09-14 21:27:06 +020014161}
14162#endif
14163
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014164 static void
14165f_test_settime(typval_T *argvars, typval_T *rettv UNUSED)
14166{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014167 time_for_testing = (time_t)tv_get_number(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014168}
14169
14170#if defined(FEAT_JOB_CHANNEL) || defined(FEAT_TIMERS) || defined(PROTO)
14171/*
14172 * Get a callback from "arg". It can be a Funcref or a function name.
14173 * When "arg" is zero return an empty string.
14174 * Return NULL for an invalid argument.
14175 */
14176 char_u *
14177get_callback(typval_T *arg, partial_T **pp)
14178{
14179 if (arg->v_type == VAR_PARTIAL && arg->vval.v_partial != NULL)
14180 {
14181 *pp = arg->vval.v_partial;
14182 ++(*pp)->pt_refcount;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014183 return partial_name(*pp);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014184 }
14185 *pp = NULL;
Bram Moolenaar437bafe2016-08-01 15:40:54 +020014186 if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014187 {
14188 func_ref(arg->vval.v_string);
14189 return arg->vval.v_string;
14190 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014191 if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
14192 return (char_u *)"";
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014193 emsg(_("E921: Invalid callback argument"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014194 return NULL;
14195}
14196
14197/*
Bram Moolenaard5359b22018-04-05 22:44:39 +020014198 * Unref/free "callback" and "partial" returned by get_callback().
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014199 */
14200 void
14201free_callback(char_u *callback, partial_T *partial)
14202{
14203 if (partial != NULL)
14204 partial_unref(partial);
14205 else if (callback != NULL)
14206 {
14207 func_unref(callback);
14208 vim_free(callback);
14209 }
14210}
14211#endif
14212
14213#ifdef FEAT_TIMERS
14214/*
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014215 * "timer_info([timer])" function
14216 */
14217 static void
14218f_timer_info(typval_T *argvars, typval_T *rettv)
14219{
14220 timer_T *timer = NULL;
14221
14222 if (rettv_list_alloc(rettv) != OK)
14223 return;
14224 if (argvars[0].v_type != VAR_UNKNOWN)
14225 {
14226 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014227 emsg(_(e_number_exp));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014228 else
14229 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014230 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar8e97bd72016-08-06 22:05:07 +020014231 if (timer != NULL)
14232 add_timer_info(rettv, timer);
14233 }
14234 }
14235 else
14236 add_timer_info_all(rettv);
14237}
14238
14239/*
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014240 * "timer_pause(timer, paused)" function
14241 */
14242 static void
14243f_timer_pause(typval_T *argvars, typval_T *rettv UNUSED)
14244{
14245 timer_T *timer = NULL;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014246 int paused = (int)tv_get_number(&argvars[1]);
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014247
14248 if (argvars[0].v_type != VAR_NUMBER)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014249 emsg(_(e_number_exp));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014250 else
14251 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014252 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014253 if (timer != NULL)
14254 timer->tr_paused = paused;
14255 }
14256}
14257
14258/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014259 * "timer_start(time, callback [, options])" function
14260 */
14261 static void
14262f_timer_start(typval_T *argvars, typval_T *rettv)
14263{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014264 long msec = (long)tv_get_number(&argvars[0]);
Bram Moolenaar75537a92016-09-05 22:45:28 +020014265 timer_T *timer;
14266 int repeat = 0;
14267 char_u *callback;
14268 dict_T *dict;
14269 partial_T *partial;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014270
Bram Moolenaar75537a92016-09-05 22:45:28 +020014271 rettv->vval.v_number = -1;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014272 if (check_secure())
14273 return;
14274 if (argvars[2].v_type != VAR_UNKNOWN)
14275 {
14276 if (argvars[2].v_type != VAR_DICT
14277 || (dict = argvars[2].vval.v_dict) == NULL)
14278 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014279 semsg(_(e_invarg2), tv_get_string(&argvars[2]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014280 return;
14281 }
14282 if (dict_find(dict, (char_u *)"repeat", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014283 repeat = dict_get_number(dict, (char_u *)"repeat");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014284 }
14285
Bram Moolenaar75537a92016-09-05 22:45:28 +020014286 callback = get_callback(&argvars[1], &partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014287 if (callback == NULL)
Bram Moolenaar75537a92016-09-05 22:45:28 +020014288 return;
14289
14290 timer = create_timer(msec, repeat);
14291 if (timer == NULL)
14292 free_callback(callback, partial);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014293 else
14294 {
Bram Moolenaar26fe0d52016-09-10 14:27:30 +020014295 if (partial == NULL)
Bram Moolenaar3ab14352016-07-30 22:32:11 +020014296 timer->tr_callback = vim_strsave(callback);
14297 else
14298 /* pointer into the partial */
14299 timer->tr_callback = callback;
Bram Moolenaar75537a92016-09-05 22:45:28 +020014300 timer->tr_partial = partial;
14301 rettv->vval.v_number = (varnumber_T)timer->tr_id;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014302 }
14303}
14304
14305/*
14306 * "timer_stop(timer)" function
14307 */
14308 static void
14309f_timer_stop(typval_T *argvars, typval_T *rettv UNUSED)
14310{
14311 timer_T *timer;
14312
14313 if (argvars[0].v_type != VAR_NUMBER)
14314 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014315 emsg(_(e_number_exp));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014316 return;
14317 }
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014318 timer = find_timer((int)tv_get_number(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014319 if (timer != NULL)
14320 stop_timer(timer);
14321}
Bram Moolenaarb73598e2016-08-07 18:22:53 +020014322
14323/*
14324 * "timer_stopall()" function
14325 */
14326 static void
14327f_timer_stopall(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14328{
14329 stop_all_timers();
14330}
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014331#endif
14332
14333/*
14334 * "tolower(string)" function
14335 */
14336 static void
14337f_tolower(typval_T *argvars, typval_T *rettv)
14338{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014339 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014340 rettv->vval.v_string = strlow_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014341}
14342
14343/*
14344 * "toupper(string)" function
14345 */
14346 static void
14347f_toupper(typval_T *argvars, typval_T *rettv)
14348{
14349 rettv->v_type = VAR_STRING;
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014350 rettv->vval.v_string = strup_save(tv_get_string(&argvars[0]));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014351}
14352
14353/*
14354 * "tr(string, fromstr, tostr)" function
14355 */
14356 static void
14357f_tr(typval_T *argvars, typval_T *rettv)
14358{
14359 char_u *in_str;
14360 char_u *fromstr;
14361 char_u *tostr;
14362 char_u *p;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014363 int inlen;
14364 int fromlen;
14365 int tolen;
14366 int idx;
14367 char_u *cpstr;
14368 int cplen;
14369 int first = TRUE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014370 char_u buf[NUMBUFLEN];
14371 char_u buf2[NUMBUFLEN];
14372 garray_T ga;
14373
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014374 in_str = tv_get_string(&argvars[0]);
14375 fromstr = tv_get_string_buf_chk(&argvars[1], buf);
14376 tostr = tv_get_string_buf_chk(&argvars[2], buf2);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014377
14378 /* Default return value: empty string. */
14379 rettv->v_type = VAR_STRING;
14380 rettv->vval.v_string = NULL;
14381 if (fromstr == NULL || tostr == NULL)
14382 return; /* type error; errmsg already given */
14383 ga_init2(&ga, (int)sizeof(char), 80);
14384
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014385 if (!has_mbyte)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014386 /* not multi-byte: fromstr and tostr must be the same length */
14387 if (STRLEN(fromstr) != STRLEN(tostr))
14388 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014389error:
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014390 semsg(_(e_invarg2), fromstr);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014391 ga_clear(&ga);
14392 return;
14393 }
14394
14395 /* fromstr and tostr have to contain the same number of chars */
14396 while (*in_str != NUL)
14397 {
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014398 if (has_mbyte)
14399 {
14400 inlen = (*mb_ptr2len)(in_str);
14401 cpstr = in_str;
14402 cplen = inlen;
14403 idx = 0;
14404 for (p = fromstr; *p != NUL; p += fromlen)
14405 {
14406 fromlen = (*mb_ptr2len)(p);
14407 if (fromlen == inlen && STRNCMP(in_str, p, inlen) == 0)
14408 {
14409 for (p = tostr; *p != NUL; p += tolen)
14410 {
14411 tolen = (*mb_ptr2len)(p);
14412 if (idx-- == 0)
14413 {
14414 cplen = tolen;
14415 cpstr = p;
14416 break;
14417 }
14418 }
14419 if (*p == NUL) /* tostr is shorter than fromstr */
14420 goto error;
14421 break;
14422 }
14423 ++idx;
14424 }
14425
14426 if (first && cpstr == in_str)
14427 {
14428 /* Check that fromstr and tostr have the same number of
14429 * (multi-byte) characters. Done only once when a character
14430 * of in_str doesn't appear in fromstr. */
14431 first = FALSE;
14432 for (p = tostr; *p != NUL; p += tolen)
14433 {
14434 tolen = (*mb_ptr2len)(p);
14435 --idx;
14436 }
14437 if (idx != 0)
14438 goto error;
14439 }
14440
14441 (void)ga_grow(&ga, cplen);
14442 mch_memmove((char *)ga.ga_data + ga.ga_len, cpstr, (size_t)cplen);
14443 ga.ga_len += cplen;
14444
14445 in_str += inlen;
14446 }
14447 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014448 {
14449 /* When not using multi-byte chars we can do it faster. */
14450 p = vim_strchr(fromstr, *in_str);
14451 if (p != NULL)
14452 ga_append(&ga, tostr[p - fromstr]);
14453 else
14454 ga_append(&ga, *in_str);
14455 ++in_str;
14456 }
14457 }
14458
14459 /* add a terminating NUL */
14460 (void)ga_grow(&ga, 1);
14461 ga_append(&ga, NUL);
14462
14463 rettv->vval.v_string = ga.ga_data;
14464}
14465
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014466/*
14467 * "trim({expr})" function
14468 */
14469 static void
14470f_trim(typval_T *argvars, typval_T *rettv)
14471{
14472 char_u buf1[NUMBUFLEN];
14473 char_u buf2[NUMBUFLEN];
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014474 char_u *head = tv_get_string_buf_chk(&argvars[0], buf1);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014475 char_u *mask = NULL;
14476 char_u *tail;
14477 char_u *prev;
14478 char_u *p;
14479 int c1;
14480
14481 rettv->v_type = VAR_STRING;
14482 if (head == NULL)
14483 {
14484 rettv->vval.v_string = NULL;
14485 return;
14486 }
14487
14488 if (argvars[1].v_type == VAR_STRING)
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014489 mask = tv_get_string_buf_chk(&argvars[1], buf2);
Bram Moolenaar295ac5a2018-03-22 23:04:02 +010014490
14491 while (*head != NUL)
14492 {
14493 c1 = PTR2CHAR(head);
14494 if (mask == NULL)
14495 {
14496 if (c1 > ' ' && c1 != 0xa0)
14497 break;
14498 }
14499 else
14500 {
14501 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14502 if (c1 == PTR2CHAR(p))
14503 break;
14504 if (*p == NUL)
14505 break;
14506 }
14507 MB_PTR_ADV(head);
14508 }
14509
14510 for (tail = head + STRLEN(head); tail > head; tail = prev)
14511 {
14512 prev = tail;
14513 MB_PTR_BACK(head, prev);
14514 c1 = PTR2CHAR(prev);
14515 if (mask == NULL)
14516 {
14517 if (c1 > ' ' && c1 != 0xa0)
14518 break;
14519 }
14520 else
14521 {
14522 for (p = mask; *p != NUL; MB_PTR_ADV(p))
14523 if (c1 == PTR2CHAR(p))
14524 break;
14525 if (*p == NUL)
14526 break;
14527 }
14528 }
14529 rettv->vval.v_string = vim_strnsave(head, (int)(tail - head));
14530}
14531
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014532#ifdef FEAT_FLOAT
14533/*
14534 * "trunc({float})" function
14535 */
14536 static void
14537f_trunc(typval_T *argvars, typval_T *rettv)
14538{
14539 float_T f = 0.0;
14540
14541 rettv->v_type = VAR_FLOAT;
14542 if (get_float_arg(argvars, &f) == OK)
14543 /* trunc() is not in C90, use floor() or ceil() instead. */
14544 rettv->vval.v_float = f > 0 ? floor(f) : ceil(f);
14545 else
14546 rettv->vval.v_float = 0.0;
14547}
14548#endif
14549
14550/*
14551 * "type(expr)" function
14552 */
14553 static void
14554f_type(typval_T *argvars, typval_T *rettv)
14555{
14556 int n = -1;
14557
14558 switch (argvars[0].v_type)
14559 {
Bram Moolenaarf562e722016-07-19 17:25:25 +020014560 case VAR_NUMBER: n = VAR_TYPE_NUMBER; break;
14561 case VAR_STRING: n = VAR_TYPE_STRING; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014562 case VAR_PARTIAL:
Bram Moolenaarf562e722016-07-19 17:25:25 +020014563 case VAR_FUNC: n = VAR_TYPE_FUNC; break;
14564 case VAR_LIST: n = VAR_TYPE_LIST; break;
14565 case VAR_DICT: n = VAR_TYPE_DICT; break;
14566 case VAR_FLOAT: n = VAR_TYPE_FLOAT; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014567 case VAR_SPECIAL:
14568 if (argvars[0].vval.v_number == VVAL_FALSE
14569 || argvars[0].vval.v_number == VVAL_TRUE)
Bram Moolenaarf562e722016-07-19 17:25:25 +020014570 n = VAR_TYPE_BOOL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014571 else
Bram Moolenaarf562e722016-07-19 17:25:25 +020014572 n = VAR_TYPE_NONE;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014573 break;
Bram Moolenaarf562e722016-07-19 17:25:25 +020014574 case VAR_JOB: n = VAR_TYPE_JOB; break;
14575 case VAR_CHANNEL: n = VAR_TYPE_CHANNEL; break;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014576 case VAR_BLOB: n = VAR_TYPE_BLOB; break;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014577 case VAR_UNKNOWN:
Bram Moolenaar95f09602016-11-10 20:01:45 +010014578 internal_error("f_type(UNKNOWN)");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014579 n = -1;
14580 break;
14581 }
14582 rettv->vval.v_number = n;
14583}
14584
14585/*
14586 * "undofile(name)" function
14587 */
14588 static void
14589f_undofile(typval_T *argvars UNUSED, typval_T *rettv)
14590{
14591 rettv->v_type = VAR_STRING;
14592#ifdef FEAT_PERSISTENT_UNDO
14593 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014594 char_u *fname = tv_get_string(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014595
14596 if (*fname == NUL)
14597 {
14598 /* If there is no file name there will be no undo file. */
14599 rettv->vval.v_string = NULL;
14600 }
14601 else
14602 {
14603 char_u *ffname = FullName_save(fname, FALSE);
14604
14605 if (ffname != NULL)
14606 rettv->vval.v_string = u_get_undo_file_name(ffname, FALSE);
14607 vim_free(ffname);
14608 }
14609 }
14610#else
14611 rettv->vval.v_string = NULL;
14612#endif
14613}
14614
14615/*
14616 * "undotree()" function
14617 */
14618 static void
14619f_undotree(typval_T *argvars UNUSED, typval_T *rettv)
14620{
14621 if (rettv_dict_alloc(rettv) == OK)
14622 {
14623 dict_T *dict = rettv->vval.v_dict;
14624 list_T *list;
14625
Bram Moolenaare0be1672018-07-08 16:50:37 +020014626 dict_add_number(dict, "synced", (long)curbuf->b_u_synced);
14627 dict_add_number(dict, "seq_last", curbuf->b_u_seq_last);
14628 dict_add_number(dict, "save_last", (long)curbuf->b_u_save_nr_last);
14629 dict_add_number(dict, "seq_cur", curbuf->b_u_seq_cur);
14630 dict_add_number(dict, "time_cur", (long)curbuf->b_u_time_cur);
14631 dict_add_number(dict, "save_cur", (long)curbuf->b_u_save_nr_cur);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014632
14633 list = list_alloc();
14634 if (list != NULL)
14635 {
14636 u_eval_tree(curbuf->b_u_oldhead, list);
14637 dict_add_list(dict, "entries", list);
14638 }
14639 }
14640}
14641
14642/*
14643 * "values(dict)" function
14644 */
14645 static void
14646f_values(typval_T *argvars, typval_T *rettv)
14647{
14648 dict_list(argvars, rettv, 1);
14649}
14650
14651/*
14652 * "virtcol(string)" function
14653 */
14654 static void
14655f_virtcol(typval_T *argvars, typval_T *rettv)
14656{
14657 colnr_T vcol = 0;
14658 pos_T *fp;
14659 int fnum = curbuf->b_fnum;
14660
14661 fp = var2fpos(&argvars[0], FALSE, &fnum);
14662 if (fp != NULL && fp->lnum <= curbuf->b_ml.ml_line_count
14663 && fnum == curbuf->b_fnum)
14664 {
14665 getvvcol(curwin, fp, NULL, NULL, &vcol);
14666 ++vcol;
14667 }
14668
14669 rettv->vval.v_number = vcol;
14670}
14671
14672/*
14673 * "visualmode()" function
14674 */
14675 static void
14676f_visualmode(typval_T *argvars, typval_T *rettv)
14677{
14678 char_u str[2];
14679
14680 rettv->v_type = VAR_STRING;
14681 str[0] = curbuf->b_visual_mode_eval;
14682 str[1] = NUL;
14683 rettv->vval.v_string = vim_strsave(str);
14684
14685 /* A non-zero number or non-empty string argument: reset mode. */
14686 if (non_zero_arg(&argvars[0]))
14687 curbuf->b_visual_mode_eval = NUL;
14688}
14689
14690/*
14691 * "wildmenumode()" function
14692 */
14693 static void
14694f_wildmenumode(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
14695{
14696#ifdef FEAT_WILDMENU
14697 if (wild_menu_showing)
14698 rettv->vval.v_number = 1;
14699#endif
14700}
14701
14702/*
14703 * "winbufnr(nr)" function
14704 */
14705 static void
14706f_winbufnr(typval_T *argvars, typval_T *rettv)
14707{
14708 win_T *wp;
14709
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014710 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014711 if (wp == NULL)
14712 rettv->vval.v_number = -1;
14713 else
14714 rettv->vval.v_number = wp->w_buffer->b_fnum;
14715}
14716
14717/*
14718 * "wincol()" function
14719 */
14720 static void
14721f_wincol(typval_T *argvars UNUSED, typval_T *rettv)
14722{
14723 validate_cursor();
14724 rettv->vval.v_number = curwin->w_wcol + 1;
14725}
14726
14727/*
14728 * "winheight(nr)" function
14729 */
14730 static void
14731f_winheight(typval_T *argvars, typval_T *rettv)
14732{
14733 win_T *wp;
14734
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014735 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014736 if (wp == NULL)
14737 rettv->vval.v_number = -1;
14738 else
14739 rettv->vval.v_number = wp->w_height;
14740}
14741
14742/*
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014743 * "winlayout()" function
14744 */
14745 static void
14746f_winlayout(typval_T *argvars, typval_T *rettv)
14747{
14748 tabpage_T *tp;
14749
14750 if (rettv_list_alloc(rettv) != OK)
14751 return;
14752
14753 if (argvars[0].v_type == VAR_UNKNOWN)
14754 tp = curtab;
14755 else
14756 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014757 tp = find_tabpage((int)tv_get_number(&argvars[0]));
Bram Moolenaar0f6b4f02018-08-21 16:56:34 +020014758 if (tp == NULL)
14759 return;
14760 }
14761
14762 get_framelayout(tp->tp_topframe, rettv->vval.v_list, TRUE);
14763}
14764
14765/*
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014766 * "winline()" function
14767 */
14768 static void
14769f_winline(typval_T *argvars UNUSED, typval_T *rettv)
14770{
14771 validate_cursor();
14772 rettv->vval.v_number = curwin->w_wrow + 1;
14773}
14774
14775/*
14776 * "winnr()" function
14777 */
14778 static void
14779f_winnr(typval_T *argvars UNUSED, typval_T *rettv)
14780{
14781 int nr = 1;
14782
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014783 nr = get_winnr(curtab, &argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014784 rettv->vval.v_number = nr;
14785}
14786
14787/*
14788 * "winrestcmd()" function
14789 */
14790 static void
14791f_winrestcmd(typval_T *argvars UNUSED, typval_T *rettv)
14792{
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014793 win_T *wp;
14794 int winnr = 1;
14795 garray_T ga;
14796 char_u buf[50];
14797
14798 ga_init2(&ga, (int)sizeof(char), 70);
Bram Moolenaar29323592016-07-24 22:04:11 +020014799 FOR_ALL_WINDOWS(wp)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014800 {
14801 sprintf((char *)buf, "%dresize %d|", winnr, wp->w_height);
14802 ga_concat(&ga, buf);
14803 sprintf((char *)buf, "vert %dresize %d|", winnr, wp->w_width);
14804 ga_concat(&ga, buf);
14805 ++winnr;
14806 }
14807 ga_append(&ga, NUL);
14808
14809 rettv->vval.v_string = ga.ga_data;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014810 rettv->v_type = VAR_STRING;
14811}
14812
14813/*
14814 * "winrestview()" function
14815 */
14816 static void
14817f_winrestview(typval_T *argvars, typval_T *rettv UNUSED)
14818{
14819 dict_T *dict;
14820
14821 if (argvars[0].v_type != VAR_DICT
14822 || (dict = argvars[0].vval.v_dict) == NULL)
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014823 emsg(_(e_invarg));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014824 else
14825 {
14826 if (dict_find(dict, (char_u *)"lnum", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014827 curwin->w_cursor.lnum = (linenr_T)dict_get_number(dict, (char_u *)"lnum");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014828 if (dict_find(dict, (char_u *)"col", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014829 curwin->w_cursor.col = (colnr_T)dict_get_number(dict, (char_u *)"col");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014830 if (dict_find(dict, (char_u *)"coladd", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014831 curwin->w_cursor.coladd = (colnr_T)dict_get_number(dict, (char_u *)"coladd");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014832 if (dict_find(dict, (char_u *)"curswant", -1) != NULL)
14833 {
Bram Moolenaar8f667172018-12-14 15:38:31 +010014834 curwin->w_curswant = (colnr_T)dict_get_number(dict, (char_u *)"curswant");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014835 curwin->w_set_curswant = FALSE;
14836 }
14837
14838 if (dict_find(dict, (char_u *)"topline", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014839 set_topline(curwin, (linenr_T)dict_get_number(dict, (char_u *)"topline"));
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014840#ifdef FEAT_DIFF
14841 if (dict_find(dict, (char_u *)"topfill", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014842 curwin->w_topfill = (int)dict_get_number(dict, (char_u *)"topfill");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014843#endif
14844 if (dict_find(dict, (char_u *)"leftcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014845 curwin->w_leftcol = (colnr_T)dict_get_number(dict, (char_u *)"leftcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014846 if (dict_find(dict, (char_u *)"skipcol", -1) != NULL)
Bram Moolenaar8f667172018-12-14 15:38:31 +010014847 curwin->w_skipcol = (colnr_T)dict_get_number(dict, (char_u *)"skipcol");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014848
14849 check_cursor();
14850 win_new_height(curwin, curwin->w_height);
Bram Moolenaar02631462017-09-22 15:20:32 +020014851 win_new_width(curwin, curwin->w_width);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014852 changed_window_setting();
14853
14854 if (curwin->w_topline <= 0)
14855 curwin->w_topline = 1;
14856 if (curwin->w_topline > curbuf->b_ml.ml_line_count)
14857 curwin->w_topline = curbuf->b_ml.ml_line_count;
14858#ifdef FEAT_DIFF
14859 check_topfill(curwin, TRUE);
14860#endif
14861 }
14862}
14863
14864/*
14865 * "winsaveview()" function
14866 */
14867 static void
14868f_winsaveview(typval_T *argvars UNUSED, typval_T *rettv)
14869{
14870 dict_T *dict;
14871
14872 if (rettv_dict_alloc(rettv) == FAIL)
14873 return;
14874 dict = rettv->vval.v_dict;
14875
Bram Moolenaare0be1672018-07-08 16:50:37 +020014876 dict_add_number(dict, "lnum", (long)curwin->w_cursor.lnum);
14877 dict_add_number(dict, "col", (long)curwin->w_cursor.col);
Bram Moolenaare0be1672018-07-08 16:50:37 +020014878 dict_add_number(dict, "coladd", (long)curwin->w_cursor.coladd);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014879 update_curswant();
Bram Moolenaare0be1672018-07-08 16:50:37 +020014880 dict_add_number(dict, "curswant", (long)curwin->w_curswant);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014881
Bram Moolenaare0be1672018-07-08 16:50:37 +020014882 dict_add_number(dict, "topline", (long)curwin->w_topline);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014883#ifdef FEAT_DIFF
Bram Moolenaare0be1672018-07-08 16:50:37 +020014884 dict_add_number(dict, "topfill", (long)curwin->w_topfill);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014885#endif
Bram Moolenaare0be1672018-07-08 16:50:37 +020014886 dict_add_number(dict, "leftcol", (long)curwin->w_leftcol);
14887 dict_add_number(dict, "skipcol", (long)curwin->w_skipcol);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014888}
14889
14890/*
14891 * "winwidth(nr)" function
14892 */
14893 static void
14894f_winwidth(typval_T *argvars, typval_T *rettv)
14895{
14896 win_T *wp;
14897
Bram Moolenaarbabfcf52018-10-25 13:11:16 +020014898 wp = find_win_by_nr_or_id(&argvars[0]);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014899 if (wp == NULL)
14900 rettv->vval.v_number = -1;
14901 else
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014902 rettv->vval.v_number = wp->w_width;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014903}
14904
14905/*
14906 * "wordcount()" function
14907 */
14908 static void
14909f_wordcount(typval_T *argvars UNUSED, typval_T *rettv)
14910{
14911 if (rettv_dict_alloc(rettv) == FAIL)
14912 return;
14913 cursor_pos_info(rettv->vval.v_dict);
14914}
14915
14916/*
14917 * "writefile()" function
14918 */
14919 static void
14920f_writefile(typval_T *argvars, typval_T *rettv)
14921{
14922 int binary = FALSE;
14923 int append = FALSE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014924#ifdef HAVE_FSYNC
14925 int do_fsync = p_fs;
14926#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014927 char_u *fname;
14928 FILE *fd;
14929 int ret = 0;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014930 listitem_T *li;
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014931 list_T *list = NULL;
14932 blob_T *blob = NULL;
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014933
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014934 rettv->vval.v_number = -1;
Bram Moolenaar8c62a082019-02-08 14:34:10 +010014935 if (check_secure())
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014936 return;
14937
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014938 if (argvars[0].v_type == VAR_LIST)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014939 {
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014940 list = argvars[0].vval.v_list;
14941 if (list == NULL)
14942 return;
14943 for (li = list->lv_first; li != NULL; li = li->li_next)
14944 if (tv_get_string_chk(&li->li_tv) == NULL)
14945 return;
14946 }
14947 else if (argvars[0].v_type == VAR_BLOB)
14948 {
14949 blob = argvars[0].vval.v_blob;
14950 if (blob == NULL)
14951 return;
14952 }
14953 else
14954 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014955 semsg(_(e_invarg2), "writefile()");
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014956 return;
14957 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014958
14959 if (argvars[2].v_type != VAR_UNKNOWN)
14960 {
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014961 char_u *arg2 = tv_get_string_chk(&argvars[2]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014962
14963 if (arg2 == NULL)
14964 return;
14965 if (vim_strchr(arg2, 'b') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014966 binary = TRUE;
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014967 if (vim_strchr(arg2, 'a') != NULL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014968 append = TRUE;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010014969#ifdef HAVE_FSYNC
14970 if (vim_strchr(arg2, 's') != NULL)
14971 do_fsync = TRUE;
14972 else if (vim_strchr(arg2, 'S') != NULL)
14973 do_fsync = FALSE;
14974#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014975 }
14976
Bram Moolenaard155d7a2018-12-21 16:04:21 +010014977 fname = tv_get_string_chk(&argvars[1]);
Bram Moolenaar8cf91282017-06-13 19:38:37 +020014978 if (fname == NULL)
14979 return;
14980
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014981 /* Always open the file in binary mode, library functions have a mind of
14982 * their own about CR-LF conversion. */
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014983 if (*fname == NUL || (fd = mch_fopen((char *)fname,
14984 append ? APPENDBIN : WRITEBIN)) == NULL)
14985 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +010014986 semsg(_(e_notcreate), *fname == NUL ? (char_u *)_("<empty>") : fname);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020014987 ret = -1;
14988 }
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014989 else if (blob)
14990 {
14991 if (write_blob(fd, blob) == FAIL)
14992 ret = -1;
14993#ifdef HAVE_FSYNC
14994 else if (do_fsync)
14995 // Ignore the error, the user wouldn't know what to do about it.
14996 // May happen for a device.
Bram Moolenaara7870192019-02-14 12:56:36 +010014997 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar6e5ea8d2019-01-12 22:47:31 +010014998#endif
14999 fclose(fd);
15000 }
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015001 else
15002 {
Bram Moolenaar8cf91282017-06-13 19:38:37 +020015003 if (write_list(fd, list, binary) == FAIL)
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015004 ret = -1;
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015005#ifdef HAVE_FSYNC
Bram Moolenaar291a9d12017-11-25 14:37:11 +010015006 else if (do_fsync)
15007 /* Ignore the error, the user wouldn't know what to do about it.
15008 * May happen for a device. */
Bram Moolenaara7870192019-02-14 12:56:36 +010015009 vim_ignored = vim_fsync(fileno(fd));
Bram Moolenaar7567d0b2017-11-16 23:04:15 +010015010#endif
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015011 fclose(fd);
15012 }
15013
15014 rettv->vval.v_number = ret;
15015}
15016
15017/*
15018 * "xor(expr, expr)" function
15019 */
15020 static void
15021f_xor(typval_T *argvars, typval_T *rettv)
15022{
Bram Moolenaard155d7a2018-12-21 16:04:21 +010015023 rettv->vval.v_number = tv_get_number_chk(&argvars[0], NULL)
15024 ^ tv_get_number_chk(&argvars[1], NULL);
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015025}
15026
Bram Moolenaar73dad1e2016-07-17 22:13:49 +020015027#endif /* FEAT_EVAL */